[AMD Official Use Only - General] Hello Tomas, I generated the key as you suggested, and I am no longer getting an error message! Thank you for that. Here is how I'm generating the key now: // SEV certificate are little-endian, must reverse bytes before generating key if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256) || (cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA384)) { //Grab x param and flip bytes to BE memcpy(px, &cert->pub_key.ecdsa.qx, ec_group_order); if(!sev::reverse_bytes(px, sizeof(px))) break; //Grab y param and flip bytes to BE memcpy(py, &cert->pub_key.ecdsa.qy, ec_group_order); if(!sev::reverse_bytes(py, sizeof(py))) break; } else if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA256) || (cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA384)) { //Grab x param and flip bytes to BE memcpy(px, &cert->pub_key.ecdh.qx, ec_group_order); if(!sev::reverse_bytes(px, sizeof(px))) break; //Grab y param and flip bytes to BE memcpy(py, &cert->pub_key.ecdh.qy, ec_group_order); if(!sev::reverse_bytes(py, sizeof(py))) break; } int px_size = sizeof(px)/sizeof(*px); int py_size = sizeof(py)/sizeof(*py); // Will contain x and y components unsigned char public_key_xy[1 + px_size + py_size] = {0}; //Add point conversion as first value public_key_xy[0] = POINT_CONVERSION_UNCOMPRESSED; //Add x components after point compression memcpy(public_key_xy + 1, px, px_size); //Add y components after x memcpy(public_key_xy + px_size + 1, py ,py_size); // int nid = EC_curve_nist2nid("P-384"); // NID_secp384r1 OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new(); if ( params_build == NULL ) { cout << "Params build fails" << endl; break; } if (!OSSL_PARAM_BLD_push_utf8_string(params_build, OSSL_PKEY_PARAM_GROUP_NAME, "P-384", 0)) { cout<< "Push EC curve to build fails" << endl; break; } if (!OSSL_PARAM_BLD_push_octet_string(params_build, OSSL_PKEY_PARAM_PUB_KEY, public_key_xy, sizeof(public_key_xy))) { cout << "Error: failed to push qx into param build." << endl; break; } OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build); if ( params == NULL ) { cout << "Error: building parameters." << endl; break; } OSSL_PARAM_BLD_free(params_build); key_gen_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); if(EVP_PKEY_fromdata_init(key_gen_ctx) != 1) { cout << "failed to initialize key creation." << endl; break; } if(EVP_PKEY_fromdata(key_gen_ctx, &evp_pub_key, EVP_PKEY_PUBLIC_KEY, params) != 1) { cout << "key generation breaks" << endl; printf("Failed Final Verify %s\n",ERR_error_string(ERR_get_error(),NULL)); break; } if (EVP_PKEY_get_base_id(evp_pub_key) != EVP_PKEY_EC) { cout << "wrong key type" << endl; break; } } if (!evp_pub_key) { cout << "no evp pkey" << endl; break; } cout << "compile key succesful" << endl; cmd_ret = STATUS_SUCCESS; Although the key generation works and I'm not getting a verify error anymore, I am still unsuccessful on verifying the digest. It keeps failing (returning 0). Here is how I'm currently trying to do the verification. ECDSA_SIG *tmp_ecdsa_sig = ECDSA_SIG_new(); BIGNUM *r_big_num = BN_new(); BIGNUM *s_big_num = BN_new(); uint32_t sig_len; unsigned char* der_sig; // 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); // FreesBIGNUMs manually here BN_free(r_big_num); ECDSA_SIG_free(tmp_ecdsa_sig); break; } int der_sig_len = i2d_ECDSA_SIG(tmp_ecdsa_sig, NULL); der_sig = static_cast<unsigned char*>(OPENSSL_malloc(der_sig_len)); unsigned char* der_iter = der_sig; der_sig_len = i2d_ECDSA_SIG(tmp_ecdsa_sig, &der_iter); // <= bugfix here if (der_sig_len == 0) { cout << "sig length invalid" << endl; break; } if (der_sig == NULL) { cout << "sig generation failed" << endl; break; } verify_md_ctx = EVP_MD_CTX_new(); if (!verify_md_ctx) { cout << "Error md verify context " << endl;; break; } if (EVP_DigestVerifyInit(verify_md_ctx, NULL, (parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256 || parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA256) ? EVP_sha256(): EVP_sha384(), NULL, parent_signing_key) <= 0) { cout << "Init fails " << endl; break; } if (EVP_DigestVerifyUpdate(verify_md_ctx, (uint8_t *)child_cert, pub_key_offset) <= 0){ // Calls SHA256_UPDATE cout << "updating digest fails" << endl; break; } int ret = EVP_DigestVerifyFinal(verify_md_ctx, der_sig, der_sig_len); cout << ret << endl; if (ret == 0) { cout << "EC Verify digest fails" << endl; break; } else if (ret < 0) { printf("Failed Final Verify %s\n",ERR_error_string(ERR_get_error(),NULL)); cout << "EC Verify error" << endl; break; } found_match = true; cout << "SEV EC verification Succesful" << endl; Could it be because I'm creating a ECDSA SIG object and then turning it into a der format to verify? Again, suggestions would be appreciated. Thank you! Diego Gonzalez Villalobos ---------------------------------------------------------------------------------------------------------------------------------- -----Original Message----- From: Tomas Mraz <tomas@xxxxxxxxxxx> Sent: Friday, September 23, 2022 1:17 AM To: GonzalezVillalobos, Diego <Diego.GonzalezVillalobos@xxxxxxx>; openssl-users@xxxxxxxxxxx Subject: Re: Updating RSA public key generation and signature verification from 1.1.1 to 3.0 Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding. Please look at the answer in this question in GitHub: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fopenssl%2Fopenssl%2Fissues%2F19219%23issuecomment-1247782572&data=05%7C01%7CDiego.GonzalezVillalobos%40amd.com%7C49cb5498fa2142b3c73f08da9d2b3799%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637995106207913021%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=S%2FIfBL5bnOa%2Fa2owmcihtZlG4AxTYCWDkaGpmJdid%2Fw%3D&reserved=0 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://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.openssl.org%2Fdocs%2Fman3.0%2Fman7%2FEVP_PKEY-EC.html&data=05%7C01%7CDiego.GonzalezVillalobos%40amd.com%7C49cb5498fa2142b3c73f08da9d2b3799%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637995106207913021%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=dRWekElnVV5leTg6ZN0k9LwQq1Sivf2Hx%2BZrY7YPajE%3D&reserved=0 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://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.openssl.org%2Fdocs%2Fman3.0%2Fman3%2FEVP_PKEY_fromdata.html&data=05%7C01%7CDiego.GonzalezVillalobos%40amd.com%7C49cb5498fa2142b3c73f08da9d2b3799%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637995106207913021%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=ozefo2bDWnsgQQKJIfL6maK%2Fvnp2k6nUrYh8RmOciqU%3D&reserved=0 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 +0000, 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) { > 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->pub_key.ecdh.qy, > sizeof(cert->pub_key.ecdh.qy), NULL); > } > > int nid = EC_curve_nist2nid("P-384"); // NID_secp384r1 > > OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new(); > > if ( params_build == NULL ) { > cout << "Params build fails" << endl; > break; > } > > if (!OSSL_PARAM_BLD_push_utf8_string(params_build, > OSSL_PKEY_PARAM_GROUP_NAME, "P-384", 0)) { > cout<< "Push EC curve to build fails" << endl; > break; > } > > if (!OSSL_PARAM_BLD_push_BN(params_build, > OSSL_PKEY_PARAM_EC_PUB_X, x_big_num)) { > cout << "Error: failed to push qx into param build." > << endl; > break; > } > > > if (!OSSL_PARAM_BLD_push_BN(params_build, > OSSL_PKEY_PARAM_EC_PUB_Y, y_big_num)) { > cout << "Error: failed to push qy into param build." > << endl; > break; > } > > OSSL_PARAM *params = > OSSL_PARAM_BLD_to_param(params_build); > > if ( params == NULL ) { > cout << "Error: building parameters." << endl; > break; > } > > OSSL_PARAM_BLD_free(params_build); > > key_gen_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); > EVP_PKEY_CTX_set_ec_paramgen_curve_nid(key_gen_ctx, > NID_secp384r1); > > if(EVP_PKEY_fromdata_init(key_gen_ctx) != 1) { > cout << "failed to initialize key creation." << endl; > break; > } > > if(EVP_PKEY_fromdata(key_gen_ctx, &evp_pub_key, > EVP_PKEY_PUBLIC_KEY, params) != 1) { > cout << "key generation breaks" << endl; > break; > } > > if (EVP_PKEY_get_base_id(evp_pub_key) != EVP_PKEY_EC) { > cout << "wrong key type" << endl; > break; > } > /*Generation successful*/ > > Verification: > ECDSA_SIG *tmp_ecdsa_sig = ECDSA_SIG_new(); > BIGNUM *r_big_num = BN_new(); > BIGNUM *s_big_num = BN_new(); > uint32_t sig_len; > unsigned char *p; > > // 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); > break; > } > > sig_len = i2d_ECDSA_SIG(tmp_ecdsa_sig, NULL); > unsigned char signature[sig_len]; > > p = signature; > > sig_len = i2d_ECDSA_SIG(tmp_ecdsa_sig, &p); > > > if (signature == NULL) { > cout << "sig mem failed" << endl; > break; > } > > if (sig_len == 0) > cout << "sig length invalid" << endl; > > verify_md_ctx = EVP_MD_CTX_new(); > > > if (!verify_md_ctx) { > cout << "Error md verify context " << endl;; > break; > } > > if (EVP_DigestVerifyInit(verify_md_ctx, NULL, > (parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256 || > parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA256) ? EVP_sha256() > : EVP_sha384(), NULL, parent_signing_key) <= 0) { > cout << "Init fails " << endl; > break; > } > > if (EVP_DigestVerifyUpdate(verify_md_ctx, child_cert, > pub_key_offset) <= 0){ // Calls SHA256_UPDATE > cout << "updating digest fails" << endl; > break; > } > > int ret = EVP_DigestVerifyFinal(verify_md_ctx, > signature, sig_len); > cout << ret << endl; > if (ret == 0) { > cout << "EC Verify digest fails" << endl; > break; > } else if (ret < 0) { > printf("Failed Final Verify > %s\n",ERR_error_string(ERR_get_error(),NULL)); > cout << "EC Verify error" << endl; > break; > } > > found_match = true; > cout << "SEV EC verification Succesful" << endl; > > > My current output when I reach EVP_DigestVerifyFinal is showing this > error: > Failed Final Verify error:03000095:digital envelope routines::no > operation set > > I have been playing around with it for a while, but I am stuck at this > point. Any advice would be appreciated. > > Thank you, > > Diego Gonzalez Villalobos > --------------------------------------------------------------------- > ------------------------------------------------------------- > > > -----Original Message----- > From: Tomas Mraz <tomas@xxxxxxxxxxx> > Sent: Friday, September 9, 2022 10:36 AM > To: GonzalezVillalobos, Diego <Diego.GonzalezVillalobos@xxxxxxx>; > openssl-users@xxxxxxxxxxx > Subject: Re: Updating RSA public key generation and signature > verification from 1.1.1 to 3.0 > > [CAUTION: External Email] > > On Thu, 2022-09-08 at 16:10 +0000, GonzalezVillalobos, Diego via > openssl-users wrote: > > [AMD Official Use Only - General] > > > > Hello everyone, > > > > I am currently working on updating a signature verification function > > in C++ and I am a bit stuck. I am trying to replace the deprecated > > 1.1.1 functions to the appropriate 3.0 versions. The function takes > > in > > 2 certificate objects (parent and cert), which are not x509 > > certificates, but certificates the company had previously defined. > > Using the contents from parent we create an RSA public key and using > > the contents from cert we create the digest and grab the signature > > to verify. > > > > In the 1.1.1 version we were using the RSA Object and the > > rsa_set0_key function to create the RSA public key and then used > > RSA_public_decrypt to decrypt the signature and RSA_verify_PKCS1_PSS > > to verify it. > > This > > whole workflow is now deprecated. > > > ... > > Is this the correct way of creating RSA keys now? Where is my logic > > failing? Can the same type of procedure even be done on 3.0? Any > > advice would be really appreciated. > > > > In the original code you seem to be using PSS padding for > verification. > Did you try to set the PSS padding on the digest verify context? See > demos/signature/rsa_pss_hash.c on how to do it. > > -- > Tomáš Mráz, OpenSSL -- Tomáš Mráz, OpenSSL