Re: Updating RSA public key generation and signature verification from 1.1.1 to 3.0
Please look at the answer in this question in GitHub: https://github.com/openssl/openssl/issues/19219#issuecomment-1247782572 Matt Caswell's answer to very similar question is presented there. I'm copying the answer here for convenience: You are attempting to create an EC public key using the "x" and "y" parameters - but no such parameters exist. The list of available EC parameters is on this page: https://www.openssl.org/docs/man3.0/man7/EVP_PKEY-EC.html For your purposes you need to use the OSSL_PKEY_PARAM_PUB_KEY parameter ("pub") to supply the public key. It needs to be an octet string with the value POINT_CONVERSION_UNCOMPRESSED at the start followed by the x and y co-ords concatenated together. For that curve, x and y need to be zero padded to be 32 bytes long each. There is an example of doing this on the EVP_PKEY_fromdata man page. Actually the example is is for EVP_PKEY_KEYPAIR rather than EVP_PKEY_PUBLIC_KEY, but the principle is exactly the same: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_fromdata.html We should add a feature to make it possible to supply the x and y co- ords separately. But that is not currently possible. So this is the answer - instead of trying to import the key via OSSL_PKEY_PARAM_EC_PUB_X and Y parameters, you need to pad the big endian values of X and Y to length of the ec group order (32 or 48 bytes respectively) and then concatenate POINT_CONVERSION_UNCOMPRESSED | big_endian_padded_X_value | big_endian_padded_Y_value. This can be then imported as the OSSL_PKEY_PARAM_PUB_KEY. Tomas, OpenSSL On Thu, 2022-09-22 at 19:15 +, GonzalezVillalobos, Diego wrote: > [AMD Official Use Only - General] > > Hello Tomas, > > Thank you for your response. Thanks to the example you guided me > towards I was able to get the verification to work. But now I am > stuck on a similar issue, but now I am trying to generate an EC key. > > This is how we used to generate and verify the EC public key from raw > data: > Generation: > > // Store the x and y components as separate BIGNUM > objects. The values in the > // SEV certificate are little-endian, must reverse bytes > before storing in BIGNUM > if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256) || > (cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA384)) { > x_big_num = BN_lebin2bn(cert->pub_key.ecdsa.qx, > sizeof(cert->pub_key.ecdsa.qx), NULL); // New's up BigNum > y_big_num = BN_lebin2bn(cert->pub_key.ecdsa.qy, > sizeof(cert->pub_key.ecdsa.qy), NULL); > } > else if ((cert->pub_key_algo == > SEV_SIG_ALGO_ECDH_SHA256) || > (cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA384)) > { > x_big_num = BN_lebin2bn(cert->pub_key.ecdh.qx, > sizeof(cert->pub_key.ecdh.qx), NULL); // New's up BigNum > y_big_num = BN_lebin2bn(cert->pub_key.ecdh.qy, > sizeof(cert->pub_key.ecdh.qy), NULL); > } > > int nid = EC_curve_nist2nid("P-384"); // NID_secp384r1 > > // Create/allocate memory for an EC_KEY object using the > NID above > if (!(ec_pub_key = EC_KEY_new_by_curve_name(nid))) > break; > // Store the x and y coordinates of the public key > if (EC_KEY_set_public_key_affine_coordinates(ec_pub_key, > x_big_num, y_big_num) != 1) > break; > // Make sure the key is good > if (EC_KEY_check_key(ec_pub_key) != 1) > break; > > /* > * Create a public EVP_PKEY from the public EC_KEY > * This function links evp_pub_key to ec_pub_key, so when > evp_pub_key > * is freed, ec_pub_key is freed. We don't want the user > to have to > * manage 2 keys, so just return EVP_PKEY and make sure > user free's it > */ > if (EVP_PKEY_assign_EC_KEY(evp_pub_key, ec_pub_key) != 1) > break; > /*Generation successful*/ > > Verification: > > ECDSA_SIG *tmp_ecdsa_sig = ECDSA_SIG_new(); > BIGNUM *r_big_num = BN_new(); > BIGNUM *s_big_num = BN_new(); > > // Store the x and y components as separate BIGNUM > objects. The values in the > // SEV certificate are little-endian, must reverse > bytes before storing in BIGNUM > r_big_num = BN_lebin2bn(cert_sig[i].ecdsa.r, > sizeof(sev_ecdsa_sig::r), r_big_num); // LE to BE > s_big_num = BN_lebin2bn(cert_sig[i].ecdsa.s, > sizeof(sev_ecdsa_sig::s), s_big_num); > > // Calling ECDSA_SIG_set0() transfers the memory > management of the values to > // the ECDSA_SIG object, and therefore the values > that have been passed > // in should not be freed directly after this > function has been called > if (ECDSA_SIG_set0(tmp_ecdsa_sig, r_big_num, > s_big_num) != 1) { >
RE: Updating RSA public key generation and signature verification from 1.1.1 to 3.0
[AMD Official Use Only - General] Hello Tomas, Thank you for your response. Thanks to the example you guided me towards I was able to get the verification to work. But now I am stuck on a similar issue, but now I am trying to generate an EC key. This is how we used to generate and verify the EC public key from raw data: Generation: // Store the x and y components as separate BIGNUM objects. The values in the // SEV certificate are little-endian, must reverse bytes before storing in BIGNUM if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256) || (cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA384)) { x_big_num = BN_lebin2bn(cert->pub_key.ecdsa.qx, sizeof(cert->pub_key.ecdsa.qx), NULL); // New's up BigNum y_big_num = BN_lebin2bn(cert->pub_key.ecdsa.qy, sizeof(cert->pub_key.ecdsa.qy), NULL); } else if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA256) || (cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA384)) { x_big_num = BN_lebin2bn(cert->pub_key.ecdh.qx, sizeof(cert->pub_key.ecdh.qx), NULL); // New's up BigNum y_big_num = BN_lebin2bn(cert->pub_key.ecdh.qy, sizeof(cert->pub_key.ecdh.qy), NULL); } int nid = EC_curve_nist2nid("P-384"); // NID_secp384r1 // Create/allocate memory for an EC_KEY object using the NID above if (!(ec_pub_key = EC_KEY_new_by_curve_name(nid))) break; // Store the x and y coordinates of the public key if (EC_KEY_set_public_key_affine_coordinates(ec_pub_key, x_big_num, y_big_num) != 1) break; // Make sure the key is good if (EC_KEY_check_key(ec_pub_key) != 1) break; /* * Create a public EVP_PKEY from the public EC_KEY * This function links evp_pub_key to ec_pub_key, so when evp_pub_key * is freed, ec_pub_key is freed. We don't want the user to have to * manage 2 keys, so just return EVP_PKEY and make sure user free's it */ if (EVP_PKEY_assign_EC_KEY(evp_pub_key, ec_pub_key) != 1) break; /*Generation successful*/ Verification: ECDSA_SIG *tmp_ecdsa_sig = ECDSA_SIG_new(); BIGNUM *r_big_num = BN_new(); BIGNUM *s_big_num = BN_new(); // Store the x and y components as separate BIGNUM objects. The values in the // SEV certificate are little-endian, must reverse bytes before storing in BIGNUM r_big_num = BN_lebin2bn(cert_sig[i].ecdsa.r, sizeof(sev_ecdsa_sig::r), r_big_num);// LE to BE s_big_num = BN_lebin2bn(cert_sig[i].ecdsa.s, sizeof(sev_ecdsa_sig::s), s_big_num); // Calling ECDSA_SIG_set0() transfers the memory management of the values to // the ECDSA_SIG object, and therefore the values that have been passed // in should not be freed directly after this function has been called if (ECDSA_SIG_set0(tmp_ecdsa_sig, r_big_num, s_big_num) != 1) { BN_free(s_big_num); // Frees BIGNUMs manually here BN_free(r_big_num); ECDSA_SIG_free(tmp_ecdsa_sig); continue; } EC_KEY *tmp_ec_key = EVP_PKEY_get1_EC_KEY(parent_signing_key); // Make a local key so you can free it later if (ECDSA_do_verify(sha_digest, (uint32_t)sha_length, tmp_ecdsa_sig, tmp_ec_key) != 1) { EC_KEY_free(tmp_ec_key); ECDSA_SIG_free(tmp_ecdsa_sig); // Frees BIGNUMs too continue; } found_match = true; EC_KEY_free(tmp_ec_key); ECDSA_SIG_free(tmp_ecdsa_sig); // Frees BIGNUMs too break; } /*Verification successful*/ This is my current attempt for public key generation and verification: Generation: / Store the x and y components as separate BIGNUM objects. The values in the // SEV certificate are little-endian, must reverse bytes before storing in BIGNUM if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256) || (cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA384)) { x_big_num = BN_lebin2bn(cert->pub_key.ecdsa.qx, sizeof(cert->pub_key.ecdsa.qx), NULL); // New's up BigNum y_big_num = BN_lebin2bn(cert->pub_key.ecdsa.qy, sizeof(cert->pub_key.ecdsa.qy), NULL); } else if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA256) || (cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA384)) { x_big_num = BN_lebin2bn(cert->pub_key.ecdh.qx, sizeof(cert->pub_key.ecdh.qx), NULL); // New's up BigNum y_big_num = BN_lebin2bn(cert->