mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-05-02 17:00:53 +00:00

The mbed TLS library has introduced some changes in the API from the 1.3.x to the 2.x releases. Using the 2.x releases requires some changes to the crypto and transport modules. This patch updates both modules to the mbed TLS 2.x API. All references to the mbed TLS library in the code or documentation have been updated to 'mbed TLS'. Old references to PolarSSL have been updated to 'mbed TLS'. User guide updated to use mbed TLS 2.2.0. NOTE: moving up to mbed TLS 2.x from 1.3.x is not backward compatible. Applying this patch will require an mbed TLS 2.x release to be used. Also note that the mbed TLS license changed to Apache version 2.0. Change-Id: Iba4584408653cf153091f2ca2ee23bc9add7fda4
457 lines
11 KiB
C
457 lines
11 KiB
C
/*
|
|
* 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 mbed TLS
|
|
*
|
|
* 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>
|
|
|
|
/* mbed TLS headers */
|
|
#include <mbedtls/asn1.h>
|
|
#include <mbedtls/oid.h>
|
|
#include <mbedtls/platform.h>
|
|
|
|
/* Maximum OID string length ("a.b.c.d.e.f ...") */
|
|
#define MAX_OID_STR_LEN 64
|
|
|
|
#define LIB_NAME "mbed TLS 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 mbedtls_asn1_buf tbs;
|
|
static mbedtls_asn1_buf v3_ext;
|
|
static mbedtls_asn1_buf pk;
|
|
static mbedtls_asn1_buf sig_alg;
|
|
static mbedtls_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];
|
|
mbedtls_asn1_buf extn_oid;
|
|
int is_critical;
|
|
|
|
assert(oid != NULL);
|
|
|
|
p = v3_ext.p;
|
|
end = v3_ext.p + v3_ext.len;
|
|
|
|
mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
|
|
while (p < end) {
|
|
memset(&extn_oid, 0x0, sizeof(extn_oid));
|
|
is_critical = 0; /* DEFAULT FALSE */
|
|
|
|
mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
end_ext_data = p + len;
|
|
|
|
/* Get extension ID */
|
|
extn_oid.tag = *p;
|
|
mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID);
|
|
extn_oid.p = p;
|
|
p += extn_oid.len;
|
|
|
|
/* Get optional critical */
|
|
mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
|
|
|
|
/* Extension data */
|
|
mbedtls_asn1_get_tag(&p, end_ext_data, &len,
|
|
MBEDTLS_ASN1_OCTET_STRING);
|
|
end_ext_octet = p + len;
|
|
|
|
/* Detect requested extension */
|
|
oid_len = mbedtls_oid_get_numeric_string(oid_str,
|
|
MAX_OID_STR_LEN,
|
|
&extn_oid);
|
|
if (oid_len == MBEDTLS_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;
|
|
mbedtls_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 = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_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 = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_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 = mbedtls_asn1_get_tag(&p, end, &len,
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
|
|
MBEDTLS_ASN1_CONSTRUCTED | 0);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
p += len;
|
|
|
|
/*
|
|
* CertificateSerialNumber ::= INTEGER
|
|
*/
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
p += len;
|
|
|
|
/*
|
|
* signature AlgorithmIdentifier
|
|
*/
|
|
sig_alg1.p = p;
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_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 = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
p += len;
|
|
|
|
/*
|
|
* Validity ::= SEQUENCE {
|
|
* notBefore Time,
|
|
* notAfter Time }
|
|
*
|
|
*/
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
p += len;
|
|
|
|
/*
|
|
* subject Name
|
|
*/
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
p += len;
|
|
|
|
/*
|
|
* SubjectPublicKeyInfo
|
|
*/
|
|
pk.p = p;
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
pk.len = (p + len) - pk.p;
|
|
p += len;
|
|
|
|
/*
|
|
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
|
*/
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
|
|
MBEDTLS_ASN1_CONSTRUCTED | 1);
|
|
if (ret != 0) {
|
|
if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
} else {
|
|
p += len;
|
|
}
|
|
|
|
/*
|
|
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
|
*/
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
|
|
MBEDTLS_ASN1_CONSTRUCTED | 2);
|
|
if (ret != 0) {
|
|
if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
} else {
|
|
p += len;
|
|
}
|
|
|
|
/*
|
|
* extensions [3] EXPLICIT Extensions OPTIONAL
|
|
*/
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
|
|
MBEDTLS_ASN1_CONSTRUCTED | 3);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
|
|
/*
|
|
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
|
|
*/
|
|
v3_ext.p = p;
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_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 = mbedtls_asn1_get_tag(&p, end, &len,
|
|
MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_ASN1_SEQUENCE);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
|
|
/* Get extension ID */
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID);
|
|
if (ret != 0) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
p += len;
|
|
|
|
/* Get optional critical */
|
|
ret = mbedtls_asn1_get_bool(&p, end, &is_critical);
|
|
if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
|
|
return IMG_PARSER_ERR_FORMAT;
|
|
}
|
|
|
|
/* Data should be octet string type */
|
|
ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
MBEDTLS_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 = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
|
|
MBEDTLS_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 = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_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);
|