in src/utils/crypto_utils/src/crypto_lib.c [906:1107]
CONSTBUFFER_HANDLE CryptoUtils_GenerateRsaPublicKey(const char* modulus_b64url, const char* exponent_b64url)
{
CONSTBUFFER_HANDLE publicKeyData = NULL;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
unsigned char *modulus_bytes, *exponent_bytes;
int modulus_length, exponent_length;
int status = 0;
EVP_PKEY* pkey = NULL;
EVP_PKEY_CTX* ctx = NULL;
OSSL_ENCODER_CTX* pkey_encoder_ctx = NULL;
OSSL_PARAM_BLD* param_bld = NULL;
OSSL_PARAM* params = NULL;
BIGNUM* bn_modulus = NULL;
BIGNUM* bn_exponent = NULL;
unsigned char* der_encoded_bytes = NULL;
size_t der_length = 0;
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
modulus_length = (int)Base64URLDecode(modulus_b64url, &modulus_bytes);
if (modulus_length == 0)
{
goto done;
}
exponent_length = (int)Base64URLDecode(exponent_b64url, &exponent_bytes);
if (exponent_length == 0)
{
goto done;
}
bn_modulus = BN_bin2bn(modulus_bytes, modulus_length, NULL);
if (bn_modulus == NULL)
{
goto done;
}
bn_exponent = BN_bin2bn(exponent_bytes, exponent_length, NULL);
if (bn_exponent == NULL)
{
goto done;
}
param_bld = OSSL_PARAM_BLD_new();
if (param_bld == NULL)
{
goto done;
}
status = OSSL_PARAM_BLD_push_BN(param_bld, "n", bn_modulus);
if (status != 1)
{
goto done;
}
status = OSSL_PARAM_BLD_push_BN(param_bld, "e", bn_exponent);
if (status != 1)
{
goto done;
}
status = OSSL_PARAM_BLD_push_BN(param_bld, "d", NULL);
if (status != 1)
{
goto done;
}
params = OSSL_PARAM_BLD_to_param(param_bld);
if (params == NULL)
{
goto done;
}
status = EVP_PKEY_fromdata_init(ctx);
if (status != 1)
{
goto done;
}
status = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params);
if (status != 1)
{
goto done;
}
pkey_encoder_ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, "DER", NULL, NULL);
if (pkey_encoder_ctx == NULL)
{
goto done;
}
if (OSSL_ENCODER_to_data(pkey_encoder_ctx, &der_encoded_bytes, &der_length) != 1)
{
goto done;
}
// copies bytes into new buffer, so let it free after done:
publicKeyData = CONSTBUFFER_Create(der_encoded_bytes, der_length);
done:
if (ctx != NULL)
{
EVP_PKEY_CTX_free(ctx);
}
if (param_bld != NULL)
{
OSSL_PARAM_BLD_free(param_bld);
}
if (params != NULL)
{
OSSL_PARAM_free(params);
}
if (pkey_encoder_ctx != NULL)
{
OSSL_ENCODER_CTX_free(pkey_encoder_ctx);
}
free(der_encoded_bytes);
free(modulus_bytes);
free(exponent_bytes);
BN_free(bn_modulus);
BN_free(bn_exponent);
// OpenSSL 3.0 took the guess work out of ownership so we can free the pkey in addition to the bn_modulus and bn_exponent
EVP_PKEY_free(pkey);
#else
unsigned char* modulus_bytes = NULL;
unsigned char* exponent_bytes = NULL;
int modulus_length, exponent_length;
BIGNUM* bn_modulus = NULL;
BIGNUM* bn_exponent = NULL;
RSA* rsa = NULL;
unsigned char* der_encoded_bytes = NULL;
int der_length = 0;
modulus_length = (int)Base64URLDecode(modulus_b64url, &modulus_bytes);
if (modulus_length == 0)
{
goto done;
}
exponent_length = (int)Base64URLDecode(exponent_b64url, &exponent_bytes);
if (exponent_length == 0)
{
goto done;
}
bn_modulus = BN_bin2bn(modulus_bytes, modulus_length, NULL);
if (bn_modulus == NULL)
{
goto done;
}
bn_exponent = BN_bin2bn(exponent_bytes, exponent_length, NULL);
if (bn_exponent == NULL)
{
goto done;
}
rsa = RSA_new();
if (rsa == NULL)
{
goto done;
}
if (RSA_set0_key(rsa, bn_modulus, bn_exponent, NULL) == 0)
{
goto done;
}
der_encoded_bytes = NULL;
der_length = i2d_RSAPublicKey(rsa, &der_encoded_bytes); // DER PKCS#1
if (der_length == 0)
{
goto done;
}
// copies bytes into new buffer, so let it free after done:
publicKeyData = CONSTBUFFER_Create(der_encoded_bytes, (size_t)der_length);
done:
free(der_encoded_bytes);
free(modulus_bytes);
free(exponent_bytes);
// Do not explicitly free bn_modulus and bn_exponent
RSA_free(rsa);
#endif
return publicKeyData;
}