TBB: add mbedTLS authentication related libraries

This patch adds the following mbedTLS based libraries:

* Cryptographic library

It is used by the crypto module to verify a digital signature
and a hash. This library relies on mbedTLS to perform the
cryptographic operations. mbedTLS sources must be obtained
separately.

Two key algorithms are currently supported:

    * RSA-2048
    * ECDSA-SECP256R1

The platform is responsible for picking up the required
algorithm by defining the 'MBEDTLS_KEY_ALG' variable in the
platform makefile. Available options are:

    * 'rsa' (for RSA-2048) (default option)
    * 'ecdsa' (for ECDSA-SECP256R1)

Hash algorithm currently supported is SHA-256.

* Image parser library

Used by the image parser module to extract the authentication
parameters stored in X509v3 certificates.

Change-Id: I597c4be3d29287f2f18b82846973afc142ee0bf0
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
new file mode 100644
index 0000000..2978260
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -0,0 +1,65 @@
+/*
+ * 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>
+
+/* mbedTLS headers */
+#include <polarssl/memory_buffer_alloc.h>
+
+/*
+ * mbedTLS heap
+ */
+#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];
+
+/*
+ * mbedTLS initialization function
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+void mbedtls_init(void)
+{
+	static int ready;
+	int rc;
+
+	if (!ready) {
+		/* Initialize the mbedTLS heap */
+		rc = memory_buffer_alloc_init(heap, MBEDTLS_HEAP_SIZE);
+		if (rc == 0) {
+			ready = 1;
+		} else {
+			assert(0);
+		}
+	}
+}
diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk
new file mode 100644
index 0000000..b71bbc9
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_common.mk
@@ -0,0 +1,60 @@
+#
+# 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.
+#
+
+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 (${MBEDTLS_DIR},)
+  $(error Error: MBEDTLS_DIR not set)
+endif
+
+INCLUDES		+=	-I${MBEDTLS_DIR}/include		\
+				-Iinclude/drivers/auth/mbedtls
+
+# Specify mbedTLS configuration file
+POLARSSL_CONFIG_FILE	:=	"<mbedtls_config.h>"
+$(eval $(call add_define,POLARSSL_CONFIG_FILE))
+
+MBEDTLS_COMMON_SOURCES	:=	drivers/auth/mbedtls/mbedtls_common.c	\
+				$(addprefix ${MBEDTLS_DIR}/library/,	\
+				asn1parse.c 				\
+				asn1write.c 				\
+				memory_buffer_alloc.c			\
+				oid.c 					\
+				platform.c 				\
+				)
+
+BL1_SOURCES		+=	${MBEDTLS_COMMON_SOURCES}
+BL2_SOURCES		+=	${MBEDTLS_COMMON_SOURCES}
+DISABLE_PEDANTIC	:=	1
+
+endif
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
new file mode 100644
index 0000000..f69f930
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -0,0 +1,229 @@
+/*
+ * 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);
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.mk b/drivers/auth/mbedtls/mbedtls_crypto.mk
new file mode 100644
index 0000000..67d2eb4
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_crypto.mk
@@ -0,0 +1,72 @@
+#
+# 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}
diff --git a/drivers/auth/mbedtls/mbedtls_x509.mk b/drivers/auth/mbedtls/mbedtls_x509.mk
new file mode 100644
index 0000000..3f9420d
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_x509.mk
@@ -0,0 +1,40 @@
+#
+# 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}
diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c
new file mode 100644
index 0000000..a8605ce
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c
@@ -0,0 +1,438 @@
+/*
+ * 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);