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

GonzalezVillalobos, Diego Diego.GonzalezVillalobos at amd.com
Wed Sep 28 22:12:57 UTC 2022


[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 at openssl.org> 
Sent: Friday, September 23, 2022 1:17 AM
To: GonzalezVillalobos, Diego <Diego.GonzalezVillalobos at amd.com>; openssl-users at openssl.org
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 at openssl.org>
> Sent: Friday, September 9, 2022 10:36 AM
> To: GonzalezVillalobos, Diego <Diego.GonzalezVillalobos at amd.com>;
> openssl-users at openssl.org
> 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


More information about the openssl-users mailing list