diff options
Diffstat (limited to 'src/signframework/ossl_functions_ecc.c')
-rw-r--r-- | src/signframework/ossl_functions_ecc.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/signframework/ossl_functions_ecc.c b/src/signframework/ossl_functions_ecc.c new file mode 100644 index 0000000..58fb3ba --- /dev/null +++ b/src/signframework/ossl_functions_ecc.c @@ -0,0 +1,187 @@ +/* Copyright 2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include <openssl/crypto.h> +#include <openssl/ecdsa.h> +#include <openssl/obj_mac.h> +#include <openssl/objects.h> + +#include "debug.h" +#include "utils.h" +#include "ossl_functions_ecc.h" + +/* messages are traced here + + All messages, even error messages, are traced only if verbose is set. There messages are + 'techie' and should not be returned unless the user asks for them. +*/ + +extern FILE* messageFile; +extern int verbose; + +long Ossl_VerifyECC(int *valid, /* output boolean */ + const unsigned char *digest, + size_t digestLength, + const unsigned char *publicKey, + size_t publicKeyLength, + const unsigned char *signature, + unsigned long signatureLength) +{ + long rc = 0; /* function return code */ + int irc; + EC_KEY *ecPubKey = NULL; /* freed @1 */ + + if (verbose) fprintf(messageFile, "Ossl_VerifyECC: Verifying using OpenSSL\n"); + if (verbose) PrintAll(messageFile, "Ossl_VerifyECC: public key", publicKeyLength, publicKey); + if (verbose) PrintAll(messageFile, "Ossl_VerifyECC: digest", digestLength, digest); + if (verbose) PrintAll(messageFile, "Ossl_VerifyECC: signature", signatureLength, signature); + /* create an EC public key token */ + if (rc == 0) { + rc = Ossl_SetPubKey_ECC(&ecPubKey, /* freed @1 */ + publicKey, + publicKeyLength); + } + /* verify signature */ + if (rc == 0) { + if (verbose) fprintf(messageFile, "Ossl_VerifyECC: signature length out %lu\n", + signatureLength); + irc = ECDSA_verify(0, /* type ignored */ + digest, /* digest to be verified*/ + digestLength, + signature, /* DER encoded signature */ + signatureLength, /* length of signature */ + ecPubKey); /* public key */ + if (irc == 0) { + if (verbose) fprintf(messageFile, + "Ossl_VerifyECC: ECDSA_verify failed\n"); + *valid = FALSE; + } + else { + if (verbose) fprintf(messageFile, + "Ossl_VerifyECC: ECDSA_verify success\n"); + *valid = TRUE; + } + } + /* cleanup */ + if (ecPubKey != NULL) { /* @1 */ + EC_KEY_free(ecPubKey); + } + return rc; +} + +long Ossl_SetPubKey_ECC(EC_KEY **ecPubKey, /* freed by caller */ + const unsigned char *publicKey, + size_t publicKeyLength) +{ + long rc = 0; + int irc; + int nid; + EC_GROUP *group = NULL; /* freed @1 */ + EC_POINT *ec_point = NULL; /* freed @2 */ + + if (verbose) fprintf(messageFile, "Ossl_SetPubKey_ECC: Creating public key token\n"); + /* create an EC_KEY */ + if (rc == 0) { + *ecPubKey = EC_KEY_new(); /* freed @5 */ + if (*ecPubKey == NULL) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_KEY_new\n"); + rc = ERROR_CODE; + } + } + /* Creates a EC_GROUP object with a curve specified by a NID */ + if (rc == 0) { + nid = NID_secp521r1; /* P-521 */ + if (verbose) fprintf(messageFile, "Ossl_SetPubKey_ECC: nid %d %s\n", nid, OBJ_nid2sn(nid)); + group = EC_GROUP_new_by_curve_name(nid); /* freed @1 */ + if (group == NULL) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_GROUP_new_by_curve_name\n"); + rc = ERROR_CODE; + } + } + /* create a new EC_POINT */ + if (rc == 0) { + ec_point = EC_POINT_new(group); /* freed @2 */ + if (ec_point == NULL) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_POINT_new\n"); + rc = ERROR_CODE; + } + } + /* Sets the EC_GROUP P-521 of an EC_KEY object */ + if (rc == 0) { + irc = EC_KEY_set_group(*ecPubKey, group); + if (irc == 0) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_KEY_set_group\n"); + rc = ERROR_CODE; + } + } + /* assign the public key to the EC_POINT */ + if (rc == 0) { + /** Decodes a EC_POINT from a octet string + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param buf memory buffer with the encoded ec point + * \param len length of the encoded ec point + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occured + */ + irc = EC_POINT_oct2point(group, + ec_point, + publicKey, + publicKeyLength, + NULL); + if (irc == 0) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_POINT_oct2point\n"); + rc = ERROR_CODE; + } + } + if (rc == 0) { + /** Sets the public key of a EC_KEY object. + * \param key EC_KEY object + * \param pub EC_POINT object with the public key (note: the EC_KEY object + * will use an own copy of the EC_POINT object). + * \return 1 on success and 0 if an error occurred. + */ + irc = EC_KEY_set_public_key(*ecPubKey, ec_point); + if (irc == 0) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_KEY_set_public_key\n"); + rc = ERROR_CODE; + } + } + /* sanity check */ + if (rc == 0) { + /** Verifies that a private and/or public key is valid. + * \param key the EC_KEY object + * \return 1 on success and 0 otherwise. + */ + irc = EC_KEY_check_key(*ecPubKey); + if (irc == 0) { + fprintf(messageFile, "Ossl_SetPubKey_ECC: unable to EC_KEY_check_key\n"); + rc = ERROR_CODE; + } + } + /* cleanup */ + if (group != NULL) { + EC_GROUP_free(group); /* @1 */ + } + if (ec_point != NULL) { + EC_POINT_free(ec_point); /* @2 */ + } + return rc; +} |