Paweł R.
Paweł R.

Reputation: 121

How to properly create an RSA key from raw data in OpenSSL 3.0 in C language?

i'm fairly new to OpenSSL and my current task at work is updating the code of a project from OpenSSL 1.1.1 to OpenSSL 3.0 and I'm stuck on a really weird problem.

I'm trying to create an RSA key from given raw data, precisely binary modulus and exponent that are converted to BIGNUM. I've tried to make it as it is described in the manual and the key creation works, but the problem is whatever I try to do with that key (or CTX based on it) fails, whether it's signature decryption or verification.

Here's the code where I create the key:

    /* function set up above */
    ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
    if ( ctx == NULL) {
        ERROR("Error: failed to initialize CTX from name.\n");
        goto OPENSSL_ERROR;
    }

    modulus = BN_bin2bn(pubkey->data, pubkey->size, NULL);
    exponent = BN_bin2bn(exp_arr, 3, NULL);
    if ( modulus == NULL || exponent == NULL ) {
        goto OPENSSL_ERROR;
    }

    OSSL_PARAM params[] = {
        OSSL_PARAM_BN("n", &modulus, BN_num_bytes(modulus)*8),
        OSSL_PARAM_BN("e", &exponent, BN_num_bytes(exponent)*8),
        OSSL_PARAM_BN("d", NULL, 0),
        OSSL_PARAM_END
    };

    status = EVP_PKEY_fromdata_init(ctx);
    if ( status <= 0 ) {
        ERROR("Error: failed to initialize key creation.\n");
        goto OPENSSL_ERROR;
    }

    status = EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params);
    if ( status <= 0 || evp_key == NULL ) {
        ERROR("Error: failed to create key.\n");
        goto OPENSSL_ERROR;
    }
    /* goes on to decrypt signature and later verify it against data - both fail */

It goes through swiftly, but trying to do whatever with that key or CTX based on that key fails miserably. I tried creating CTX with EVP_PKEY_CTX_new_id(), but it changed nothing. I tried omitting the parameter "d", but it changed nothing.

If anyone knows what I'm doing wrong and what should be changed - all help will be greatly appreciated.

P.S.

  1. pubkey is passed to the function as argument, data is a binary array, size is obviously it's size (size_t)
  2. the params given to the key are the same as in the previous version of the code which used the RSA_set0_key() function
  3. unsigned char exp_arr[] = {0x01, 0x00, 0x01};

Upvotes: 5

Views: 2587

Answers (1)

Paweł R.
Paweł R.

Reputation: 121

It is not obvious in the manual (nothing new with OpenSSL).

The problem is that the OSSL_PARAM params array cannot be initialized the way it is in the code above. It needs to be built using OSSL_PARAM_BLD, like this:

    OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new();
    if ( params_build == NULL ) {
        goto OPENSSL_ERROR;
    }
    if ( !OSSL_PARAM_BLD_push_BN(params_build, "n", modulus) ) {
        ERROR("Error: failed to push modulus into param build.\n");
        goto OPENSSL_ERROR;
    }
    if ( !OSSL_PARAM_BLD_push_BN(params_build, "e", exponent) ) {
        ERROR("Error: failed to push exponent into param build.\n");
        goto OPENSSL_ERROR;
    }
    if ( !OSSL_PARAM_BLD_push_BN(params_build, "d", NULL) ) {
        ERROR("Error: failed to push NULL into param build.\n");
        goto OPENSSL_ERROR;
    }
    OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build);
    if ( params == NULL ) {
        ERROR("Error: failed to construct params from build.\n");
        goto OPENSSL_ERROR;
    }

It'll probably work the same with all other types of keys created with EVP_PKEY_fromdata() function.

[IMPORTANT!] Remember to check what are settable parameters for the key you're trying to create, otherwise you might get stuck on that part for a long time not knowing what's wrong with your code ;)

Upvotes: 7

Related Questions