in client-library/src/Attestation/AttestationClient/lib/TpmUnseal.cpp [195:329]
bool attest::DecryptJwt(const EncryptionParameters& encryption_params,
const attest::Buffer& decryption_key,
const attest::Buffer& jwt_encrypted,
std::string& jwt_decrypted,
std::string& err) {
err.clear();
if(encryption_params.block_mode != attest::BlockCipherMode::CHAINING_MODE_GCM) {
CLIENT_LOG_ERROR("Unsupported block mode");
err = std::string("Error: Unsupported block mode");
return false;
}
if(encryption_params.block_padding != attest::BlockCipherPadding::PKCS7) {
CLIENT_LOG_ERROR("Unsupported block padding");
err = std::string("Error: Unsupported block padding");
return false;
}
if(encryption_params.cipher_alg != attest::CipherAlgorithm::AES) {
CLIENT_LOG_ERROR("Unsupported decryption algorithm");
err = std::string("Error: Unsupported decryption algorithm");
return false;
}
EVP_CIPHER_CTX *ctx;
// Create and initialise the context
if(!(ctx = EVP_CIPHER_CTX_new())) {
CLIENT_LOG_ERROR("Openssl Error: Failed to initialize evp cipher");
err = std::string("Openssl Error: Failed to initialize evp cipher");
return false;
}
const EVP_CIPHER* alg = _GetOpenSslAesGcmAlg(decryption_key.size());
if(alg == nullptr) {
CLIENT_LOG_ERROR("Openssl Error: Failed to get decryption algorithm");
err = std::string("Openssl Error: Failed to get decryption algorithm");
return false;
}
//Initialise the decryption operation.
if(!EVP_DecryptInit_ex(ctx, alg, NULL, NULL, NULL)) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());
err = std::string("Openssl Error:") + error_str;
return false;
}
// Set IV length. Not necessary if this is 12 bytes (96 bits)
if(!EVP_CIPHER_CTX_ctrl(ctx,
EVP_CTRL_GCM_SET_IVLEN,
static_cast<int>(encryption_params.iv.size()),
NULL)) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());
err = std::string("Openssl Error:") + error_str;
return false;
}
// Initialise key and IV
if(!EVP_DecryptInit_ex(ctx,
NULL,
NULL,
decryption_key.data(),
encryption_params.iv.data())) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());
err = std::string("Openssl Error:") + error_str;
return false;
}
attest::Buffer auth_data{'T','r','a','n','s','p','o','r','t',' ','K','e','y'};
int out_bytes = 0;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx,
NULL,
&out_bytes,
auth_data.data(),
static_cast<int>(auth_data.size()))) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());;
err = std::string("Openssl Error:") + error_str;
return false;
}
attest::Buffer plain_text(jwt_encrypted.size());
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx,
plain_text.data(),
&out_bytes,
(const unsigned char*)jwt_encrypted.data(),
static_cast<int>(jwt_encrypted.size()))) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());
err = std::string("Openssl Error:") + error_str;
return false;
}
// Set expected tag value. Works in OpenSSL 1.0.1d and later
if(!EVP_CIPHER_CTX_ctrl(ctx,
EVP_CTRL_GCM_SET_TAG,
static_cast<int>(encryption_params.authentication_data.size()),
(void *)encryption_params.authentication_data.data())) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());
err = std::string("Openssl Error:") + error_str;
return false;
}
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
int ret = EVP_DecryptFinal_ex(ctx,
plain_text.data(),
&out_bytes);
if(ret <= 0) {
std::string error_str(ERR_error_string(ERR_get_error(), nullptr));
CLIENT_LOG_ERROR("Openssl Error:%s", error_str.c_str());
err = std::string("Openssl Error:") + error_str;
return false;
}
// Clean up
EVP_CIPHER_CTX_free(ctx);
jwt_decrypted.assign(plain_text.begin(), plain_text.end());
return true;
}