Commit 84f95bed authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #315 from jcastillo-arm/jc/tbb_tmp9

Authentication Framework
parents dba12894 d337aaaf
......@@ -73,9 +73,9 @@ DISABLE_PEDANTIC := 0
# Flags to generate the Chain of Trust
GENERATE_COT := 0
CREATE_KEYS := 1
SAVE_KEYS := 0
# Flags to build TF with Trusted Boot support
TRUSTED_BOARD_BOOT := 0
AUTH_MOD := none
# By default, consider that the platform's reset address is not programmable.
# The platform Makefile is free to override this value.
PROGRAMMABLE_RESET_ADDRESS := 0
......@@ -214,6 +214,7 @@ INCLUDES += -Iinclude/bl31 \
-Iinclude/common \
-Iinclude/drivers \
-Iinclude/drivers/arm \
-Iinclude/drivers/auth \
-Iinclude/drivers/io \
-Iinclude/drivers/ti/uart \
-Iinclude/lib \
......@@ -270,6 +271,7 @@ $(eval $(call add_define,USE_COHERENT_MEM))
# Process Generate CoT flags
$(eval $(call assert_boolean,GENERATE_COT))
$(eval $(call assert_boolean,CREATE_KEYS))
$(eval $(call assert_boolean,SAVE_KEYS))
# Process TRUSTED_BOARD_BOOT flag
$(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
......@@ -327,28 +329,15 @@ ifneq (${GENERATE_COT},0)
ifneq (${CREATE_KEYS},0)
$(eval CRT_ARGS += -n)
ifneq (${SAVE_KEYS},0)
$(eval CRT_ARGS += -k)
endif
endif
$(eval CRT_ARGS += $(if ${ROT_KEY}, --rot-key ${ROT_KEY}))
$(eval CRT_ARGS += $(if ${TRUSTED_WORLD_KEY}, --trusted-world-key ${TRUSTED_WORLD_KEY}))
$(eval CRT_ARGS += $(if ${NON_TRUSTED_WORLD_KEY}, --non-trusted-world-key ${NON_TRUSTED_WORLD_KEY}))
$(eval CRT_ARGS += --trusted-key-cert ${TRUSTED_KEY_CERT})
endif
# Check Trusted Board Boot options
ifneq (${TRUSTED_BOARD_BOOT},0)
ifeq (${AUTH_MOD},none)
$(error Error: When TRUSTED_BOARD_BOOT=1, AUTH_MOD has to be the name of a valid authentication module)
else
# We expect to locate an *.mk file under the specified AUTH_MOD directory
AUTH_MAKE := $(shell m="common/auth/${AUTH_MOD}/${AUTH_MOD}.mk"; [ -f "$$m" ] && echo "$$m")
ifeq (${AUTH_MAKE},)
$(error Error: No common/auth/${AUTH_MOD}/${AUTH_MOD}.mk located)
endif
$(info Including ${AUTH_MAKE})
include ${AUTH_MAKE}
endif
BL_COMMON_SOURCES += common/auth.c
$(eval CRT_ARGS += $(if ${KEY_ALG}, --key-alg ${KEY_ALG}))
endif
# Check if -pedantic option should be used
......@@ -514,7 +503,6 @@ $(eval FIP_ARGS += $(if $4,--bl$(1)-cert $(BUILD_PLAT)/bl$(1).crt))
$(eval FIP_ARGS += $(if $4,$(if $5,--bl$(1)-key-cert $(BUILD_PLAT)/bl$(1)_key.crt)))
$(eval CRT_DEPS += $(if $4,$(2),))
$(eval CRT_DEPS += $(if $4,$(if $6,$(6),)))
$(eval CRT_ARGS += $(if $4,--bl$(1) $(2)))
$(eval CRT_ARGS += $(if $4,$(if $6,--bl$(1)-key $(6))))
$(eval CRT_ARGS += $(if $4,--bl$(1)-cert $(BUILD_PLAT)/bl$(1).crt))
......
......@@ -51,6 +51,12 @@ SECTIONS
*(.text*)
*(.rodata*)
/* Ensure 8-byte alignment for descriptors and ensure inclusion */
. = ALIGN(8);
__PARSER_LIB_DESCS_START__ = .;
KEEP(*(.img_parser_lib_descs))
__PARSER_LIB_DESCS_END__ = .;
/*
* Ensure 8-byte alignment for cpu_ops so that its fields are also
* aligned. Also ensure cpu_ops inclusion.
......
......@@ -31,7 +31,7 @@
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <auth.h>
#include <auth_mod.h>
#include <bl_common.h>
#include <debug.h>
#include <platform.h>
......@@ -157,40 +157,20 @@ void bl1_main(void)
/* Find out how much free trusted ram remains after BL1 load */
bl1_tzram_layout = bl1_plat_sec_mem_layout();
INFO("BL1: Loading BL2\n");
#if TRUSTED_BOARD_BOOT
/* Initialize authentication module */
auth_init();
/*
* Load the BL2 certificate into the BL2 region. This region will be
* overwritten by the image, so the authentication module is responsible
* for storing the relevant data from the certificate (keys, hashes,
* etc.) so it can be used later.
*/
err = load_image(bl1_tzram_layout,
BL2_CERT_NAME,
BL2_BASE,
&bl2_image_info,
NULL);
if (err) {
ERROR("Failed to load BL2 certificate.\n");
panic();
}
err = auth_verify_obj(AUTH_BL2_IMG_CERT, bl2_image_info.image_base,
bl2_image_info.image_size);
if (err) {
ERROR("Failed to validate BL2 certificate.\n");
panic();
}
auth_mod_init();
#endif /* TRUSTED_BOARD_BOOT */
/* Load the BL2 image */
err = load_image(bl1_tzram_layout,
BL2_IMAGE_NAME,
err = load_auth_image(bl1_tzram_layout,
BL2_IMAGE_ID,
BL2_BASE,
&bl2_image_info,
&bl2_ep);
if (err) {
/*
* TODO: print failure to load BL2 but also add a tzwdog timer
......@@ -200,19 +180,6 @@ void bl1_main(void)
panic();
}
#if TRUSTED_BOARD_BOOT
err = auth_verify_obj(AUTH_BL2_IMG, bl2_image_info.image_base,
bl2_image_info.image_size);
if (err) {
ERROR("Failed to validate BL2 image.\n");
panic();
}
/* After working with data, invalidate the data cache */
inv_dcache_range(bl2_image_info.image_base,
(size_t)bl2_image_info.image_size);
#endif /* TRUSTED_BOARD_BOOT */
/*
* Create a new layout of memory for BL2 as seen by BL1 i.e.
* tell it the amount of total and free memory available.
......
......@@ -50,6 +50,13 @@ SECTIONS
*bl2_entrypoint.o(.text*)
*(.text*)
*(.rodata*)
/* Ensure 8-byte alignment for descriptors and ensure inclusion */
. = ALIGN(8);
__PARSER_LIB_DESCS_START__ = .;
KEEP(*(.img_parser_lib_descs))
__PARSER_LIB_DESCS_END__ = .;
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
......
......@@ -31,149 +31,14 @@
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <auth.h>
#include <auth_mod.h>
#include <bl_common.h>
#include <debug.h>
#include <platform.h>
#include <platform_def.h>
#include <stdint.h>
#include "bl2_private.h"
#if TRUSTED_BOARD_BOOT
#ifdef BL32_BASE
static int bl32_cert_error;
#endif
/*
* Load and authenticate the key and content certificates for a BL3-x image
*
* Parameters:
* key_cert_blob: key certificate blob id (see auth.h)
* key_cert_name: key certificate filename
* cont_cert_blob: content certificate blob id (see auth.h)
* cont_cert_name: content certificate filename
* mem_layout: Trusted SRAM memory layout
* load_addr: load the certificates at this address
*
* Return: 0 = success, Otherwise = error
*/
static int load_cert_bl3x(int key_cert_blob, const char *key_cert_name,
int cont_cert_blob, const char *cont_cert_name,
meminfo_t *mem_layout, uint64_t load_addr)
{
image_info_t image_info;
int err;
/* Load Key certificate */
image_info.h.version = VERSION_1;
err = load_image(mem_layout, key_cert_name, load_addr, &image_info, NULL);
if (err) {
ERROR("Cannot load %s.\n", key_cert_name);
return err;
}
err = auth_verify_obj(key_cert_blob, image_info.image_base,
image_info.image_size);
if (err) {
ERROR("Invalid key certificate %s.\n", key_cert_name);
return err;
}
/* Load Content certificate */
image_info.h.version = VERSION_1;
err = load_image(mem_layout, cont_cert_name, load_addr, &image_info, NULL);
if (err) {
ERROR("Cannot load %s.\n", cont_cert_name);
return err;
}
err = auth_verify_obj(cont_cert_blob, image_info.image_base,
image_info.image_size);
if (err) {
ERROR("Invalid content certificate %s.\n", cont_cert_name);
return err;
}
return 0;
}
/*
* Load and authenticate the Trusted Key certificate the key and content
* certificates for each of the BL3-x images.
*
* Return: 0 = success, Otherwise = error
*/
static int load_certs(void)
{
const uint64_t load_addr = BL31_BASE;
image_info_t image_info;
meminfo_t *mem_layout;
int err;
/* Find out how much free trusted ram remains after BL2 load */
mem_layout = bl2_plat_sec_mem_layout();
/* Load the Trusted Key certificate in the BL31 region */
image_info.h.version = VERSION_1;
err = load_image(mem_layout, TRUSTED_KEY_CERT_NAME, load_addr,
&image_info, NULL);
if (err) {
ERROR("Failed to load Trusted Key certificate.\n");
return err;
}
/* Validate the certificate */
err = auth_verify_obj(AUTH_TRUSTED_KEY_CERT, image_info.image_base,
image_info.image_size);
if (err) {
ERROR("Invalid Trusted Key certificate.\n");
return err;
}
/* Load and validate Key and Content certificates for BL3-x images */
#ifdef BL30_BASE
err = load_cert_bl3x(AUTH_BL30_KEY_CERT, BL30_KEY_CERT_NAME,
AUTH_BL30_IMG_CERT, BL30_CERT_NAME,
mem_layout, load_addr);
if (err) {
ERROR("Failed to verify BL3-0 authenticity\n");
return err;
}
#endif /* BL30_BASE */
err = load_cert_bl3x(AUTH_BL31_KEY_CERT, BL31_KEY_CERT_NAME,
AUTH_BL31_IMG_CERT, BL31_CERT_NAME,
mem_layout, load_addr);
if (err) {
ERROR("Failed to verify BL3-1 authenticity\n");
return err;
}
#ifdef BL32_BASE
/* BL3-2 image is optional, but keep the return value in case the
* image is present but the certificate is missing */
err = load_cert_bl3x(AUTH_BL32_KEY_CERT, BL32_KEY_CERT_NAME,
AUTH_BL32_IMG_CERT, BL32_CERT_NAME,
mem_layout, load_addr);
if (err) {
WARN("Failed to verify BL3-2 authenticity\n");
}
bl32_cert_error = err;
#endif /* BL32_BASE */
err = load_cert_bl3x(AUTH_BL33_KEY_CERT, BL33_KEY_CERT_NAME,
AUTH_BL33_IMG_CERT, BL33_CERT_NAME,
mem_layout, load_addr);
if (err) {
ERROR("Failed to verify BL3-3 authenticity\n");
return err;
}
return 0;
}
#endif /* TRUSTED_BOARD_BOOT */
/*******************************************************************************
* Load the BL3-0 image if there's one.
* If a platform does not want to attempt to load BL3-0 image it must leave
......@@ -199,34 +64,18 @@ static int load_bl30(void)
INFO("BL2: Loading BL3-0\n");
bl2_plat_get_bl30_meminfo(&bl30_mem_info);
bl30_image_info.h.version = VERSION_1;
e = load_image(&bl30_mem_info,
BL30_IMAGE_NAME,
e = load_auth_image(&bl30_mem_info,
BL30_IMAGE_ID,
BL30_BASE,
&bl30_image_info,
NULL);
if (e)
return e;
#if TRUSTED_BOARD_BOOT
e = auth_verify_obj(AUTH_BL30_IMG,
bl30_image_info.image_base,
bl30_image_info.image_size);
if (e) {
ERROR("Failed to authenticate BL3-0 image.\n");
return e;
}
/* After working with data, invalidate the data cache */
inv_dcache_range(bl30_image_info.image_base,
(size_t)bl30_image_info.image_size);
#endif /* TRUSTED_BOARD_BOOT */
if (e == 0) {
/* The subsequent handling of BL3-0 is platform specific */
e = bl2_plat_handle_bl30(&bl30_image_info);
if (e) {
ERROR("Failure in platform-specific handling of BL3-0 image.\n");
return e;
}
}
#endif /* BL30_BASE */
......@@ -256,30 +105,16 @@ static int load_bl31(bl31_params_t *bl2_to_bl31_params,
bl31_ep_info->args.arg0 = (unsigned long)bl2_to_bl31_params;
/* Load the BL3-1 image */
e = load_image(bl2_tzram_layout,
BL31_IMAGE_NAME,
e = load_auth_image(bl2_tzram_layout,
BL31_IMAGE_ID,
BL31_BASE,
bl2_to_bl31_params->bl31_image_info,
bl31_ep_info);
if (e)
return e;
#if TRUSTED_BOARD_BOOT
e = auth_verify_obj(AUTH_BL31_IMG,
bl2_to_bl31_params->bl31_image_info->image_base,
bl2_to_bl31_params->bl31_image_info->image_size);
if (e) {
ERROR("Failed to authenticate BL3-1 image.\n");
return e;
}
/* After working with data, invalidate the data cache */
inv_dcache_range(bl2_to_bl31_params->bl31_image_info->image_base,
(size_t)bl2_to_bl31_params->bl31_image_info->image_size);
#endif /* TRUSTED_BOARD_BOOT */
if (e == 0) {
bl2_plat_set_bl31_ep_info(bl2_to_bl31_params->bl31_image_info,
bl31_ep_info);
}
return e;
}
......@@ -308,37 +143,17 @@ static int load_bl32(bl31_params_t *bl2_to_bl31_params)
* completely different memory.
*/
bl2_plat_get_bl32_meminfo(&bl32_mem_info);
e = load_image(&bl32_mem_info,
BL32_IMAGE_NAME,
e = load_auth_image(&bl32_mem_info,
BL32_IMAGE_ID,
BL32_BASE,
bl2_to_bl31_params->bl32_image_info,
bl2_to_bl31_params->bl32_ep_info);
if (e)
return e;
#if TRUSTED_BOARD_BOOT
/* Image is present. Check if there is a valid certificate */
if (bl32_cert_error) {
ERROR("Failed to authenticate BL3-2 certificates.\n");
return bl32_cert_error;
}
e = auth_verify_obj(AUTH_BL32_IMG,
bl2_to_bl31_params->bl32_image_info->image_base,
bl2_to_bl31_params->bl32_image_info->image_size);
if (e) {
ERROR("Failed to authenticate BL3-2 image.\n");
return e;
}
/* After working with data, invalidate the data cache */
inv_dcache_range(bl2_to_bl31_params->bl32_image_info->image_base,
(size_t)bl2_to_bl31_params->bl32_image_info->image_size);
#endif /* TRUSTED_BOARD_BOOT */
if (e == 0) {
bl2_plat_set_bl32_ep_info(
bl2_to_bl31_params->bl32_image_info,
bl2_to_bl31_params->bl32_ep_info);
}
#endif /* BL32_BASE */
return e;
......@@ -361,30 +176,16 @@ static int load_bl33(bl31_params_t *bl2_to_bl31_params)
bl2_plat_get_bl33_meminfo(&bl33_mem_info);
/* Load the BL3-3 image in non-secure memory provided by the platform */
e = load_image(&bl33_mem_info,
BL33_IMAGE_NAME,
e = load_auth_image(&bl33_mem_info,
BL33_IMAGE_ID,
plat_get_ns_image_entrypoint(),
bl2_to_bl31_params->bl33_image_info,
bl2_to_bl31_params->bl33_ep_info);
if (e)
return e;
#if TRUSTED_BOARD_BOOT
e = auth_verify_obj(AUTH_BL33_IMG,
bl2_to_bl31_params->bl33_image_info->image_base,
bl2_to_bl31_params->bl33_image_info->image_size);
if (e) {
ERROR("Failed to authenticate BL3-3 image.\n");
return e;
}
/* After working with data, invalidate the data cache */
inv_dcache_range(bl2_to_bl31_params->bl33_image_info->image_base,
(size_t)bl2_to_bl31_params->bl33_image_info->image_size);
#endif /* TRUSTED_BOARD_BOOT */
if (e == 0) {
bl2_plat_set_bl33_ep_info(bl2_to_bl31_params->bl33_image_info,
bl2_to_bl31_params->bl33_ep_info);
}
return e;
}
......@@ -408,14 +209,7 @@ void bl2_main(void)
#if TRUSTED_BOARD_BOOT
/* Initialize authentication module */
auth_init();
/* Validate the certificates involved in the Chain of Trust */
e = load_certs();
if (e) {
ERROR("Chain of Trust invalid. Aborting...\n");
panic();
}
auth_mod_init();
#endif /* TRUSTED_BOARD_BOOT */
/*
......
/*
* 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 <stddef.h>
#include <assert.h>
#include <auth.h>
#include <debug.h>
#include <platform.h>
#include <platform_def.h>
#include <platform_oid.h>
#include <polarssl/memory_buffer_alloc.h>
#include <polarssl/oid.h>
#include <polarssl/platform.h>
#include <polarssl/sha256.h>
#include <polarssl/x509_crt.h>
/*
* 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
};
......@@ -31,6 +31,7 @@
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <auth_mod.h>
#include <bl_common.h>
#include <debug.h>
#include <errno.h>
......@@ -156,7 +157,7 @@ static void dump_load_info(unsigned long image_load_addr,
}
/* Generic function to return the size of an image */
unsigned long image_size(const char *image_name)
unsigned long image_size(unsigned int image_id)
{
uintptr_t dev_handle;
uintptr_t image_handle;
......@@ -164,29 +165,27 @@ unsigned long image_size(const char *image_name)
size_t image_size = 0;
int io_result = IO_FAIL;
assert(image_name != NULL);
/* Obtain a reference to the image by querying the platform layer */
io_result = plat_get_image_source(image_name, &dev_handle, &image_spec);
io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
if (io_result != IO_SUCCESS) {
WARN("Failed to obtain reference to image '%s' (%i)\n",
image_name, io_result);
WARN("Failed to obtain reference to image id=%u (%i)\n",
image_id, io_result);
return 0;
}
/* Attempt to access the image */
io_result = io_open(dev_handle, image_spec, &image_handle);
if (io_result != IO_SUCCESS) {
WARN("Failed to access image '%s' (%i)\n",
image_name, io_result);
WARN("Failed to access image id=%u (%i)\n",
image_id, io_result);
return 0;
}
/* Find the size of the image */
io_result = io_size(image_handle, &image_size);
if ((io_result != IO_SUCCESS) || (image_size == 0)) {
WARN("Failed to determine the size of the image '%s' file (%i)\n",
image_name, io_result);
WARN("Failed to determine the size of the image id=%u (%i)\n",
image_id, io_result);
}
io_result = io_close(image_handle);
/* Ignore improbable/unrecoverable error in 'close' */
......@@ -210,8 +209,8 @@ unsigned long image_size(const char *image_name)
* Returns 0 on success, a negative error code otherwise.
******************************************************************************/
int load_image(meminfo_t *mem_layout,
const char *image_name,
uint64_t image_base,
unsigned int image_id,
uintptr_t image_base,
image_info_t *image_data,
entry_point_info_t *entry_point_info)
{
......@@ -223,33 +222,32 @@ int load_image(meminfo_t *mem_layout,
int io_result = IO_FAIL;
assert(mem_layout != NULL);
assert(image_name != NULL);
assert(image_data != NULL);
assert(image_data->h.version >= VERSION_1);
/* Obtain a reference to the image by querying the platform layer */
io_result = plat_get_image_source(image_name, &dev_handle, &image_spec);
io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
if (io_result != IO_SUCCESS) {
WARN("Failed to obtain reference to image '%s' (%i)\n",
image_name, io_result);
WARN("Failed to obtain reference to image id=%u (%i)\n",
image_id, io_result);
return io_result;
}
/* Attempt to access the image */
io_result = io_open(dev_handle, image_spec, &image_handle);
if (io_result != IO_SUCCESS) {
WARN("Failed to access image '%s' (%i)\n",
image_name, io_result);
WARN("Failed to access image id=%u (%i)\n",
image_id, io_result);
return io_result;
}
INFO("Loading file '%s' at address 0x%lx\n", image_name, image_base);
INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base);
/* Find the size of the image */
io_result = io_size(image_handle, &image_size);
if ((io_result != IO_SUCCESS) || (image_size == 0)) {
WARN("Failed to determine the size of the image '%s' file (%i)\n",
image_name, io_result);
WARN("Failed to determine the size of the image id=%u (%i)\n",
image_id, io_result);
goto exit;
}
......@@ -267,7 +265,7 @@ int load_image(meminfo_t *mem_layout,
/* TODO: Consider whether to try to recover/retry a partially successful read */
io_result = io_read(image_handle, image_base, image_size, &bytes_read);
if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) {
WARN("Failed to load '%s' file (%i)\n", image_name, io_result);
WARN("Failed to load image id=%u (%i)\n", image_id, io_result);
goto exit;
}
......@@ -298,7 +296,7 @@ int load_image(meminfo_t *mem_layout,
*/
flush_dcache_range(image_base, image_size);
INFO("File '%s' loaded: 0x%lx - 0x%lx\n", image_name, image_base,
INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base,
image_base + image_size);
exit:
......@@ -311,3 +309,54 @@ exit:
return io_result;
}
/*******************************************************************************
* Generic function to load and authenticate an image. The image is actually
* loaded by calling the 'load_image()' function. In addition, this function
* uses recursion to authenticate the parent images up to the root of trust.
******************************************************************************/
int load_auth_image(meminfo_t *mem_layout,
unsigned int image_id,
uintptr_t image_base,
image_info_t *image_data,
entry_point_info_t *entry_point_info)
{
int rc;
#if TRUSTED_BOARD_BOOT
unsigned int parent_id;
/* Use recursion to authenticate parent images */
rc = auth_mod_get_parent_id(image_id, &parent_id);
if (rc == 0) {
rc = load_auth_image(mem_layout, parent_id, image_base,
image_data, NULL);
if (rc != IO_SUCCESS) {
return rc;
}
}
#endif /* TRUSTED_BOARD_BOOT */
/* Load the image */
rc = load_image(mem_layout, image_id, image_base, image_data,
entry_point_info);
if (rc != IO_SUCCESS) {
return rc;
}
#if TRUSTED_BOARD_BOOT
/* Authenticate it */
rc = auth_mod_verify_img(image_id,
(void *)image_data->image_base,
image_data->image_size);
if (rc != 0) {
return IO_FAIL;
}
/* After working with data, invalidate the data cache */
inv_dcache_range(image_data->image_base,
(size_t)image_data->image_size);
#endif /* TRUSTED_BOARD_BOOT */
return IO_SUCCESS;
}
This diff is collapsed.
......@@ -134,51 +134,6 @@ platform port to define additional platform porting constants in
Defines the character string printed by BL1 upon entry into the `bl1_main()`
function.
* **#define : BL2_IMAGE_NAME**
Name of the BL2 binary image on the host file-system. This name is used by
BL1 to load BL2 into secure memory from non-volatile storage.
* **#define : BL31_IMAGE_NAME**
Name of the BL3-1 binary image on the host file-system. This name is used by
BL2 to load BL3-1 into secure memory from platform storage.
* **#define : BL33_IMAGE_NAME**
Name of the BL3-3 binary image on the host file-system. This name is used by
BL2 to load BL3-3 into non-secure memory from platform storage.
* **#define : BL2_CERT_NAME**
Name of the BL2 content certificate on the host file-system (mandatory when
Trusted Board Boot is enabled).
* **#define : TRUSTED_KEY_CERT_NAME**
Name of the Trusted Key certificate on the host file-system (mandatory when
Trusted Board Boot is enabled).
* **#define : BL31_KEY_CERT_NAME**
Name of the BL3-1 Key certificate on the host file-system (mandatory when
Trusted Board Boot is enabled).
* **#define : BL31_CERT_NAME**
Name of the BL3-1 Content certificate on the host file-system (mandatory
when Trusted Board Boot is enabled).
* **#define : BL33_KEY_CERT_NAME**
Name of the BL3-3 Key certificate on the host file-system (mandatory when
Trusted Board Boot is enabled).
* **#define : BL33_CERT_NAME**
Name of the BL3-3 Content certificate on the host file-system (mandatory
when Trusted Board Boot is enabled).
* **#define : PLATFORM_CORE_COUNT**
Defines the total number of CPUs implemented by the platform across all
......@@ -243,42 +198,93 @@ platform port to define additional platform porting constants in
Defines the base address in non-secure DRAM where BL2 loads the BL3-3 binary
image. Must be aligned on a page-size boundary.
For every image, the platform must define individual identifiers that will be
used by BL1 or BL2 to load the corresponding image into memory from non-volatile
storage. For the sake of performance, integer numbers will be used as
identifiers. The platform will use those identifiers to return the relevant
information about the image to be loaded (file handler, load address,
authentication information, etc.). The following image identifiers are
mandatory:
* **#define : BL2_IMAGE_ID**
BL2 image identifier, used by BL1 to load BL2.
* **#define : BL31_IMAGE_ID**
BL3-1 image identifier, used by BL2 to load BL3-1.
* **#define : BL33_IMAGE_ID**
BL3-3 image identifier, used by BL2 to load BL3-3.
If Trusted Board Boot is enabled, the following certificate identifiers must
also be defined:
* **#define : BL2_CERT_ID**
BL2 content certificate identifier, used by BL1 to load the BL2 content
certificate.
* **#define : TRUSTED_KEY_CERT_ID**
Trusted key certificate identifier, used by BL2 to load the trusted key
certificate.
* **#define : BL31_KEY_CERT_ID**
BL3-1 key certificate identifier, used by BL2 to load the BL3-1 key
certificate.
* **#define : BL31_CERT_ID**
BL3-1 content certificate identifier, used by BL2 to load the BL3-1 content
certificate.
* **#define : BL33_KEY_CERT_ID**
BL3-3 key certificate identifier, used by BL2 to load the BL3-3 key
certificate.
* **#define : BL33_CERT_ID**
BL3-3 content certificate identifier, used by BL2 to load the BL3-3 content
certificate.
If a BL3-0 image is supported by the platform, the following constants must
also be defined:
* **#define : BL30_IMAGE_NAME**
* **#define : BL30_IMAGE_ID**
Name of the BL3-0 binary image on the host file-system. This name is used by
BL2 to load BL3-0 into secure memory from platform storage before being
transfered to the SCP.
BL3-0 image identifier, used by BL2 to load BL3-0 into secure memory from
platform storage before being transfered to the SCP.
* **#define : BL30_KEY_CERT_NAME**
* **#define : BL30_KEY_CERT_ID**
Name of the BL3-0 Key certificate on the host file-system (mandatory when
Trusted Board Boot is enabled).
BL3-0 key certificate identifier, used by BL2 to load the BL3-0 key
certificate (mandatory when Trusted Board Boot is enabled).
* **#define : BL30_CERT_NAME**
* **#define : BL30_CERT_ID**
Name of the BL3-0 Content certificate on the host file-system (mandatory
when Trusted Board Boot is enabled).
BL3-0 content certificate identifier, used by BL2 to load the BL3-0 content
certificate (mandatory when Trusted Board Boot is enabled).
If a BL3-2 image is supported by the platform, the following constants must
also be defined:
* **#define : BL32_IMAGE_NAME**
* **#define : BL32_IMAGE_ID**
Name of the BL3-2 binary image on the host file-system. This name is used by
BL2 to load BL3-2 into secure memory from platform storage.
BL3-2 image identifier, used by BL2 to load BL3-2.
* **#define : BL32_KEY_CERT_NAME**
* **#define : BL32_KEY_CERT_ID**
Name of the BL3-2 Key certificate on the host file-system (mandatory when
Trusted Board Boot is enabled).
BL3-2 key certificate identifier, used by BL2 to load the BL3-2 key
certificate (mandatory when Trusted Board Boot is enabled).
* **#define : BL32_CERT_NAME**
* **#define : BL32_CERT_ID**
Name of the BL3-2 Content certificate on the host file-system (mandatory
when Trusted Board Boot is enabled).
BL3-2 content certificate identifier, used by BL2 to load the BL3-2 content
certificate (mandatory when Trusted Board Boot is enabled).
* **#define : BL32_BASE**
......@@ -466,15 +472,36 @@ The ARM FVP port uses this function to initialize the mailbox memory used for
providing the warm-boot entry-point addresses.
### Function: plat_match_rotpk()
### Function: plat_get_rotpk_info()
Argument : const unsigned char *, unsigned int
Argument : void *, void **, unsigned int *, unsigned int *
Return : int
This function is mandatory when Trusted Board Boot is enabled. It receives a
pointer to a buffer containing a signing key and its size as parameters and
returns 0 (success) if that key matches the ROT (Root Of Trust) key stored in
the platform. Any other return value means a mismatch.
This function is mandatory when Trusted Board Boot is enabled. It returns a
pointer to the ROTPK stored in the platform (or a hash of it) and its length.
The ROTPK must be encoded in DER format according to the following ASN.1
structure:
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
In case the function returns a hash of the key:
DigestInfo ::= SEQUENCE {
digestAlgorithm AlgorithmIdentifier,
digest OCTET STRING
}
The function returns 0 on success. Any other value means the ROTPK could not be
retrieved from the platform. The function also reports extra information related
to the ROTPK in the flags parameter.
......@@ -1528,10 +1555,11 @@ provide at least one driver for a device capable of supporting generic
operations such as loading a bootloader image.
The current implementation only allows for known images to be loaded by the
firmware. These images are specified by using their names, as defined in
[include/plat/common/platform.h]. The platform layer (`plat_get_image_source()`)
then returns a reference to a device and a driver-specific `spec` which will be
understood by the driver to allow access to the image data.
firmware. These images are specified by using their identifiers, as defined in
[include/plat/common/platform_def.h] (or a separate header file included from
there). The platform layer (`plat_get_image_source()`) then returns a reference
to a device and a driver-specific `spec` which will be understood by the driver
to allow access to the image data.
The layer is designed in such a way that is it possible to chain drivers with
other drivers. For example, file-system drivers may be implemented on top of
......
......@@ -6,7 +6,7 @@ Contents :
1. [Introduction](#1--introduction)
2. [Chain of Trust](#2--chain-of-trust)
3. [Trusted Board Boot Sequence](#3--trusted-board-boot-sequence)
4. [Authentication Module](#4--authentication-module)
4. [Authentication Framework](#4--authentication-framework)
5. [Certificate Generation Tool](#5--certificate-generation-tool)
......@@ -209,27 +209,15 @@ The mechanism used for generating the FIP and the Authentication module are
described in the following sections.
4. Authentication Module
-------------------------
4. Authentication Framework
----------------------------
The authentication module implements the required support to authenticate the
corresponding certificates or images at each step in the Trusted Board Boot
sequence. The module relies on the PolarSSL library (v1.3.9) to perform the
following operations:
The authentication framework included in the Trusted Firmware provides support
to implement the desired trusted boot sequence. ARM platforms use this framework
to implement the boot requirements specified in the TBBR-client document.
* Parsing X.509 certificates and verifying them using SHA-256 with RSA
Encryption.
* Extracting public keys and hashes from the certificates.
* Generating hashes (SHA-256) of boot loader images
At each step, the module is responsible for allocating memory to store the
public keys or hashes that will be used in later steps. The step identifier is
used to determine what information must be saved, according to the CoT model
detailed in the previous sections.
The authentication module resides in the `common/auth/polarssl` directory.
Instructions for including the necessary modules of the PolarSSL SSL library and
building the authentication module can be found in the [User Guide].
More information about the authentication framework can be found in the
[Auth Framework] document.
5. Certificate Generation Tool
......@@ -257,4 +245,5 @@ _Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
[X.509 v3]: http://www.ietf.org/rfc/rfc5280.txt
[X.690]: http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
[Auth Framework]: auth-framework.md
[User Guide]: user-guide.md
......@@ -265,16 +265,8 @@ performed.
* `TRUSTED_BOARD_BOOT`: Boolean flag to include support for the Trusted Board
Boot feature. When set to '1', BL1 and BL2 images include support to load
and verify the certificates and images in a FIP. The default value is '0'.
A successful build, when `TRUSTED_BOARD_BOOT=1`, depends upon the correct
initialization of the `AUTH_MOD` option. Generation and inclusion of
certificates in the FIP depends upon the value of the `GENERATE_COT` option.
* `AUTH_MOD`: This option is used when `TRUSTED_BOARD_BOOT=1`. It specifies
the name of the authentication module that will be used in the Trusted Board
Boot sequence. The module must be located in `common/auth/<module name>`
directory. The directory must contain a makefile `<module name>.mk` which
will be used to build the module. More information can be found in
[Trusted Board Boot]. The default module name is 'none'.
Generation and inclusion of certificates in the FIP depends upon the value
of the `GENERATE_COT` option.
* `GENERATE_COT`: Boolean flag used to build and execute the `cert_create`
tool to create certificates as per the Chain of Trust described in
......@@ -297,28 +289,40 @@ performed.
certificate generation tool to create new keys in case no valid keys are
present or specified. Allowed options are '0' or '1'. Default is '1'.
* `SAVE_KEYS`: This option is used when `GENERATE_COT=1`. It tells the
certificate generation tool to save the keys used to establish the Chain of
Trust. Allowed options are '0' or '1'. Default is '0' (do not save).
Note: This option depends on 'CREATE_KEYS' to be enabled. If the keys
already exist in disk, they will be overwritten without further notice.
* `ROT_KEY`: This option is used when `GENERATE_COT=1`. It specifies the
file that contains the ROT private key in PEM format.
file that contains the ROT private key in PEM format. If `SAVE_KEYS=1`, this
file name will be used to save the key.
* `TRUSTED_WORLD_KEY`: This option is used when `GENERATE_COT=1`. It
specifies the file that contains the Trusted World private key in PEM
format.
format. If `SAVE_KEYS=1`, this file name will be used to save the key.
* `NON_TRUSTED_WORLD_KEY`: This option is used when `GENERATE_COT=1`. It
specifies the file that contains the Non-Trusted World private key in PEM
format.
format. If `SAVE_KEYS=1`, this file name will be used to save the key.
* `BL30_KEY`: This option is used when `GENERATE_COT=1`. It specifies the
file that contains the BL3-0 private key in PEM format.
file that contains the BL3-0 private key in PEM format. If `SAVE_KEYS=1`,
this file name will be used to save the key.
* `BL31_KEY`: This option is used when `GENERATE_COT=1`. It specifies the
file that contains the BL3-1 private key in PEM format.
file that contains the BL3-1 private key in PEM format. If `SAVE_KEYS=1`,
this file name will be used to save the key.
* `BL32_KEY`: This option is used when `GENERATE_COT=1`. It specifies the
file that contains the BL3-2 private key in PEM format.
file that contains the BL3-2 private key in PEM format. If `SAVE_KEYS=1`,
this file name will be used to save the key.
* `BL33_KEY`: This option is used when `GENERATE_COT=1`. It specifies the
file that contains the BL3-3 private key in PEM format.
file that contains the BL3-3 private key in PEM format. If `SAVE_KEYS=1`,
this file name will be used to save the key.
* `PROGRAMMABLE_RESET_ADDRESS`: This option indicates whether the reset
vector address can be programmed or is fixed on the platform. It can take
......@@ -334,6 +338,23 @@ performed.
For a better understanding of these options, the ARM development platform memory
map is explained in the [Firmware Design].
* `ARM_ROTPK_LOCATION`: used when `TRUSTED_BOARD_BOOT=1`. It specifies the
location of the ROTPK hash returned by the function `plat_get_rotpk_info()`
for ARM platforms. Depending on the selected option, the proper private key
must be specified using the `ROT_KEY` option when building the Trusted
Firmware. This private key will be used by the certificate generation tool
to sign the BL2 and Trusted Key certificates. Available options for
`ARM_ROTPK_LOCATION` are:
- `regs` : return the ROTPK hash stored in the Trusted root-key storage
registers. The private key corresponding to this ROTPK hash is not
currently available.
- `devel_rsa` : return a development public key hash embedded in the BL1
and BL2 binaries. This hash has been obtained from the RSA public key
`arm_rotpk_rsa.der`, located in `plat/arm/board/common/rotpk`. To use
this option, `arm_rotprivk_rsa.pem` must be specified as `ROT_KEY` when
creating the certificates.
#### ARM CSS platform specific build options
* `CSS_DETECT_PRE_1_7_0_SCP`: Boolean flag to detect SCP version
......@@ -486,25 +507,58 @@ The Trusted Board Boot feature is described in [Trusted Board Boot]. The
following steps should be followed to build a FIP image with support for this
feature.
1. Fulfill the dependencies of the `polarssl` authentication module by checking
out the tag `polarssl-1.3.9` from the [PolarSSL Repository].
1. Fulfill the dependencies of the `mbedtls` cryptographic and image parser
modules by checking out the tag `mbedtls-1.3.11` from the
[mbedTLS Repository].
The `common/auth/polarssl/polarssl.mk` contains the list of PolarSSL source
files the module depends upon. `common/auth/polarssl/polarssl_config.h`
contains the configuration options required to build the PolarSSL sources.
The `drivers/auth/mbedtls/mbedtls_*.mk` files contain the list of mbedTLS
source files the modules depend upon.
`include/drivers/auth/mbedtls/mbedtls_config.h` contains the configuration
options required to build the mbedTLS sources.
Note that the PolarSSL SSL library is licensed under the GNU GPL version 2
or later license. Using PolarSSL source code will affect the licensing of
Note that the mbedTLS library is licensed under the GNU GPL version 2
or later license. Using mbedTLS source code will affect the licensing of
Trusted Firmware binaries that are built using this library.
2. Ensure that the following command line variables are set while invoking
`make` to build Trusted Firmware:
* `POLARSSL_DIR=<path of the directory containing PolarSSL sources>`
* `AUTH_MOD=polarssl`
* `MBEDTLS_DIR=<path of the directory containing mbedTLS sources>`
* `TRUSTED_BOARD_BOOT=1`
* `GENERATE_COT=1`
In the case of ARM platforms, the location of the ROTPK hash must also be
specified at build time. Two locations are currently supported (see
`ARM_ROTPK_LOCATION` build option):
* `ARM_ROTPK_LOCATION=regs`: the ROTPK hash is obtained from the Trusted
root-key storage registers present in the platform. On Juno, this
registers are read-only. On FVP Base and Cortex models, the registers
are read-only, but the value can be specified using the command line
option `bp.trusted_key_storage.public_key` when launching the model.
On both Juno and FVP models, the default value corresponds to an
ECDSA-SECP256R1 public key hash, whose private part is not currently
available.
* `ARM_ROTPK_LOCATION=devel_rsa`: use the ROTPK hash that is hardcoded
in the ARM platform port. The private/public RSA key pair may be
found in `plat/arm/board/common/rotpk`.
Example of command line using RSA development keys:
CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \
BL33=<path-to>/<bl33_image> \
MBEDTLS_DIR=<path of the directory containing mbedTLS sources> \
make PLAT=<platform> TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \
ARM_ROTPK_LOCATION=devel_rsa \
ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \
all fip
The result of this build will be the bl1.bin and the fip.bin binaries, with
the difference that the FIP will include the certificates corresponding to
the Chain of Trust described in the TBBR-client document. These certificates
can also be found in the output build directory.
### Checking source code style
......@@ -1124,5 +1178,5 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._
[Linaro Toolchain]: http://releases.linaro.org/14.07/components/toolchain/binaries/
[EDK2]: http://github.com/tianocore/edk2
[DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php
[Polarssl Repository]: https://github.com/polarssl/polarssl.git
[mbedTLS Repository]: https://github.com/ARMmbed/mbedtls.git
[Trusted Board Boot]: trusted-board-boot.md
/*
* 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.
*/
#include <assert.h>
#include <auth_common.h>
#include <auth_mod.h>
#include <cot_def.h>
#include <crypto_mod.h>
#include <debug.h>
#include <img_parser_mod.h>
#include <platform.h>
#include <platform_def.h>
#include <stdint.h>
#include <string.h>
#define return_if_error(rc) \
do { \
if (rc != 0) { \
return rc; \
} \
} while (0)
/* Pointer to CoT */
extern const auth_img_desc_t *const cot_desc_ptr;
extern unsigned int auth_img_flags[];
static int cmp_auth_param_type_desc(const auth_param_type_desc_t *a,
const auth_param_type_desc_t *b)
{
if ((a->type == b->type) && (a->cookie == b->cookie)) {
return 0;
}
return 1;
}
/*
* This function obtains the requested authentication parameter data from the
* information extracted from the parent image after its authentication.
*/
static int auth_get_param(const auth_param_type_desc_t *param_type_desc,
const auth_img_desc_t *img_desc,
void **param, unsigned int *len)
{
int i;
for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) {
if (0 == cmp_auth_param_type_desc(param_type_desc,
img_desc->authenticated_data[i].type_desc)) {
*param = img_desc->authenticated_data[i].data.ptr;
*len = img_desc->authenticated_data[i].data.len;
return 0;
}
}
return 1;
}
/*
* Authenticate an image by matching the data hash
*
* This function implements 'AUTH_METHOD_HASH'. To authenticate an image using
* this method, the image must contain:
*
* - The data to calculate the hash from
*
* The parent image must contain:
*
* - The hash to be matched with (including hash algorithm)
*
* For a successful authentication, both hashes must match. The function calls
* the crypto-module to check this matching.
*
* Parameters:
* param: parameters to perform the hash authentication
* img_desc: pointer to image descriptor so we can know the image type
* and parent image
* img: pointer to image in memory
* img_len: length of image (in bytes)
*
* Return:
* 0 = success, Otherwise = error
*/
static int auth_hash(const auth_method_param_hash_t *param,
const auth_img_desc_t *img_desc,
void *img, unsigned int img_len)
{
void *data_ptr, *hash_der_ptr;
unsigned int data_len, hash_der_len;
int rc = 0;
/* Get the hash from the parent image. This hash will be DER encoded
* and contain the hash algorithm */
rc = auth_get_param(param->hash, img_desc->parent,
&hash_der_ptr, &hash_der_len);
return_if_error(rc);
/* Get the data to be hashed from the current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->data,
img, img_len, &data_ptr, &data_len);
return_if_error(rc);
/* Ask the crypto module to verify this hash */
rc = crypto_mod_verify_hash(data_ptr, data_len,
hash_der_ptr, hash_der_len);
return rc;
}
/*
* Authenticate by digital signature
*
* This function implements 'AUTH_METHOD_SIG'. To authenticate an image using
* this method, the image must contain:
*
* - Data to be signed
* - Signature
* - Signature algorithm
*
* We rely on the image parser module to extract this data from the image.
* The parent image must contain:
*
* - Public key (or a hash of it)
*
* If the parent image contains only a hash of the key, we will try to obtain
* the public key from the image itself (i.e. self-signed certificates). In that
* case, the signature verification is considered just an integrity check and
* the authentication is established by calculating the hash of the key and
* comparing it with the hash obtained from the parent.
*
* If the image has no parent (NULL), it means it has to be authenticated using
* the ROTPK stored in the platform. Again, this ROTPK could be the key itself
* or a hash of it.
*
* Return: 0 = success, Otherwise = error
*/
static int auth_signature(const auth_method_param_sig_t *param,
const auth_img_desc_t *img_desc,
void *img, unsigned int img_len)
{
void *data_ptr, *pk_ptr, *pk_hash_ptr, *sig_ptr, *sig_alg_ptr;
unsigned int data_len, pk_len, pk_hash_len, sig_len, sig_alg_len;
unsigned int flags = 0;
int rc = 0;
/* Get the data to be signed from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->data,
img, img_len, &data_ptr, &data_len);
return_if_error(rc);
/* Get the signature from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->sig,
img, img_len, &sig_ptr, &sig_len);
return_if_error(rc);
/* Get the signature algorithm from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->alg,
img, img_len, &sig_alg_ptr, &sig_alg_len);
return_if_error(rc);
/* Get the public key from the parent. If there is no parent (NULL),
* the certificate has been signed with the ROTPK, so we have to get
* the PK from the platform */
if (img_desc->parent) {
rc = auth_get_param(param->pk, img_desc->parent,
&pk_ptr, &pk_len);
} else {
rc = plat_get_rotpk_info(param->pk->cookie, &pk_ptr, &pk_len,
&flags);
}
return_if_error(rc);
/* If the PK is a hash of the key, retrieve the key from the image */
if (flags & ROTPK_IS_HASH) {
pk_hash_ptr = pk_ptr;
pk_hash_len = pk_len;
rc = img_parser_get_auth_param(img_desc->img_type,
param->pk, img, img_len,
&pk_ptr, &pk_len);
return_if_error(rc);
/* Ask the crypto module to verify the signature */
rc = crypto_mod_verify_signature(data_ptr, data_len,
sig_ptr, sig_len,
sig_alg_ptr, sig_alg_len,
pk_ptr, pk_len);
return_if_error(rc);
/* Ask the crypto-module to verify the key hash */
rc = crypto_mod_verify_hash(pk_ptr, pk_len,
pk_hash_ptr, pk_hash_len);
} else {
/* Ask the crypto module to verify the signature */
rc = crypto_mod_verify_signature(data_ptr, data_len,
sig_ptr, sig_len,
sig_alg_ptr, sig_alg_len,
pk_ptr, pk_len);
}
return rc;
}
/*
* Return the parent id in the output parameter '*parent_id'
*
* Return value:
* 0 = Image has parent, 1 = Image has no parent or parent is authenticated
*/
int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id)
{
const auth_img_desc_t *img_desc = NULL;
assert(parent_id != NULL);
/* Get the image descriptor */
img_desc = &cot_desc_ptr[img_id];
/* Check if the image has no parent (ROT) */
if (img_desc->parent == NULL) {
*parent_id = 0;
return 1;
}
/* Check if the parent has already been authenticated */
if (auth_img_flags[img_desc->parent->img_id] & IMG_FLAG_AUTHENTICATED) {
*parent_id = 0;
return 1;
}
*parent_id = img_desc->parent->img_id;
return 0;
}
/*
* Initialize the different modules in the authentication framework
*/
void auth_mod_init(void)
{
/* Check we have a valid CoT registered */
assert(cot_desc_ptr != NULL);
/* Crypto module */
crypto_mod_init();
/* Image parser module */
img_parser_init();
}
/*
* Authenticate a certificate/image
*
* Return: 0 = success, Otherwise = error
*/
int auth_mod_verify_img(unsigned int img_id,
void *img_ptr,
unsigned int img_len)
{
const auth_img_desc_t *img_desc = NULL;
const auth_method_desc_t *auth_method = NULL;
void *param_ptr;
unsigned int param_len;
int rc, i;
/* Get the image descriptor from the chain of trust */
img_desc = &cot_desc_ptr[img_id];
/* Ask the parser to check the image integrity */
rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len);
return_if_error(rc);
/* Authenticate the image using the methods indicated in the image
* descriptor. */
for (i = 0 ; i < AUTH_METHOD_NUM ; i++) {
auth_method = &img_desc->img_auth_methods[i];
switch (auth_method->type) {
case AUTH_METHOD_NONE:
rc = 0;
break;
case AUTH_METHOD_HASH:
rc = auth_hash(&auth_method->param.hash,
img_desc, img_ptr, img_len);
break;
case AUTH_METHOD_SIG:
rc = auth_signature(&auth_method->param.sig,
img_desc, img_ptr, img_len);
break;
default:
/* Unknown authentication method */
rc = 1;
break;
}
return_if_error(rc);
}
/* Extract the parameters indicated in the image descriptor to
* authenticate the children images. */
for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) {
if (img_desc->authenticated_data[i].type_desc == NULL) {
continue;
}
/* Get the parameter from the image parser module */
rc = img_parser_get_auth_param(img_desc->img_type,
img_desc->authenticated_data[i].type_desc,
img_ptr, img_len, &param_ptr, &param_len);
return_if_error(rc);
/* Check parameter size */
if (param_len > img_desc->authenticated_data[i].data.len) {
return 1;
}
/* Copy the parameter for later use */
memcpy((void *)img_desc->authenticated_data[i].data.ptr,
(void *)param_ptr, param_len);
}
/* Mark image as authenticated */
auth_img_flags[img_desc->img_id] |= IMG_FLAG_AUTHENTICATED;
return 0;
}
/*
* 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.
*/
#include <assert.h>
#include <crypto_mod.h>
#include <debug.h>
/* Variable exported by the crypto library through REGISTER_CRYPTO_LIB() */
extern const crypto_lib_desc_t crypto_lib_desc;
/*
* The crypto module is responsible for verifying digital signatures and hashes.
* It relies on a crypto library to perform the cryptographic operations.
*
* The crypto module itself does not impose any specific format on signatures,
* signature algorithm, keys or hashes, but most cryptographic libraries will
* take the parameters as the following DER encoded ASN.1 structures:
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING
* }
*
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*
* SignatureAlgorithm ::= AlgorithmIdentifier
*
* SignatureValue ::= BIT STRING
*/
/*
* Perform some static checking and call the library initialization function
*/
void crypto_mod_init(void)
{
assert(crypto_lib_desc.name != NULL);
assert(crypto_lib_desc.init != NULL);
assert(crypto_lib_desc.verify_signature != NULL);
assert(crypto_lib_desc.verify_hash != NULL);
/* Initialize the cryptographic library */
crypto_lib_desc.init();
INFO("Using crypto library '%s'\n", crypto_lib_desc.name);
}
/*
* Function to verify a digital signature
*
* Parameters:
*
* data_ptr, data_len: signed data
* sig_ptr, sig_len: the digital signature
* sig_alg_ptr, sig_alg_len: the digital signature algorithm
* pk_ptr, pk_len: the public key
*/
int crypto_mod_verify_signature(void *data_ptr, unsigned int data_len,
void *sig_ptr, unsigned int sig_len,
void *sig_alg_ptr, unsigned int sig_alg_len,
void *pk_ptr, unsigned int pk_len)
{
assert(data_ptr != NULL);
assert(data_len != 0);
assert(sig_ptr != NULL);
assert(sig_len != 0);
assert(sig_alg_ptr != NULL);
assert(sig_alg_len != 0);
assert(pk_ptr != NULL);
assert(pk_len != 0);
return crypto_lib_desc.verify_signature(data_ptr, data_len,
sig_ptr, sig_len,
sig_alg_ptr, sig_alg_len,
pk_ptr, pk_len);
}
/*
* Verify a hash by comparison
*
* Parameters:
*
* data_ptr, data_len: data to be hashed
* digest_info_ptr, digest_info_len: hash to be compared
*/
int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len,
void *digest_info_ptr, unsigned int digest_info_len)
{
assert(data_ptr != NULL);
assert(data_len != 0);
assert(digest_info_ptr != NULL);
assert(digest_info_len != 0);
return crypto_lib_desc.verify_hash(data_ptr, data_len,
digest_info_ptr, digest_info_len);
}
/*
* 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.
*/
#include <assert.h>
#include <auth_common.h>
#include <debug.h>
#include <errno.h>
#include <img_parser_mod.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
extern uintptr_t __PARSER_LIB_DESCS_START__;
extern uintptr_t __PARSER_LIB_DESCS_END__;
#define PARSER_LIB_DESCS_START ((uintptr_t) (&__PARSER_LIB_DESCS_START__))
#define PARSER_LIB_DESCS_END ((uintptr_t) (&__PARSER_LIB_DESCS_END__))
static unsigned int parser_lib_indices[IMG_MAX_TYPES];
static img_parser_lib_desc_t *parser_lib_descs;
#define INVALID_IDX UINT_MAX
static void validate_desc(img_parser_lib_desc_t *desc)
{
assert(desc != NULL);
assert(desc->init != NULL);
assert(desc->name != NULL);
assert(desc->check_integrity != NULL);
assert(desc->get_auth_param != NULL);
}
void img_parser_init(void)
{
unsigned int index, mod_num;
/* Initialise internal variables to invalid state */
for (index = 0; index < IMG_MAX_TYPES; index++) {
parser_lib_indices[index] = INVALID_IDX;
}
/* Calculate how many image parsers are registered. At least one parser
* must be present */
mod_num = PARSER_LIB_DESCS_END - PARSER_LIB_DESCS_START;
mod_num /= sizeof(img_parser_lib_desc_t);
assert(mod_num > 0);
parser_lib_descs = (img_parser_lib_desc_t *) PARSER_LIB_DESCS_START;
for (index = 0; index < mod_num; index++) {
/* Check that the image parser library descriptor is valid */
validate_desc(&parser_lib_descs[index]);
/* Initialize image parser */
parser_lib_descs[index].init();
/* Ensure only one parser is registered for each image type */
assert(parser_lib_indices[parser_lib_descs[index].img_type] ==
INVALID_IDX);
/* Keep the index of this hash calculator */
parser_lib_indices[parser_lib_descs[index].img_type] = index;
}
}
int img_parser_check_integrity(img_type_t img_type,
void *img_ptr, unsigned int img_len)
{
unsigned int idx;
assert(img_ptr != NULL);
assert(img_len != 0);
/* No integrity checks on raw images */
if (img_type == IMG_RAW) {
return IMG_PARSER_OK;
}
/* Find the index of the required image parser */
idx = parser_lib_indices[img_type];
assert(idx != INVALID_IDX);
/* Call the function to check the image integrity */
return parser_lib_descs[idx].check_integrity(img_ptr, img_len);
}
/*
* Extract an authentication parameter from an image
*
* Parameters:
* img_type: image type (certificate, raw image, etc)
* type_desc: provides info to obtain the parameter
* img_ptr: pointer to image data
* img_len: image length
* param_ptr: [out] stores a pointer to the parameter
* param_len: [out] stores the length of the parameter
*/
int img_parser_get_auth_param(img_type_t img_type,
const auth_param_type_desc_t *type_desc,
void *img_ptr, unsigned int img_len,
void **param_ptr, unsigned int *param_len)
{
unsigned int idx;
assert(type_desc != NULL);
assert(img_ptr != NULL);
assert(img_len != 0);
assert(param_ptr != NULL);
assert(param_len != NULL);
/* In a raw image we can only get the data itself */
if (img_type == IMG_RAW) {
assert(type_desc->type == AUTH_PARAM_RAW_DATA);
*param_ptr = img_ptr;
*param_len = img_len;
return IMG_PARSER_OK;
}
/* Find the index of the required image parser library */
idx = parser_lib_indices[img_type];
assert(idx != INVALID_IDX);
/* Call the function to obtain the parameter */
return parser_lib_descs[idx].get_auth_param(type_desc, img_ptr, img_len,
param_ptr, param_len);
}
......@@ -29,33 +29,37 @@
*/
#include <assert.h>
#include <auth.h>
#include <debug.h>
/* mbedTLS headers */
#include <polarssl/memory_buffer_alloc.h>
/*
* Initialize the authentication module
* mbedTLS heap
*/
void auth_init(void)
{
assert(auth_mod.name);
assert(auth_mod.init);
assert(auth_mod.verify);
INFO("Using authentication module '%s'\n", auth_mod.name);
if (auth_mod.init() != 0)
assert(0);
}
#if (MBEDTLS_KEY_ALG_ID == MBEDTLS_ECDSA)
#define MBEDTLS_HEAP_SIZE (14*1024)
#elif (MBEDTLS_KEY_ALG_ID == MBEDTLS_RSA)
#define MBEDTLS_HEAP_SIZE (8*1024)
#endif
static unsigned char heap[MBEDTLS_HEAP_SIZE];
/*
* Authenticate a certificate/image
* mbedTLS initialization function
*
* Return: 0 = success, Otherwise = error
*/
int auth_verify_obj(unsigned int obj_id, uintptr_t obj_buf, size_t len)
void mbedtls_init(void)
{
assert(obj_id < AUTH_NUM_OBJ);
assert(obj_buf != 0);
assert(auth_mod.verify);
static int ready;
int rc;
return auth_mod.verify(obj_id, obj_buf, len);
if (!ready) {
/* Initialize the mbedTLS heap */
rc = memory_buffer_alloc_init(heap, MBEDTLS_HEAP_SIZE);
if (rc == 0) {
ready = 1;
} else {
assert(0);
}
}
}
......@@ -28,41 +28,33 @@
# POSSIBILITY OF SUCH DAMAGE.
#
# POLARSSL_DIR must be set to the PolarSSL main directory (it must contain
ifneq (${MBEDTLS_COMMON_MK},1)
MBEDTLS_COMMON_MK := 1
# MBEDTLS_DIR must be set to the mbedTLS main directory (it must contain
# the 'include' and 'library' subdirectories).
ifeq (${POLARSSL_DIR},)
$(error Error: POLARSSL_DIR not set)
ifeq (${MBEDTLS_DIR},)
$(error Error: MBEDTLS_DIR not set)
endif
INCLUDES += -I${POLARSSL_DIR}/include \
-Icommon/auth/polarssl
INCLUDES += -I${MBEDTLS_DIR}/include \
-Iinclude/drivers/auth/mbedtls
POLARSSL_CONFIG_FILE := "<polarssl_config.h>"
# Specify mbedTLS configuration file
POLARSSL_CONFIG_FILE := "<mbedtls_config.h>"
$(eval $(call add_define,POLARSSL_CONFIG_FILE))
POLARSSL_SOURCES := $(addprefix ${POLARSSL_DIR}/library/, \
MBEDTLS_COMMON_SOURCES := drivers/auth/mbedtls/mbedtls_common.c \
$(addprefix ${MBEDTLS_DIR}/library/, \
asn1parse.c \
asn1write.c \
bignum.c \
md.c \
md_wrap.c \
memory_buffer_alloc.c \
oid.c \
pk.c \
pk_wrap.c \
pkparse.c \
pkwrite.c \
platform.c \
rsa.c \
sha256.c \
x509.c \
x509_crt.c \
)
BL1_SOURCES += ${POLARSSL_SOURCES} \
common/auth/polarssl/polarssl.c
BL2_SOURCES += ${POLARSSL_SOURCES} \
common/auth/polarssl/polarssl.c
BL1_SOURCES += ${MBEDTLS_COMMON_SOURCES}
BL2_SOURCES += ${MBEDTLS_COMMON_SOURCES}
DISABLE_PEDANTIC := 1
endif
/*
* 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.
*/
#include <crypto_mod.h>
#include <debug.h>
#include <mbedtls_common.h>
#include <stddef.h>
#include <string.h>
/* mbedTLS headers */
#include <polarssl/md_wrap.h>
#include <polarssl/memory_buffer_alloc.h>
#include <polarssl/oid.h>
#include <polarssl/platform.h>
#define LIB_NAME "mbedTLS"
/*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING
* }
*/
/*
* Initialize the library and export the descriptor
*/
static void init(void)
{
/* Initialize mbedTLS */
mbedtls_init();
}
/*
* Verify a signature.
*
* Parameters are passed using the DER encoding format following the ASN.1
* structures detailed above.
*/
static int verify_signature(void *data_ptr, unsigned int data_len,
void *sig_ptr, unsigned int sig_len,
void *sig_alg, unsigned int sig_alg_len,
void *pk_ptr, unsigned int pk_len)
{
asn1_buf sig_oid, sig_params;
asn1_buf signature;
md_type_t md_alg;
pk_type_t pk_alg;
pk_context pk;
int rc;
void *sig_opts = NULL;
const md_info_t *md_info;
unsigned char *p, *end;
unsigned char hash[POLARSSL_MD_MAX_SIZE];
/* Get pointers to signature OID and parameters */
p = (unsigned char *)sig_alg;
end = (unsigned char *)(p + sig_alg_len);
rc = asn1_get_alg(&p, end, &sig_oid, &sig_params);
if (rc != 0) {
return CRYPTO_ERR_SIGNATURE;
}
/* Get the actual signature algorithm (MD + PK) */
rc = oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
if (rc != 0) {
return CRYPTO_ERR_SIGNATURE;
}
/* Parse the public key */
pk_init(&pk);
p = (unsigned char *)pk_ptr;
end = (unsigned char *)(p + pk_len);
rc = pk_parse_subpubkey(&p, end, &pk);
if (rc != 0) {
return CRYPTO_ERR_SIGNATURE;
}
/* Get the signature (bitstring) */
p = (unsigned char *)sig_ptr;
end = (unsigned char *)(p + sig_len);
signature.tag = *p;
rc = asn1_get_bitstring_null(&p, end, &signature.len);
if (rc != 0) {
rc = CRYPTO_ERR_SIGNATURE;
goto end;
}
signature.p = p;
/* Calculate the hash of the data */
md_info = md_info_from_type(md_alg);
if (md_info == NULL) {
rc = CRYPTO_ERR_SIGNATURE;
goto end;
}
p = (unsigned char *)data_ptr;
rc = md(md_info, p, data_len, hash);
if (rc != 0) {
rc = CRYPTO_ERR_SIGNATURE;
goto end;
}
/* Verify the signature */
rc = pk_verify_ext(pk_alg, sig_opts, &pk, md_alg, hash,
md_info->size, signature.p, signature.len);
if (rc != 0) {
rc = CRYPTO_ERR_SIGNATURE;
goto end;
}
/* Signature verification success */
rc = CRYPTO_SUCCESS;
end:
pk_free(&pk);
return rc;
}
/*
* Match a hash
*
* Digest info is passed in DER format following the ASN.1 structure detailed
* above.
*/
static int verify_hash(void *data_ptr, unsigned int data_len,
void *digest_info_ptr, unsigned int digest_info_len)
{
asn1_buf hash_oid, params;
md_type_t md_alg;
const md_info_t *md_info;
unsigned char *p, *end, *hash;
unsigned char data_hash[POLARSSL_MD_MAX_SIZE];
size_t len;
int rc;
/* Digest info should be an ASN1_SEQUENCE */
p = (unsigned char *)digest_info_ptr;
end = (unsigned char *)(digest_info_ptr + digest_info_len);
rc = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (rc != 0) {
return CRYPTO_ERR_HASH;
}
/* Get the hash algorithm */
rc = asn1_get_alg(&p, end, &hash_oid, &params);
if (rc != 0) {
return CRYPTO_ERR_HASH;
}
rc = oid_get_md_alg(&hash_oid, &md_alg);
if (rc != 0) {
return CRYPTO_ERR_HASH;
}
md_info = md_info_from_type(md_alg);
if (md_info == NULL) {
return CRYPTO_ERR_HASH;
}
/* Hash should be octet string type */
rc = asn1_get_tag(&p, end, &len, ASN1_OCTET_STRING);
if (rc != 0) {
return CRYPTO_ERR_HASH;
}
/* Length of hash must match the algorithm's size */
if (len != md_info->size) {
return CRYPTO_ERR_HASH;
}
hash = p;
/* Calculate the hash of the data */
p = (unsigned char *)data_ptr;
rc = md(md_info, p, data_len, data_hash);
if (rc != 0) {
return CRYPTO_ERR_HASH;
}
/* Compare values */
rc = memcmp(data_hash, hash, md_info->size);
if (rc != 0) {
return CRYPTO_ERR_HASH;
}
return CRYPTO_SUCCESS;
}
/*
* Register crypto library descriptor
*/
REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash);
#
# 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.
#
include drivers/auth/mbedtls/mbedtls_common.mk
# The platform may define the variable 'MBEDTLS_KEY_ALG' to select the key
# algorithm to use. Default algorithm is ECDSA.
ifeq (${MBEDTLS_KEY_ALG},)
MBEDTLS_KEY_ALG := rsa
endif
MBEDTLS_CRYPTO_SOURCES := drivers/auth/mbedtls/mbedtls_crypto.c \
$(addprefix ${MBEDTLS_DIR}/library/, \
bignum.c \
md.c \
md_wrap.c \
pk.c \
pk_wrap.c \
pkparse.c \
pkwrite.c \
sha256.c \
)
# Key algorithm specific files
ifeq (${MBEDTLS_KEY_ALG},ecdsa)
MBEDTLS_CRYPTO_SOURCES += $(addprefix ${MBEDTLS_DIR}/library/, \
ecdsa.c \
ecp_curves.c \
ecp.c \
)
MBEDTLS_KEY_ALG_ID := MBEDTLS_ECDSA
else ifeq (${MBEDTLS_KEY_ALG},rsa)
MBEDTLS_CRYPTO_SOURCES += $(addprefix ${MBEDTLS_DIR}/library/, \
rsa.c \
)
MBEDTLS_KEY_ALG_ID := MBEDTLS_RSA
else
$(error "MBEDTLS_KEY_ALG=${MBEDTLS_KEY_ALG} not supported on mbedTLS")
endif
# mbedTLS libraries rely on this define to build correctly
$(eval $(call add_define,MBEDTLS_KEY_ALG_ID))
BL1_SOURCES += ${MBEDTLS_CRYPTO_SOURCES}
BL2_SOURCES += ${MBEDTLS_CRYPTO_SOURCES}
#
# 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.
#
include drivers/auth/mbedtls/mbedtls_common.mk
MBEDTLS_X509_SOURCES := drivers/auth/mbedtls/mbedtls_x509_parser.c \
$(addprefix ${MBEDTLS_DIR}/library/, \
x509.c \
x509_crt.c \
)
BL1_SOURCES += ${MBEDTLS_X509_SOURCES}
BL2_SOURCES += ${MBEDTLS_X509_SOURCES}
/*
* 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.
*/
/*
* X509 parser based on PolarSSL
*
* This module implements functions to check the integrity of a X509v3
* certificate ASN.1 structure and extract authentication parameters from the
* extensions field, such as an image hash or a public key.
*/
#include <assert.h>
#include <img_parser_mod.h>
#include <mbedtls_common.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/* mbedTLS headers */
#include <polarssl/asn1.h>
#include <polarssl/oid.h>
#include <polarssl/platform.h>
/* Maximum OID string length ("a.b.c.d.e.f ...") */
#define MAX_OID_STR_LEN 64
#define LIB_NAME "mbedTLS X509v3"
/* Temporary variables to speed up the authentication parameters search. These
* variables are assigned once during the integrity check and used any time an
* authentication parameter is requested, so we do not have to parse the image
* again */
static asn1_buf tbs;
static asn1_buf v3_ext;
static asn1_buf pk;
static asn1_buf sig_alg;
static asn1_buf signature;
/*
* Get X509v3 extension
*
* Global variable 'v3_ext' must point to the extensions region
* in the certificate. No need to check for errors since the image has passed
* the integrity check.
*/
static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
{
int oid_len;
size_t len;
unsigned char *end_ext_data, *end_ext_octet;
unsigned char *p;
const unsigned char *end;
char oid_str[MAX_OID_STR_LEN];
asn1_buf extn_oid;
int is_critical;
assert(oid != NULL);
p = v3_ext.p;
end = v3_ext.p + v3_ext.len;
asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
while (p < end) {
memset(&extn_oid, 0x0, sizeof(extn_oid));
is_critical = 0; /* DEFAULT FALSE */
asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
end_ext_data = p + len;
/* Get extension ID */
extn_oid.tag = *p;
asn1_get_tag(&p, end, &extn_oid.len, ASN1_OID);
extn_oid.p = p;
p += extn_oid.len;
/* Get optional critical */
asn1_get_bool(&p, end_ext_data, &is_critical);
/* Extension data */
asn1_get_tag(&p, end_ext_data, &len, ASN1_OCTET_STRING);
end_ext_octet = p + len;
/* Detect requested extension */
oid_len = oid_get_numeric_string(oid_str,
MAX_OID_STR_LEN, &extn_oid);
if (oid_len == POLARSSL_ERR_OID_BUF_TOO_SMALL) {
return IMG_PARSER_ERR;
}
if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
*ext = (void *)p;
*ext_len = (unsigned int)len;
return IMG_PARSER_OK;
}
/* Next */
p = end_ext_octet;
}
return IMG_PARSER_ERR_NOT_FOUND;
}
/*
* Check the integrity of the certificate ASN.1 structure.
* Extract the relevant data that will be used later during authentication.
*/
static int cert_parse(void *img, unsigned int img_len)
{
int ret, is_critical;
size_t len;
unsigned char *p, *end, *crt_end;
asn1_buf sig_alg1, sig_alg2;
p = (unsigned char *)img;
len = img_len;
end = p + len;
/*
* Certificate ::= SEQUENCE {
* tbsCertificate TBSCertificate,
* signatureAlgorithm AlgorithmIdentifier,
* signatureValue BIT STRING }
*/
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
if (len > (size_t)(end - p)) {
return IMG_PARSER_ERR_FORMAT;
}
crt_end = p + len;
/*
* TBSCertificate ::= SEQUENCE {
*/
tbs.p = p;
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
end = p + len;
tbs.len = end - tbs.p;
/*
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
ret = asn1_get_tag(&p, end, &len,
ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
/*
* CertificateSerialNumber ::= INTEGER
*/
ret = asn1_get_tag(&p, end, &len, ASN1_INTEGER);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
/*
* signature AlgorithmIdentifier
*/
sig_alg1.p = p;
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
if ((end - p) < 1) {
return IMG_PARSER_ERR_FORMAT;
}
sig_alg1.len = (p + len) - sig_alg1.p;
p += len;
/*
* issuer Name
*/
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
/*
* Validity ::= SEQUENCE {
* notBefore Time,
* notAfter Time }
*
*/
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
/*
* subject Name
*/
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
/*
* SubjectPublicKeyInfo
*/
pk.p = p;
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
pk.len = (p + len) - pk.p;
p += len;
/*
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
*/
ret = asn1_get_tag(&p, end, &len,
ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1);
if (ret != 0) {
if (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG) {
return IMG_PARSER_ERR_FORMAT;
}
} else {
p += len;
}
/*
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
*/
ret = asn1_get_tag(&p, end, &len,
ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 2);
if (ret != 0) {
if (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG) {
return IMG_PARSER_ERR_FORMAT;
}
} else {
p += len;
}
/*
* extensions [3] EXPLICIT Extensions OPTIONAL
*/
ret = asn1_get_tag(&p, end, &len,
ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
/*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
*/
v3_ext.p = p;
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
v3_ext.len = (p + len) - v3_ext.p;
/*
* Check extensions integrity
*/
while (p < end) {
ret = asn1_get_tag(&p, end, &len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
/* Get extension ID */
ret = asn1_get_tag(&p, end, &len, ASN1_OID);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
/* Get optional critical */
ret = asn1_get_bool(&p, end, &is_critical);
if ((ret != 0) && (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG)) {
return IMG_PARSER_ERR_FORMAT;
}
/* Data should be octet string type */
ret = asn1_get_tag(&p, end, &len, ASN1_OCTET_STRING);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
p += len;
}
if (p != end) {
return IMG_PARSER_ERR_FORMAT;
}
end = crt_end;
/*
* }
* -- end of TBSCertificate
*
* signatureAlgorithm AlgorithmIdentifier
*/
sig_alg2.p = p;
ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
if ((end - p) < 1) {
return IMG_PARSER_ERR_FORMAT;
}
sig_alg2.len = (p + len) - sig_alg2.p;
p += len;
/* Compare both signature algorithms */
if (sig_alg1.len != sig_alg2.len) {
return IMG_PARSER_ERR_FORMAT;
}
if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
return IMG_PARSER_ERR_FORMAT;
}
memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
/*
* signatureValue BIT STRING
*/
signature.p = p;
ret = asn1_get_tag(&p, end, &len, ASN1_BIT_STRING);
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
signature.len = (p + len) - signature.p;
p += len;
/* Check certificate length */
if (p != end) {
return IMG_PARSER_ERR_FORMAT;
}
return IMG_PARSER_OK;
}
/* Exported functions */
static void init(void)
{
mbedtls_init();
}
static int check_integrity(void *img, unsigned int img_len)
{
return cert_parse(img, img_len);
}
/*
* Extract an authentication parameter from an X509v3 certificate
*/
static int get_auth_param(const auth_param_type_desc_t *type_desc,
void *img, unsigned int img_len,
void **param, unsigned int *param_len)
{
int rc = IMG_PARSER_OK;
/* We do not use img because the check_integrity function has already
* extracted the relevant data (v3_ext, pk, sig_alg, etc) */
switch (type_desc->type) {
case AUTH_PARAM_RAW_DATA:
/* Data to be signed */
*param = (void *)tbs.p;
*param_len = (unsigned int)tbs.len;
break;
case AUTH_PARAM_HASH:
/* All these parameters are included as X509v3 extensions */
rc = get_ext(type_desc->cookie, param, param_len);
break;
case AUTH_PARAM_PUB_KEY:
if (type_desc->cookie != 0) {
/* Get public key from extension */
rc = get_ext(type_desc->cookie, param, param_len);
} else {
/* Get the subject public key */
*param = (void *)pk.p;
*param_len = (unsigned int)pk.len;
}
break;
case AUTH_PARAM_SIG_ALG:
/* Get the certificate signature algorithm */
*param = (void *)sig_alg.p;
*param_len = (unsigned int)sig_alg.len;
break;
case AUTH_PARAM_SIG:
/* Get the certificate signature */
*param = (void *)signature.p;
*param_len = (unsigned int)signature.len;
break;
default:
rc = IMG_PARSER_ERR_NOT_FOUND;
break;
}
return rc;
}
REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
check_integrity, get_auth_param);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment