TBB: use ASN.1 type DigestInfo to represent hashes

The cert_create tool calculates the hash of each BL image and includes
it as an ASN.1 OCTET STRING in the corresponding certificate extension.
Without additional information, the firmware running on the platform
has to know in advance the algorithm used to generate the hash.

This patch modifies the cert_create tool so the certificate extensions
that include an image hash are generated according to the following
ASN.1 structure:

    DigestInfo ::= SEQUENCE {
        digestAlgorithm  AlgorithmIdentifier,
        digest           OCTET STRING
    }

    AlgorithmIdentifier ::=  SEQUENCE  {
        algorithm        OBJECT IDENTIFIER,
        parameters       ANY DEFINED BY algorithm OPTIONAL
    }

The PolarSSL module has been updated to extract the image hash
from the certificate extension according to this structure.

Change-Id: I6d83430f12a8a0eea8447bec7c936e903f644c85
This commit is contained in:
Juan Castillo 2015-03-05 14:30:00 +00:00
parent fd34e7ba77
commit c3da66b1bb
4 changed files with 173 additions and 43 deletions

View File

@ -51,8 +51,8 @@
* during the Trusted Boot process.
*/
/* SHA256 algorithm */
#define SHA_BYTES 32
/* Maximum OID string length ("a.b.c.d.e.f ...") */
#define MAX_OID_STR_LEN 64
/*
* An 8 KB stack has been proven to be enough for the current Trusted Boot
@ -78,6 +78,18 @@ static unsigned char heap[POLARSSL_HEAP_SIZE];
*/
#define RSA_PUB_DER_MAX_BYTES 38 + 2 * POLARSSL_MPI_MAX_SIZE
/*
* SHA256:
* DigestInfo ::= SEQUENCE { 1 + 1
* digestAlgorithm AlgorithmIdentifier, + 1 + 1 (sequence)
* + 1 + 1 + 9 (sha256 oid)
* + 1 + 1 (params null)
* digest OCTET STRING + 1 + 1 + 32 (sha256)
* }
*/
#define SHA256_BYTES 32
#define SHA256_DER_BYTES (19 + SHA256_BYTES)
/*
* Buffer for storing public keys extracted from certificates while they are
* verified
@ -89,13 +101,13 @@ static x509_crt cert;
/* BL specific variables */
#if IMAGE_BL1
static unsigned char sha_bl2[SHA_BYTES];
static unsigned char sha_bl2[SHA256_DER_BYTES];
#elif IMAGE_BL2
/* Buffers to store the hash of BL3-x images */
static unsigned char sha_bl30[SHA_BYTES];
static unsigned char sha_bl31[SHA_BYTES];
static unsigned char sha_bl32[SHA_BYTES];
static unsigned char sha_bl33[SHA_BYTES];
static unsigned char sha_bl30[SHA256_DER_BYTES];
static unsigned char sha_bl31[SHA256_DER_BYTES];
static unsigned char sha_bl32[SHA256_DER_BYTES];
static unsigned char sha_bl33[SHA256_DER_BYTES];
/* Buffers to store the Trusted and Non-Trusted world public keys */
static unsigned char tz_world_pk[RSA_PUB_DER_MAX_BYTES];
static unsigned char ntz_world_pk[RSA_PUB_DER_MAX_BYTES];
@ -111,12 +123,12 @@ static int x509_get_crt_ext_data(const unsigned char **ext_data,
x509_crt *crt,
const char *oid)
{
int ret;
int ret, oid_len;
size_t len;
unsigned char *end_ext_data, *end_ext_octet;
unsigned char *p;
const unsigned char *end;
char oid_str[64];
char oid_str[MAX_OID_STR_LEN];
p = crt->v3_ext.p;
end = crt->v3_ext.p + crt->v3_ext.len;
@ -177,8 +189,12 @@ static int x509_get_crt_ext_data(const unsigned char **ext_data,
POLARSSL_ERR_ASN1_LENGTH_MISMATCH;
/* Detect requested extension */
oid_get_numeric_string(oid_str, 64, &extn_oid);
if (memcmp(oid, oid_str, sizeof(oid)) == 0) {
oid_len = oid_get_numeric_string(oid_str,
MAX_OID_STR_LEN, &extn_oid);
if (oid_len == POLARSSL_ERR_OID_BUF_TOO_SMALL)
return POLARSSL_ERR_X509_INVALID_EXTENSIONS +
POLARSSL_ERR_ASN1_BUF_TOO_SMALL;
if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
*ext_data = p;
*ext_len = len;
return 0;
@ -251,11 +267,8 @@ static int check_bl2_cert(unsigned char *buf, size_t len)
goto error;
}
assert(sz == SHA_BYTES + 2);
/* Skip the tag and length bytes and copy the hash */
p += 2;
memcpy(sha_bl2, p, SHA_BYTES);
assert(sz == SHA256_DER_BYTES);
memcpy(sha_bl2, p, SHA256_DER_BYTES);
error:
x509_crt_free(&cert);
@ -433,11 +446,8 @@ static int check_bl3x_cert(unsigned char *buf, size_t len,
goto error;
}
assert(sz == SHA_BYTES + 2);
/* Skip the tag and length bytes and copy the hash */
p += 2;
memcpy(sha, p, SHA_BYTES);
assert(sz == SHA256_DER_BYTES);
memcpy(sha, p, SHA256_DER_BYTES);
error:
x509_crt_free(&cert);
@ -460,18 +470,68 @@ error:
static int check_bl_img(unsigned char *buf, size_t len,
const unsigned char *sha)
{
unsigned char img_sha[SHA_BYTES];
asn1_buf md_oid, params;
md_type_t md_alg;
int err;
unsigned char *p = NULL;
const unsigned char *end = NULL;
size_t sz;
unsigned char img_sha[SHA256_BYTES];
/*
* Extract the image hash from the ASN.1 structure:
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING
* }
*/
p = (unsigned char *)sha;
end = sha + SHA256_DER_BYTES;
err = asn1_get_tag(&p, end, &sz, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (err != 0) {
ERROR("Malformed image hash extension\n");
goto error;
}
err = asn1_get_alg(&p, end, &md_oid, &params);
if (err != 0) {
ERROR("Malformed image hash algorithm\n");
goto error;
}
err = oid_get_md_alg(&md_oid, &md_alg);
if (err != 0) {
ERROR("Unknown image hash algorithm\n");
goto error;
}
/* Only SHA256 is supported */
if (md_alg != POLARSSL_MD_SHA256) {
ERROR("Only SHA256 is supported as image hash algorithm\n");
err = 1;
goto error;
}
/* Get the hash */
err = asn1_get_tag(&p, end, &sz, ASN1_OCTET_STRING);
if (err != 0) {
ERROR("Image hash not found in extension\n");
goto error;
}
/* Calculate the hash of the image */
sha256(buf, len, img_sha, 0);
/* Match the hash with the one extracted from the certificate */
if (memcmp(img_sha, sha, SHA_BYTES)) {
if (memcmp(img_sha, p, SHA256_BYTES)) {
ERROR("Image hash mismatch\n");
return 1;
}
return 0;
error:
return err;
}
/*

View File

@ -63,7 +63,8 @@ enum {
};
int ext_init(ext_t *tbb_ext);
X509_EXTENSION *ext_new_hash(int nid, int crit, unsigned char *buf, size_t len);
X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
unsigned char *buf, size_t len);
X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value);
X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k);

View File

@ -31,13 +31,29 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
#include "ext.h"
DECLARE_ASN1_ITEM(ASN1_INTEGER)
DECLARE_ASN1_ITEM(X509_ALGOR)
DECLARE_ASN1_ITEM(ASN1_OCTET_STRING)
typedef struct {
X509_ALGOR *hashAlgorithm;
ASN1_OCTET_STRING *dataHash;
} HASH;
ASN1_SEQUENCE(HASH) = {
ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR),
ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(HASH)
DECLARE_ASN1_FUNCTIONS(HASH)
IMPLEMENT_ASN1_FUNCTIONS(HASH)
/*
* This function adds the TBB extensions to the internal extension list
* maintained by OpenSSL so they can be used later.
@ -123,37 +139,85 @@ X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len)
}
/*
* Creates a x509v3 extension containing a hash encapsulated in an ASN1 Octet
* String
* Creates a x509v3 extension containing a hash
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING
* }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*
* Parameters:
* pex: OpenSSL extension pointer (output parameter)
* nid: extension identifier
* crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
* md: hash algorithm
* buf: pointer to the buffer that contains the hash
* len: size of the hash in bytes
*
* Return: Extension address, NULL if error
*/
X509_EXTENSION *ext_new_hash(int nid, int crit, unsigned char *buf, size_t len)
X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
unsigned char *buf, size_t len)
{
X509_EXTENSION *ex = NULL;
ASN1_OCTET_STRING *hash = NULL;
ASN1_OCTET_STRING *octet = NULL;
HASH *hash = NULL;
ASN1_OBJECT *algorithm = NULL;
X509_ALGOR *x509_algor = NULL;
unsigned char *p = NULL;
int sz = -1;
/* Encode Hash */
hash = ASN1_OCTET_STRING_new();
ASN1_OCTET_STRING_set(hash, buf, len);
sz = i2d_ASN1_OCTET_STRING(hash, NULL);
i2d_ASN1_OCTET_STRING(hash, &p);
/* OBJECT_IDENTIFIER with hash algorithm */
algorithm = OBJ_nid2obj(md->type);
if (algorithm == NULL) {
return NULL;
}
/* Create X509_ALGOR */
x509_algor = X509_ALGOR_new();
if (x509_algor == NULL) {
return NULL;
}
x509_algor->algorithm = algorithm;
x509_algor->parameter = ASN1_TYPE_new();
ASN1_TYPE_set(x509_algor->parameter, V_ASN1_NULL, NULL);
/* OCTET_STRING with the actual hash */
octet = ASN1_OCTET_STRING_new();
if (octet == NULL) {
X509_ALGOR_free(x509_algor);
return NULL;
}
ASN1_OCTET_STRING_set(octet, buf, len);
/* HASH structure containing algorithm + hash */
hash = HASH_new();
if (hash == NULL) {
ASN1_OCTET_STRING_free(octet);
X509_ALGOR_free(x509_algor);
return NULL;
}
hash->hashAlgorithm = x509_algor;
hash->dataHash = octet;
/* DER encoded HASH */
sz = i2d_HASH(hash, &p);
if ((sz <= 0) || (p == NULL)) {
HASH_free(hash);
X509_ALGOR_free(x509_algor);
return NULL;
}
/* Create the extension */
ex = ext_new(nid, crit, p, sz);
/* Clean up */
OPENSSL_free(p);
ASN1_OCTET_STRING_free(hash);
HASH_free(hash);
return ex;
}

View File

@ -277,6 +277,7 @@ int main(int argc, char *argv[])
int i, tz_nvctr_nid, ntz_nvctr_nid, hash_nid, pk_nid;
int c, opt_idx = 0;
unsigned char md[SHA256_DIGEST_LENGTH];
const EVP_MD *md_info;
NOTICE("CoT Generation Tool: %s\n", build_msg);
NOTICE("Target platform: %s\n", platform_msg);
@ -389,6 +390,10 @@ int main(int argc, char *argv[])
exit(1);
}
/* Indicate SHA256 as image hash algorithm in the certificate
* extension */
md_info = EVP_sha256();
/* Get non-volatile counters NIDs */
CHECK_OID(tz_nvctr_nid, TZ_FW_NVCOUNTER_OID);
CHECK_OID(ntz_nvctr_nid, NTZ_FW_NVCOUNTER_OID);
@ -430,7 +435,7 @@ int main(int argc, char *argv[])
exit(1);
}
CHECK_OID(hash_nid, BL2_HASH_OID);
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md,
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md_info, md,
SHA256_DIGEST_LENGTH));
sk_X509_EXTENSION_push(sk, hash_ext);
@ -509,8 +514,8 @@ int main(int argc, char *argv[])
exit(1);
}
CHECK_OID(hash_nid, BL30_HASH_OID);
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md,
SHA256_DIGEST_LENGTH));
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md_info,
md, SHA256_DIGEST_LENGTH));
sk_X509_EXTENSION_push(sk, hash_ext);
if (!cert_new(&certs[BL30_CERT], VAL_DAYS, 0, sk)) {
@ -559,7 +564,7 @@ int main(int argc, char *argv[])
exit(1);
}
CHECK_OID(hash_nid, BL31_HASH_OID);
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md,
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md_info, md,
SHA256_DIGEST_LENGTH));
sk_X509_EXTENSION_push(sk, hash_ext);
@ -612,8 +617,8 @@ int main(int argc, char *argv[])
exit(1);
}
CHECK_OID(hash_nid, BL32_HASH_OID);
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md,
SHA256_DIGEST_LENGTH));
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md_info,
md, SHA256_DIGEST_LENGTH));
sk_X509_EXTENSION_push(sk, hash_ext);
if (!cert_new(&certs[BL32_CERT], VAL_DAYS, 0, sk)) {
@ -662,7 +667,7 @@ int main(int argc, char *argv[])
exit(1);
}
CHECK_OID(hash_nid, BL33_HASH_OID);
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md,
CHECK_NULL(hash_ext, ext_new_hash(hash_nid, EXT_CRIT, md_info, md,
SHA256_DIGEST_LENGTH));
sk_X509_EXTENSION_push(sk, hash_ext);