/* * Get EC key material and stash pointer in ex_data * Note we get called twice, once for private key, and once for public * We need to get the EC_PARAMS and EC_POINT into both, * as lib11 dates from RSA only where all the pub key components * were also part of the private key. With EC the point * is not in the private key, and the params may or may not be. * */ static EVP_PKEY *pkcs11_get_evp_key_ec(PKCS11_KEY *key) { EVP_PKEY *pk; EC_KEY *ec; ec = pkcs11_get_ec(key); if (ec == NULL) return NULL; pk = EVP_PKEY_new(); if (pk == NULL) { EC_KEY_free(ec); return NULL; } EVP_PKEY_set1_EC_KEY(pk, ec); /* Also increments the ec ref count */ if (key->isPrivate) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L EC_KEY_set_method(ec, PKCS11_get_ec_key_method()); #else ECDSA_set_method(ec, PKCS11_get_ecdsa_method()); ECDH_set_method(ec, PKCS11_get_ecdh_method()); #endif } /* TODO: Retrieve the ECDSA private key object attributes instead, * unless the key has the "sensitive" attribute set */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L EC_KEY_set_ex_data(ec, ec_ex_index, key); #else ECDSA_set_ex_data(ec, ec_ex_index, key); #endif EC_KEY_free(ec); /* Drops our reference to it */ return pk; }
// Signing functions bool OSSLECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const std::string mechanism) { std::string lowerMechanism; lowerMechanism.resize(mechanism.size()); std::transform(mechanism.begin(), mechanism.end(), lowerMechanism.begin(), tolower); if (lowerMechanism.compare("ecdsa")) { ERROR_MSG("Invalid mechanism supplied (%s)", mechanism.c_str()); return false; } // Check if the private key is the right type if (!privateKey->isOfType(OSSLECPrivateKey::type)) { ERROR_MSG("Invalid key type supplied"); return false; } OSSLECPrivateKey* pk = (OSSLECPrivateKey*) privateKey; EC_KEY* eckey = pk->getOSSLKey(); if (eckey == NULL) { ERROR_MSG("Could not get the OpenSSL private key"); return false; } // Use the OpenSSL implementation and not any engine ECDSA_set_method(eckey, ECDSA_OpenSSL()); // Perform the signature operation size_t len = pk->getOrderLength(); if (len == 0) { ERROR_MSG("Could not get the order length"); return false; } signature.resize(2 * len); memset(&signature[0], 0, 2 * len); ECDSA_SIG *sig = ECDSA_do_sign(dataToSign.const_byte_str(), dataToSign.size(), eckey); if (sig == NULL) { ERROR_MSG("ECDSA sign failed (0x%08X)", ERR_get_error()); return false; } // Store the 2 values with padding BN_bn2bin(sig->r, &signature[len - BN_num_bytes(sig->r)]); BN_bn2bin(sig->s, &signature[2 * len - BN_num_bytes(sig->s)]); ECDSA_SIG_free(sig); return true; }
static PKCS11H_BOOL __pkcs11h_openssl_session_setECDSA( IN const pkcs11h_openssl_session_t openssl_session, IN EVP_PKEY * evp ) { PKCS11H_BOOL ret = FALSE; EC_KEY *ec = NULL; _PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: __pkcs11h_openssl_session_setECDSA - entered openssl_session=%p, evp=%p", (void *)openssl_session, (void *)evp ); if ( (ec = EVP_PKEY_get1_EC_KEY (evp)) == NULL ) { _PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get EC key"); goto cleanup; } ECDSA_set_method (ec, __openssl_methods.ecdsa); ECDSA_set_ex_data (ec, __openssl_methods.ecdsa_index, openssl_session); ret = TRUE; cleanup: if (ec != NULL) { EC_KEY_free (ec); ec = NULL; } _PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: __pkcs11h_openssl_session_setECDSA - return ret=%d", ret ); return ret; }
// Verification functions bool OSSLECDSA::verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const std::string mechanism) { std::string lowerMechanism; lowerMechanism.resize(mechanism.size()); std::transform(mechanism.begin(), mechanism.end(), lowerMechanism.begin(), tolower); if (lowerMechanism.compare("ecdsa")) { ERROR_MSG("Invalid mechanism supplied (%s)", mechanism.c_str()); return false; } // Check if the private key is the right type if (!publicKey->isOfType(OSSLECPublicKey::type)) { ERROR_MSG("Invalid key type supplied"); return false; } OSSLECPublicKey* pk = (OSSLECPublicKey*) publicKey; EC_KEY* eckey = pk->getOSSLKey(); if (eckey == NULL) { ERROR_MSG("Could not get the OpenSSL public key"); return false; } // Use the OpenSSL implementation and not any engine ECDSA_set_method(eckey, ECDSA_OpenSSL()); // Perform the verify operation size_t len = pk->getOrderLength(); if (len == 0) { ERROR_MSG("Could not get the order length"); return false; } if (signature.size() != 2 * len) { ERROR_MSG("Invalid buffer length"); return false; } ECDSA_SIG* sig = ECDSA_SIG_new(); if (sig == NULL) { ERROR_MSG("Could not create an ECDSA_SIG object"); return false; } if (sig->r != NULL) BN_clear_free(sig->r); const unsigned char *s = signature.const_byte_str(); sig->r = BN_bin2bn(s, len, NULL); if (sig->s != NULL) BN_clear_free(sig->s); sig->s = BN_bin2bn(s + len, len, NULL); if (sig->r == NULL || sig->s == NULL) { ERROR_MSG("Could not add data to the ECDSA_SIG object"); ECDSA_SIG_free(sig); return false; } int ret = ECDSA_do_verify(originalData.const_byte_str(), originalData.size(), sig, eckey); if (ret != 1) { if (ret < 0) ERROR_MSG("ECDSA verify failed (0x%08X)", ERR_get_error()); ECDSA_SIG_free(sig); return false; } ECDSA_SIG_free(sig); return true; }
/* * Get EC key material and stash pointer in ex_data * Note we get called twice, once for private key, and once for public * We need to get the EC_PARAMS and EC_POINT into both, * as lib11 dates from RSA only where all the pub key components * were also part of the private key. With EC the point * is not in the private key, and the params may or may not be. * */ static EVP_PKEY *pkcs11_get_evp_key_ec(PKCS11_KEY * key) { EVP_PKEY *pk; EC_KEY * ec = NULL; CK_RV ckrv; size_t ec_paramslen = 0; CK_BYTE * ec_params = NULL; size_t ec_pointlen = 0; CK_BYTE * ec_point = NULL; PKCS11_KEY * pubkey; ASN1_OCTET_STRING *os=NULL; pk = EVP_PKEY_new(); if (pk == NULL) return NULL; ec = EC_KEY_new(); if (ec == NULL) { EVP_PKEY_free(pk); return NULL; } EVP_PKEY_set1_EC_KEY(pk, ec); /* Also increments the ec ref count */ /* For Openssl req we need at least the * EC_KEY_get0_group(ec_key)) to return the group. * Even if it fails will continue as a sign only does not need * need this if the pkcs11 or card can figure this out. */ if (key_getattr_var(key, CKA_EC_PARAMS, NULL, &ec_paramslen) == CKR_OK && ec_paramslen > 0) { ec_params = OPENSSL_malloc(ec_paramslen); if (ec_params) { ckrv = key_getattr_var(key, CKA_EC_PARAMS, ec_params, &ec_paramslen); if (ckrv == CKR_OK) { const unsigned char * a = ec_params; /* convert to OpenSSL parmas */ d2i_ECParameters(&ec, &a, (long) ec_paramslen); } } } /* Now get the ec_point */ pubkey = key->isPrivate ? PKCS11_find_key_from_key(key) : key; if (pubkey) { ckrv = key_getattr_var(pubkey, CKA_EC_POINT, NULL, &ec_pointlen); if (ckrv == CKR_OK && ec_pointlen > 0) { ec_point = OPENSSL_malloc(ec_pointlen); if (ec_point) { ckrv = key_getattr_var(pubkey, CKA_EC_POINT, ec_point, &ec_pointlen); if (ckrv == CKR_OK) { /* PKCS#11 returns ASN1 octstring*/ const unsigned char * a; /* we have asn1 octet string, need to strip off 04 len */ a = ec_point; os = d2i_ASN1_OCTET_STRING(NULL, &a, (long) ec_pointlen); if (os) { a = os->data; o2i_ECPublicKey(&ec, &a, os->length); } /* EC_KEY_print_fp(stderr, ec, 5); */ } } } } /* If the key is not extractable, create a key object * that will use the card's functions to sign & decrypt */ if (os) ASN1_STRING_free(os); if (ec_point) OPENSSL_free(ec_point); if (ec_params) OPENSSL_free(ec_params); if (key->isPrivate) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L EC_KEY_set_method(ec, PKCS11_get_ec_key_method()); #else ECDSA_set_method(ec, PKCS11_get_ecdsa_method()); /* TODO: Retrieve the ECDSA private key object attributes instead, * unless the key has the "sensitive" attribute set */ #endif } /* TODO: Extract the ECDSA private key instead, if the key * is marked as extractable (and not private?) */ #if OPENSSL_VERSION_NUMBER >= 0x10100002L EC_KEY_set_ex_data(ec,ec_key_ex_index, key); #else ECDSA_set_ex_data(ec, ecdsa_ex_index, key); #endif EC_KEY_free(ec); /* drops our reference to it */ return pk; }