TBB: use ASN.1 type DigestInfo to represent hashes
authorJuan Castillo <juan.castillo@arm.com>
Thu, 5 Mar 2015 14:30:00 +0000 (14:30 +0000)
committerJuan Castillo <juan.castillo@arm.com>
Thu, 25 Jun 2015 07:53:26 +0000 (08:53 +0100)
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

common/auth/polarssl/polarssl.c
tools/cert_create/include/ext.h
tools/cert_create/src/ext.c
tools/cert_create/src/main.c

index e099f50cdf3626a360debde8892016edb8eefd52..82c8b33168abffac960690f11e43a4e40aeb4a7a 100644 (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;
 }
 
 /*
index d73f5734fbeebe91a071309a045a4baa936265f7..57bb65f3de2229fcfc44458f1fb2752505418188 100644 (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);
 
index 31f84a86b477f325a051ae39d4146b0496181b8f..21b90db17a2eb1649d19ec8b76d585f6414cee29 100644 (file)
 #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;
 }
index 6df367a244243ba14f876ff496373748762ad980..2af5247fc5e8bc52bd956b8adafe089efdcfad88 100644 (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);