Re: Updating RSA public key generation and signature verification from 1.1.1 to 3.0

2022-09-22 Thread Tomas Mraz
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

2022-09-22 Thread GonzalezVillalobos, Diego via openssl-users
[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->