Skip to content

Commit

Permalink
Adding full validate_cert_chain capability
Browse files Browse the repository at this point in the history
Finish CEK validation, which is an SEV_CERT with an RSA signature

Signed-off-by: Brian Lilienthal <[email protected]>
  • Loading branch information
lilienbm-zz committed Feb 19, 2020
1 parent 89665ca commit 7e58d94
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 47 deletions.
7 changes: 2 additions & 5 deletions src/amdcert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ SEV_ERROR_CODE AMDCert::amd_cert_validate_sig(const amd_cert *cert,
uint32_t sig_len = cert->modulus_size/8;

uint32_t digest_len = 0;
uint8_t decrypted[AMD_CERT_KEY_BYTES_4K] = {0};
uint8_t decrypted[AMD_CERT_KEY_BYTES_4K] = {0}; // TODO wrong length
uint8_t signature[AMD_CERT_KEY_BYTES_4K] = {0};
uint32_t fixed_offset = offsetof(amd_cert, pub_exp); // 64 bytes
ePSP_DEVICE_TYPE device_type = m_sev_device->get_device_type();
Expand All @@ -139,14 +139,11 @@ SEV_ERROR_CODE AMDCert::amd_cert_validate_sig(const amd_cert *cert,
sha_digest = sha_digest_256;
sha_length = sizeof(hmac_sha_256);
}
else if (device_type == PSP_DEVICE_TYPE_ROME) {
else /*if (device_type == PSP_DEVICE_TYPE_ROME)*/ {
algo = SEV_SIG_ALGO_RSA_SHA384;
sha_digest = sha_digest_384;
sha_length = sizeof(hmac_sha_512);
}
else {
break;
}

// Memzero all the buffers
memset(sha_digest, 0, sha_length);
Expand Down
6 changes: 3 additions & 3 deletions src/amdcert.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define AMDCERT_H

#include "sevapi.h"
#include "sevcore.h" // for ePSP_DEVICE_TYPE
#include "sevcore.h" // for SEVDevice
#include <string>

constexpr uint32_t AMD_CERT_VERSION = 0x01;
Expand All @@ -32,8 +32,8 @@ static constexpr uint8_t amd_root_key_id_naples[AMD_CERT_ID_SIZE_BYTES] = {
0xb1, 0x74, 0x94, 0x56, 0x01, 0xc9, 0xea, 0x5b,
};
static constexpr uint8_t amd_root_key_id_rome[AMD_CERT_ID_SIZE_BYTES] = {
0xe6, 0x00, 0x21, 0x22, 0xfb, 0x58, 0x41, 0x93,
0x99, 0xd1, 0x5f, 0xee, 0x7b, 0x13, 0x13, 0x51
0xe6, 0x00, 0x21, 0x22, 0xfb, 0x58, 0x41, 0x93,
0x99, 0xd1, 0x5f, 0xee, 0x7b, 0x13, 0x13, 0x51
};

// Public global functions
Expand Down
7 changes: 3 additions & 4 deletions src/commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,12 +680,11 @@ int Command::validate_cert_chain(void)
cmd_ret = tmp_amd.amd_cert_export_pub_key(&ask, &ask_pubkey);
if (cmd_ret != STATUS_SUCCESS)
break;
// print_sev_cert_readable(&ask_pubkey);

// Validate the CEK
// cmd_ret = tmp_sev_cek.verify_sev_cert(&ask_pubkey);
// if (cmd_ret != STATUS_SUCCESS)
// break;
cmd_ret = tmp_sev_cek.verify_sev_cert(&ask_pubkey);
if (cmd_ret != STATUS_SUCCESS)
break;

// Validate the PEK with the CEK and OCA
cmd_ret = tmp_sev_pek.verify_sev_cert(&cek, &oca);
Expand Down
10 changes: 5 additions & 5 deletions src/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ bool encrypt(uint8_t *out, const uint8_t *in, size_t length,
break;

// Initialize the encryption operation. IMPORTANT - ensure you
// use a key and iv size appropriate for your cipher
// use a key and IV size appropriate for your cipher
if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv) != 1)
break;

Expand Down Expand Up @@ -612,11 +612,11 @@ SEV_ERROR_CODE aes_256_gcm_authenticated_encrypt(const uint8_t *p_key, size_t ke
if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
break;

// Sets the iv length: Can only be called before specifying an iv [Optional for GCM]
// Sets the IV length: Can only be called before specifying an IV [Optional for GCM]
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)iv_size, NULL))
break;

// Now initialize the context with key and iv
// Now initialize the context with key and IV
if (!EVP_EncryptInit_ex(ctx, NULL, NULL, p_key, p_iv))
break;

Expand Down Expand Up @@ -700,15 +700,15 @@ SEV_ERROR_CODE aes_256_gcm_authenticated_decrypt(const uint8_t *p_key, size_t ke

EVP_CIPHER_CTX_set_padding(ctx, 0);

// Sets the iv length: Can only be called before specifying an iv [Optional for GCM]
// Sets the IV length: Can only be called before specifying an IV [Optional for GCM]
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)iv_size, NULL))
break;

// Set Tag from the data
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, (uint8_t *)p_tag))
break;

// Now initialize the context with key and iv
// Now initialize the context with key and IV
if (!EVP_DecryptInit_ex(ctx, NULL, NULL, p_key, p_iv))
break;

Expand Down
1 change: 0 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ int main(int argc, char **argv)
break;
}
case 'u': { // VALIDATE_CERT_CHAIN
printf("This command is not complete, do not trust the output\n");
Command cmd(output_folder, verbose_flag);
cmd_ret = cmd.validate_cert_chain();
break;
Expand Down
72 changes: 45 additions & 27 deletions src/sevcert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <cstring> // memset
#include <cstring> // memset
#include <fstream>
#include <stdio.h>
#include <stdexcept>
Expand Down Expand Up @@ -336,7 +336,7 @@ bool SEVCert::create_godh_cert(EVP_PKEY **godh_key_pair, uint8_t api_major,
}

/**
* Description: Populates an empty sev_cert using an existing ecdh keypair
* Description: Populates an empty sev_cert using an existing ECDH keypair
* Typical Usage: Used to generate the Guest Owner Diffie-Hellman cert used in
* LaunchStart
* Parameters: [oca_key_pair] the input pub/priv key pair used to populate
Expand Down Expand Up @@ -539,7 +539,7 @@ SEV_ERROR_CODE SEVCert::validate_signature(const sev_cert *child_cert,
size_t sha_length = 0;

do{
//todo should this be child cert? should prob combine this function anyway
//TODO should this be child cert? should prob combine this function anyway
// Determine if SHA_TYPE is 256 bit or 384 bit
if (parent_cert->pub_key_algo == SEV_SIG_ALGO_RSA_SHA256 || parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256 ||
parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDH_SHA256)
Expand Down Expand Up @@ -575,24 +575,38 @@ SEV_ERROR_CODE SEVCert::validate_signature(const sev_cert *child_cert,
{
if ((parent_cert->pub_key_algo == SEV_SIG_ALGO_RSA_SHA256) ||
(parent_cert->pub_key_algo == SEV_SIG_ALGO_RSA_SHA384)) {
// TODO: THIS CODE IS UNTESTED!!!!!!!!!!!!!!!!!!!!!!!!!!!
printf("TODO validate_signature segfaults on RSA_verify\n");
uint32_t sig_len = parent_cert->pub_key.rsa.modulus_size/8; // Should be child_cert but SEV_RSA_SIG doesn't have a size param
uint8_t decrypted[parent_cert->pub_key.rsa.modulus_size] = {0}; // TODO wrong length
uint8_t signature[parent_cert->pub_key.rsa.modulus_size] = {0};

RSA *rsa = EVP_PKEY_get1_RSA(parent_signing_key); // Signer's (parent's) public key
if (!rsa) {
RSA *rsa_pub_key = EVP_PKEY_get1_RSA(parent_signing_key); // Signer's (parent's) public key
if (!rsa_pub_key) {
printf("Error parent signing key is bad\n");
break;
}

uint32_t sig_len = sizeof(parent_cert->sig_1.rsa); // size is wrong. should be modulus_size
if (RSA_verify((sha_type == SHA_TYPE_256) ? NID_sha256 : NID_sha384,
sha_digest, (uint32_t)sha_length, (uint8_t *)&parent_cert->sig_1.rsa, sig_len, rsa) != 1 ) {
RSA_free(rsa);
// Swap the bytes of the signature
memcpy(signature, &cert_sig[i].rsa, parent_cert->pub_key.rsa.modulus_size/8);
if (!sev::reverse_bytes(signature, parent_cert->pub_key.rsa.modulus_size/8))
break;

// Now we will verify the signature. Start by a RAW decrypt of the signature
if (RSA_public_decrypt(sig_len, signature, decrypted, rsa_pub_key, RSA_NO_PADDING) == -1)
break;

// Verify the data
// SLen of -2 means salt length is recovered from the signature
if (RSA_verify_PKCS1_PSS(rsa_pub_key, sha_digest,
(parent_cert->pub_key_algo == SEV_SIG_ALGO_RSA_SHA256) ? EVP_sha256() : EVP_sha384(),
decrypted, -2) != 1)
{
RSA_free(rsa_pub_key);
continue;
}

found_match = true;
RSA_free(rsa);
continue;
RSA_free(rsa_pub_key);
break;
}
else if ((parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256) ||
(parent_cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA384) ||
Expand All @@ -617,12 +631,16 @@ SEV_ERROR_CODE SEVCert::validate_signature(const sev_cert *child_cert,
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)
found_match = true;
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
continue;
break;
}
else { // Bad/unsupported signing key algorithm
printf("Unexpected algorithm! %x\n", parent_cert->pub_key_algo);
Expand Down Expand Up @@ -691,14 +709,14 @@ SEV_ERROR_CODE SEVCert::compile_public_key_from_certificate(const sev_cert *cert
do {
if ((cert->pub_key_algo == SEV_SIG_ALGO_RSA_SHA256) ||
(cert->pub_key_algo == SEV_SIG_ALGO_RSA_SHA384)) {
// TODO: THIS CODE IS UNTESTED!!!!!!!!!!!!!!!!!!!!!!!!!!!
printf("WARNING: You are using untested code in"
"compile_public_key_from_certificate for RSA cert type!\n");
// New up the RSA key
rsa_pub_key = RSA_new();

modulus = BN_lebin2bn(cert->pub_key.rsa.modulus, sizeof(cert->pub_key.rsa.modulus), NULL); // New's up BigNum
pub_exp = BN_lebin2bn(cert->pub_key.rsa.pub_exp, sizeof(cert->pub_key.rsa.pub_exp), NULL);
RSA_set0_key(rsa_pub_key, modulus, pub_exp, NULL);
// Convert the parent to an RSA key to pass into RSA_verify
modulus = BN_lebin2bn((uint8_t *)&cert->pub_key.rsa.modulus, cert->pub_key.rsa.modulus_size/8, NULL); // n // New's up BigNum
pub_exp = BN_lebin2bn((uint8_t *)&cert->pub_key.rsa.pub_exp, cert->pub_key.rsa.modulus_size/8, NULL); // e
if (RSA_set0_key(rsa_pub_key, modulus, pub_exp, NULL) != 1)
break;

// Make sure the key is good.
// TODO: This step fails because, from the openssl doc:
Expand All @@ -713,8 +731,8 @@ SEV_ERROR_CODE SEVCert::compile_public_key_from_certificate(const sev_cert *cert
* is freed, rsa_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_RSA(evp_pub_key, rsa_pub_key) != 1)
// break;
if (EVP_PKEY_assign_RSA(evp_pub_key, rsa_pub_key) != 1)
break;
}
else if ((cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA256) ||
(cert->pub_key_algo == SEV_SIG_ALGO_ECDSA_SHA384) ||
Expand Down Expand Up @@ -763,10 +781,10 @@ SEV_ERROR_CODE SEVCert::compile_public_key_from_certificate(const sev_cert *cert
} while (0);

// Free memory if it was allocated
BN_free(y_big_num); // If NULL, does nothing
BN_free(y_big_num); // If NULL, does nothing
BN_free(x_big_num);
BN_free(modulus);
BN_free(pub_exp);
// BN_free(modulus); // Don't free here. RSA key is associated with these
// BN_free(pub_exp);

return cmd_ret;
}
Expand Down
4 changes: 2 additions & 2 deletions src/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,8 @@ bool Tests::test_all()
if (!test_calc_measurement())
break;

// if (!test_validate_cert_chain())
// break;
if (!test_validate_cert_chain())
break;

if (!test_generate_launch_blob())
break;
Expand Down

0 comments on commit 7e58d94

Please sign in to comment.