/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* Authentication module based on PolarSSL */ #include #include #include #include #include #include #include #include #include #include #include #include /* * At each authentication stage, the module is responsible for extracting and * storing those elements (keys, hashes, etc.) that will be needed later on * during the Trusted Boot process. */ /* SHA256 algorithm */ #define SHA_BYTES 32 /* * An 8 KB stack has been proven to be enough for the current Trusted Boot * process */ #define POLARSSL_HEAP_SIZE (8*1024) static unsigned char heap[POLARSSL_HEAP_SIZE]; /* * RSA public keys: * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3 * algorithm AlgorithmIdentifier, 1 + 1 (sequence) * + 1 + 1 + 9 (rsa oid) * + 1 + 1 (params null) * subjectPublicKey BIT STRING } 1 + 3 + (1 + below) * RSAPublicKey ::= SEQUENCE { 1 + 3 * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1 * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1 * } * * POLARSSL_MPI_MAX_SIZE is set to 256 bytes (RSA-2048 bit keys) in the * configuration file */ #define RSA_PUB_DER_MAX_BYTES 38 + 2 * POLARSSL_MPI_MAX_SIZE /* * Buffer for storing public keys extracted from certificates while they are * verified */ static unsigned char pk_buf[RSA_PUB_DER_MAX_BYTES]; /* We use this variable to parse and authenticate the certificates */ static x509_crt cert; /* BL specific variables */ #if IMAGE_BL1 static unsigned char sha_bl2[SHA_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]; /* 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]; static size_t tz_world_pk_len, ntz_world_pk_len; /* Buffer to store the BL3-x public keys */ static unsigned char content_pk[RSA_PUB_DER_MAX_BYTES]; static size_t content_pk_len; #endif static int x509_get_crt_ext_data(const unsigned char **ext_data, size_t *ext_len, x509_crt *crt, const char *oid) { int ret; size_t len; unsigned char *end_ext_data, *end_ext_octet; unsigned char *p; const unsigned char *end; char oid_str[64]; p = crt->v3_ext.p; end = crt->v3_ext.p + crt->v3_ext.len; ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; if (end != p + len) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH; while (p < end) { /* * Extension ::= SEQUENCE { * extnID OBJECT IDENTIFIER, * critical BOOLEAN DEFAULT FALSE, * extnValue OCTET STRING } */ x509_buf extn_oid = {0, 0, NULL}; int is_critical = 0; /* DEFAULT FALSE */ ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; end_ext_data = p + len; /* Get extension ID */ extn_oid.tag = *p; ret = asn1_get_tag(&p, end, &extn_oid.len, ASN1_OID); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; extn_oid.p = p; p += extn_oid.len; if ((end - p) < 1) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_OUT_OF_DATA; /* Get optional critical */ ret = asn1_get_bool(&p, end_ext_data, &is_critical); if (ret != 0 && (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG)) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; /* Data should be octet string type */ ret = asn1_get_tag(&p, end_ext_data, &len, ASN1_OCTET_STRING); if (ret != 0) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + ret; end_ext_octet = p + len; if (end_ext_octet != end_ext_data) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + 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) { *ext_data = p; *ext_len = len; return 0; } /* Next */ p = end_ext_octet; } if (p != end) return POLARSSL_ERR_X509_INVALID_EXTENSIONS + POLARSSL_ERR_ASN1_LENGTH_MISMATCH; return POLARSSL_ERR_X509_UNKNOWN_OID; } #if IMAGE_BL1 /* * Parse and verify the BL2 certificate * * This function verifies the integrity of the BL2 certificate, checks that it * has been signed with the ROT key and extracts the BL2 hash stored in the * certificate so it can be matched later against the calculated hash. * * Return: 0 = success, Otherwise = error */ static int check_bl2_cert(unsigned char *buf, size_t len) { const unsigned char *p; size_t sz; int err, flags; x509_crt_init(&cert); /* Parse the BL2 certificate */ err = x509_crt_parse(&cert, buf, len); if (err) { ERROR("BL2 certificate parse error %d.\n", err); goto error; } /* Check that it has been signed with the ROT key */ err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf)); if (err < 0) { ERROR("Error loading ROT key in DER format %d.\n", err); goto error; } sz = (size_t)err; p = pk_buf + sizeof(pk_buf) - sz; err = plat_match_rotpk(p, sz); if (err) { ERROR("ROT and BL2 certificate key mismatch\n"); goto error; } /* Verify certificate */ err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL); if (err) { ERROR("BL2 certificate verification error %d. Flags: 0x%x.\n", err, flags); goto error; } /* Extract BL2 image hash from certificate */ err = x509_get_crt_ext_data(&p, &sz, &cert, BL2_HASH_OID); if (err) { ERROR("Cannot read BL2 hash from certificate\n"); 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); error: x509_crt_free(&cert); return err; } #endif /* IMAGE_BL1 */ #if IMAGE_BL2 static int check_trusted_key_cert(unsigned char *buf, size_t len) { const unsigned char *p; size_t sz; int err, flags; x509_crt_init(&cert); /* Parse the Trusted Key certificate */ err = x509_crt_parse(&cert, buf, len); if (err) { ERROR("Trusted Key certificate parse error %d.\n", err); goto error; } /* Verify Trusted Key certificate */ err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL); if (err) { ERROR("Trusted Key certificate verification error %d. Flags: " "0x%x.\n", err, flags); goto error; } /* Check that it has been signed with the ROT key */ err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf)); if (err < 0) { ERROR("Error loading ROT key in DER format %d.\n", err); goto error; } sz = (size_t)err; p = pk_buf + sizeof(pk_buf) - sz; if (plat_match_rotpk(p, sz)) { ERROR("ROT and Trusted Key certificate key mismatch\n"); goto error; } /* Extract Trusted World key from extensions */ err = x509_get_crt_ext_data(&p, &tz_world_pk_len, &cert, TZ_WORLD_PK_OID); if (err) { ERROR("Cannot read Trusted World key\n"); goto error; } assert(tz_world_pk_len <= RSA_PUB_DER_MAX_BYTES); memcpy(tz_world_pk, p, tz_world_pk_len); /* Extract Non-Trusted World key from extensions */ err = x509_get_crt_ext_data(&p, &ntz_world_pk_len, &cert, NTZ_WORLD_PK_OID); if (err) { ERROR("Cannot read Non-Trusted World key\n"); goto error; } assert(tz_world_pk_len <= RSA_PUB_DER_MAX_BYTES); memcpy(ntz_world_pk, p, ntz_world_pk_len); error: x509_crt_free(&cert); return err; } static int check_bl3x_key_cert(const unsigned char *buf, size_t len, const unsigned char *i_key, size_t i_key_len, unsigned char *s_key, size_t *s_key_len, const char *key_oid) { const unsigned char *p; size_t sz; int err, flags; x509_crt_init(&cert); /* Parse key certificate */ err = x509_crt_parse(&cert, buf, len); if (err) { ERROR("Key certificate parse error %d.\n", err); goto error; } /* Verify certificate */ err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL); if (err) { ERROR("Key certificate verification error %d. Flags: " "0x%x.\n", err, flags); goto error; } /* Check that the certificate has been signed by the issuer */ err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf)); if (err < 0) { ERROR("Error loading key in DER format %d.\n", err); goto error; } sz = (size_t)err; p = pk_buf + sizeof(pk_buf) - sz; if ((sz != i_key_len) || memcmp(p, i_key, sz)) { ERROR("Key certificate not signed with issuer key\n"); err = 1; goto error; } /* Get the content certificate key */ err = x509_get_crt_ext_data(&p, &sz, &cert, key_oid); if (err) { ERROR("Extension %s not found in Key certificate\n", key_oid); goto error; } assert(sz <= RSA_PUB_DER_MAX_BYTES); memcpy(s_key, p, sz); *s_key_len = sz; error: x509_crt_free(&cert); return err; } static int check_bl3x_cert(unsigned char *buf, size_t len, const unsigned char *i_key, size_t i_key_len, const char *hash_oid, unsigned char *sha) { const unsigned char *p; size_t sz; int err, flags; x509_crt_init(&cert); /* Parse BL31 content certificate */ err = x509_crt_parse(&cert, buf, len); if (err) { ERROR("Content certificate parse error %d.\n", err); goto error; } /* Verify certificate */ err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL); if (err) { ERROR("Content certificate verification error %d. Flags: " "0x%x.\n", err, flags); goto error; } /* Check that content certificate has been signed with the content * certificate key corresponding to this image */ sz = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf)); p = pk_buf + sizeof(pk_buf) - sz; if ((sz != i_key_len) || memcmp(p, i_key, sz)) { ERROR("Content certificate not signed with content " "certificate key\n"); err = 1; goto error; } /* Extract image hash from certificate */ err = x509_get_crt_ext_data(&p, &sz, &cert, hash_oid); if (err) { ERROR("Cannot read hash from certificate\n"); goto error; } assert(sz == SHA_BYTES + 2); /* Skip the tag and length bytes and copy the hash */ p += 2; memcpy(sha, p, SHA_BYTES); error: x509_crt_free(&cert); return err; } #endif /* IMAGE_BL2 */ /* * Calculate the hash of the image and check it against the hash extracted * previously from the certificate * * Parameters: * buf: buffer where image is loaded * len: size of the image * sha: matching hash (extracted from the image certificate) * * Return: 0 = match, Otherwise = mismatch */ static int check_bl_img(unsigned char *buf, size_t len, const unsigned char *sha) { unsigned char img_sha[SHA_BYTES]; /* 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)) { ERROR("Image hash mismatch\n"); return 1; } return 0; } /* * Object verification function * * The id parameter will indicate the expected format of the object * (certificate, image, etc). * * Return: 0 = success, Otherwise = error */ static int polarssl_mod_verify(unsigned int id, uintptr_t obj, size_t len) { int ret; switch (id) { #if IMAGE_BL1 case AUTH_BL2_IMG_CERT: ret = check_bl2_cert((unsigned char *)obj, len); break; case AUTH_BL2_IMG: ret = check_bl_img((unsigned char *)obj, len, sha_bl2); break; #endif /* IMAGE_BL1 */ #if IMAGE_BL2 case AUTH_TRUSTED_KEY_CERT: ret = check_trusted_key_cert((unsigned char *)obj, len); break; case AUTH_BL30_KEY_CERT: ret = check_bl3x_key_cert((unsigned char *)obj, len, tz_world_pk, tz_world_pk_len, content_pk, &content_pk_len, BL30_CONTENT_CERT_PK_OID); break; case AUTH_BL31_KEY_CERT: ret = check_bl3x_key_cert((unsigned char *)obj, len, tz_world_pk, tz_world_pk_len, content_pk, &content_pk_len, BL31_CONTENT_CERT_PK_OID); break; case AUTH_BL32_KEY_CERT: ret = check_bl3x_key_cert((unsigned char *)obj, len, tz_world_pk, tz_world_pk_len, content_pk, &content_pk_len, BL32_CONTENT_CERT_PK_OID); break; case AUTH_BL33_KEY_CERT: ret = check_bl3x_key_cert((unsigned char *)obj, len, ntz_world_pk, ntz_world_pk_len, content_pk, &content_pk_len, BL33_CONTENT_CERT_PK_OID); break; case AUTH_BL30_IMG_CERT: ret = check_bl3x_cert((unsigned char *)obj, len, content_pk, content_pk_len, BL30_HASH_OID, sha_bl30); break; case AUTH_BL31_IMG_CERT: ret = check_bl3x_cert((unsigned char *)obj, len, content_pk, content_pk_len, BL31_HASH_OID, sha_bl31); break; case AUTH_BL32_IMG_CERT: ret = check_bl3x_cert((unsigned char *)obj, len, content_pk, content_pk_len, BL32_HASH_OID, sha_bl32); break; case AUTH_BL33_IMG_CERT: ret = check_bl3x_cert((unsigned char *)obj, len, content_pk, content_pk_len, BL33_HASH_OID, sha_bl33); break; case AUTH_BL30_IMG: ret = check_bl_img((unsigned char *)obj, len, sha_bl30); break; case AUTH_BL31_IMG: ret = check_bl_img((unsigned char *)obj, len, sha_bl31); break; case AUTH_BL32_IMG: ret = check_bl_img((unsigned char *)obj, len, sha_bl32); break; case AUTH_BL33_IMG: ret = check_bl_img((unsigned char *)obj, len, sha_bl33); break; #endif /* IMAGE_BL2 */ default: ret = -1; break; } return ret; } /* * Module initialization function * * Return: 0 = success, Otherwise = error */ static int polarssl_mod_init(void) { /* Initialize the PolarSSL heap */ return memory_buffer_alloc_init(heap, POLARSSL_HEAP_SIZE); } const auth_mod_t auth_mod = { .name = "PolarSSL", .init = polarssl_mod_init, .verify = polarssl_mod_verify };