in client-library/src/Attestation/AttestationClient/lib/AttestationLibUtils.cpp [455:579]
AttestationResult EncryptDataWithRSAPubKey(BIO* pkey_bio,
const attest::RsaScheme rsaWrapAlgId,
const attest::RsaHashAlg rsaHashAlgId,
const Buffer& input_data,
Buffer& encrypted_data)
{
AttestationResult result(AttestationResult::ErrorCode::SUCCESS);
if (pkey_bio == NULL ||
input_data.empty()) {
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_INVALID_INPUT_PARAMETER,
"Invalid input parameter");
}
const EVP_MD* rsa_md = EVP_md_null();
switch (rsaHashAlgId)
{
case RsaHashAlg::RsaSha1:
rsa_md = EVP_sha1();
break;
case RsaHashAlg::RsaSha256:
rsa_md = EVP_sha256();
break;
case RsaHashAlg::RsaSha384:
rsa_md = EVP_sha384();
break;
case RsaHashAlg::RsaSha512:
rsa_md = EVP_sha512();
break;
default:
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_INIT_FAILED,
"EncryptDataWithRSAPubKey failed; called with unknown message digest algorithm");
}
// Set the RSA padding and message digest algorithm
int ret = 0;
int rsa_padding_algo = 0;
switch (rsaWrapAlgId)
{
case RsaScheme::RsaEs:
rsa_padding_algo = RSA_PKCS1_PADDING;
break;
case RsaScheme::RsaOaep:
rsa_padding_algo = RSA_PKCS1_OAEP_PADDING;
break;
case RsaScheme::RsaNull:
rsa_padding_algo = RSA_NO_PADDING;
break;
default:
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_INIT_FAILED,
"EncryptDataWithRSAPubKey failed; called with unknown RSA padding algorithm");
}
EVP_PKEY* pkey = PEM_read_bio_PUBKEY(pkey_bio, NULL, NULL, NULL);
EVP_PKEY_CTX* enc_ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (EVP_PKEY_encrypt_init(enc_ctx) <= 0) {
EVP_PKEY_CTX_free(enc_ctx);
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_INIT_FAILED,
"EVP_PKEY_encrypt_init failed");
}
// Set the RSA padding algorithm
ret = EVP_PKEY_CTX_set_rsa_padding(enc_ctx, rsa_padding_algo);
if (ret <= 0)
{
EVP_PKEY_CTX_free(enc_ctx);
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_INIT_FAILED,
"EVP_PKEY_CTX_set_rsa_padding failed");
}
// Set the RSA message digest algorithm
if (rsaWrapAlgId == RsaScheme::RsaOaep)
{
ret = EVP_PKEY_CTX_set_rsa_oaep_md(enc_ctx, rsa_md);
if (ret <= 0)
{
EVP_PKEY_CTX_free(enc_ctx);
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_INIT_FAILED,
"EVP_PKEY_CTX_set_rsa_oaep_md failed");
}
}
else if (rsaWrapAlgId == RsaScheme::RsaEs)
{
// TODO: There isn't equivalent of EVP_PKEY_CTX_set_rsa_oaep_md for RSA_PKCS1_PADDING
// Need to figure out how to set the hash algorithm for RSA_PKCS1_PADDING
// Note: 1- EVP_PKEY_CTX_set_rsa_oaep_md is only used for RSA_PKCS1_OAEP_PADDING
// and not for RSA_PKCS1_PADDING. EVP_PKEY_CTX_set_rsa_oaep_md throws on Linux,
// but not on Windows.
// 2- EVP_PKEY_CTX_set_signature_md is for signing and not for encryption.
// ret = EVP_PKEY_CTX_set_rsa_???_md(enc_ctx, rsa_md);
}
else if (rsaWrapAlgId == RsaScheme::RsaNull)
{
// No need to set any MD for RSA_NO_PADDING
}
else
{
// Should never get here, since we already checked for valid values
EVP_PKEY_CTX_free(enc_ctx);
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_INIT_FAILED,
"Invalid RSA wrap algorithm");
}
// Encrypt the data
size_t outlen;
unsigned char* out;
if (EVP_PKEY_encrypt(enc_ctx, NULL, &outlen, &input_data.front(), input_data.size()) <= 0) {
EVP_PKEY_CTX_free(enc_ctx);
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_FAILED,
"EVP_PKEY_encrypt failed");
}
out = (unsigned char*)OPENSSL_malloc(outlen);
if (EVP_PKEY_encrypt(enc_ctx, out, &outlen, &input_data.front(), input_data.size()) <= 0) {
EVP_PKEY_CTX_free(enc_ctx);
OPENSSL_free(out);
return LogErrorAndGetResult(AttestationResult::ErrorCode::ERROR_EVP_PKEY_ENCRYPT_FAILED,
"EVP_PKEY_encrypt failed");
}
Buffer out_data(out, out + outlen);
encrypted_data = out_data;
EVP_PKEY_CTX_free(enc_ctx);
OPENSSL_free(out);
return result;
}