Hi, comments below. On Wed, 2022-09-28 at 22:12 +0000, GonzalezVillalobos, Diego wrote: > [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. Are you sure the px_size and py_size is equal to the group order? The x and y values must be padded to the group order with 0 (at the start because the values need to be BE). > 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; > } > You do not need to call i2d_ECDSA_SIG() twice. Just assign NULL to der_iter and i2d_ECDSA_SIG(tmp_ecdsa_sig, &der_iter) call will allocate the buffer for the encoded signature for you. > 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. No, that should be correct. The signature as produced or verified by the EVP_DigestSignFinal or EVP_DigestVerifyFinal should be in the DER encoding of the ECDSA_SIG. So you have that correct. I do not see any apparent problem with your code apart of the remarks above. -- Tomáš Mráz, OpenSSL