xref: /rk3399_ARM-atf/tools/cert_create/src/ext.c (revision 067f7e9c52f5aa19bac2cb91a96e6e4f9dee6cb9)
16f971622SJuan Castillo /*
2*067f7e9cSSandrine Bailleux  * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
36f971622SJuan Castillo  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
56f971622SJuan Castillo  */
66f971622SJuan Castillo 
76f971622SJuan Castillo #include <stddef.h>
86f971622SJuan Castillo #include <stdio.h>
96f971622SJuan Castillo #include <string.h>
10c3da66b1SJuan Castillo #include <openssl/asn1.h>
11c3da66b1SJuan Castillo #include <openssl/asn1t.h>
126f971622SJuan Castillo #include <openssl/err.h>
136f971622SJuan Castillo #include <openssl/x509v3.h>
14ad2c1a9aSJuan Castillo 
15ad2c1a9aSJuan Castillo #include "cmd_opt.h"
166f971622SJuan Castillo #include "ext.h"
176f971622SJuan Castillo 
186f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_INTEGER)
19c3da66b1SJuan Castillo DECLARE_ASN1_ITEM(X509_ALGOR)
206f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_OCTET_STRING)
216f971622SJuan Castillo 
22c3da66b1SJuan Castillo typedef struct {
23c3da66b1SJuan Castillo 	X509_ALGOR *hashAlgorithm;
24c3da66b1SJuan Castillo 	ASN1_OCTET_STRING *dataHash;
25c3da66b1SJuan Castillo } HASH;
26c3da66b1SJuan Castillo 
27c3da66b1SJuan Castillo ASN1_SEQUENCE(HASH) = {
28c3da66b1SJuan Castillo 	ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR),
29c3da66b1SJuan Castillo 	ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING),
30c3da66b1SJuan Castillo } ASN1_SEQUENCE_END(HASH)
31c3da66b1SJuan Castillo 
32c3da66b1SJuan Castillo DECLARE_ASN1_FUNCTIONS(HASH)
33c3da66b1SJuan Castillo IMPLEMENT_ASN1_FUNCTIONS(HASH)
34c3da66b1SJuan Castillo 
356f971622SJuan Castillo /*
36*067f7e9cSSandrine Bailleux  * This function adds the CoT extensions to the internal extension list
376f971622SJuan Castillo  * maintained by OpenSSL so they can be used later.
386f971622SJuan Castillo  *
396f971622SJuan Castillo  * It also initializes the methods to print the contents of the extension. If an
40*067f7e9cSSandrine Bailleux  * alias is specified in the CoT extension, we reuse the methods of the alias.
416f971622SJuan Castillo  * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are
426f971622SJuan Castillo  * provided. Any other type will be printed as a raw ascii string.
436f971622SJuan Castillo  *
446f971622SJuan Castillo  * Return: 0 = success, Otherwise: error
456f971622SJuan Castillo  */
46ad2c1a9aSJuan Castillo int ext_init(void)
476f971622SJuan Castillo {
48159807e2SJuan Castillo 	cmd_opt_t cmd_opt;
496f971622SJuan Castillo 	ext_t *ext;
506f971622SJuan Castillo 	X509V3_EXT_METHOD *m;
51ad2c1a9aSJuan Castillo 	int nid, ret;
52ad2c1a9aSJuan Castillo 	unsigned int i;
536f971622SJuan Castillo 
54ad2c1a9aSJuan Castillo 	for (i = 0; i < num_extensions; i++) {
55ad2c1a9aSJuan Castillo 		ext = &extensions[i];
56ad2c1a9aSJuan Castillo 		/* Register command line option */
57ad2c1a9aSJuan Castillo 		if (ext->opt) {
58159807e2SJuan Castillo 			cmd_opt.long_opt.name = ext->opt;
59159807e2SJuan Castillo 			cmd_opt.long_opt.has_arg = required_argument;
60159807e2SJuan Castillo 			cmd_opt.long_opt.flag = NULL;
61159807e2SJuan Castillo 			cmd_opt.long_opt.val = CMD_OPT_EXT;
62159807e2SJuan Castillo 			cmd_opt.help_msg = ext->help_msg;
63159807e2SJuan Castillo 			cmd_opt_add(&cmd_opt);
64ad2c1a9aSJuan Castillo 		}
65ad2c1a9aSJuan Castillo 		/* Register the extension OID in OpenSSL */
66ad2c1a9aSJuan Castillo 		if (ext->oid == NULL) {
67ad2c1a9aSJuan Castillo 			continue;
68ad2c1a9aSJuan Castillo 		}
696f971622SJuan Castillo 		nid = OBJ_create(ext->oid, ext->sn, ext->ln);
706f971622SJuan Castillo 		if (ext->alias) {
716f971622SJuan Castillo 			X509V3_EXT_add_alias(nid, ext->alias);
726f971622SJuan Castillo 		} else {
736f971622SJuan Castillo 			m = &ext->method;
746f971622SJuan Castillo 			memset(m, 0x0, sizeof(X509V3_EXT_METHOD));
7555e291a4SJuan Castillo 			switch (ext->asn1_type) {
766f971622SJuan Castillo 			case V_ASN1_INTEGER:
776f971622SJuan Castillo 				m->it = ASN1_ITEM_ref(ASN1_INTEGER);
786f971622SJuan Castillo 				m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER;
796f971622SJuan Castillo 				m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER;
806f971622SJuan Castillo 				break;
816f971622SJuan Castillo 			case V_ASN1_OCTET_STRING:
826f971622SJuan Castillo 				m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING);
836f971622SJuan Castillo 				m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING;
846f971622SJuan Castillo 				m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING;
856f971622SJuan Castillo 				break;
866f971622SJuan Castillo 			default:
876f971622SJuan Castillo 				continue;
886f971622SJuan Castillo 			}
896f971622SJuan Castillo 			m->ext_nid = nid;
906f971622SJuan Castillo 			ret = X509V3_EXT_add(m);
916f971622SJuan Castillo 			if (!ret) {
926f971622SJuan Castillo 				ERR_print_errors_fp(stdout);
936f971622SJuan Castillo 				return 1;
946f971622SJuan Castillo 			}
956f971622SJuan Castillo 		}
966f971622SJuan Castillo 	}
976f971622SJuan Castillo 	return 0;
986f971622SJuan Castillo }
996f971622SJuan Castillo 
1006f971622SJuan Castillo /*
1016f971622SJuan Castillo  * Create a new extension
1026f971622SJuan Castillo  *
1036f971622SJuan Castillo  * Extension  ::=  SEQUENCE  {
1046f971622SJuan Castillo  *      id          OBJECT IDENTIFIER,
1056f971622SJuan Castillo  *      critical    BOOLEAN DEFAULT FALSE,
1066f971622SJuan Castillo  *      value       OCTET STRING  }
1076f971622SJuan Castillo  *
1086f971622SJuan Castillo  * Parameters:
1096f971622SJuan Castillo  *   pex: OpenSSL extension pointer (output parameter)
1106f971622SJuan Castillo  *   nid: extension identifier
1116f971622SJuan Castillo  *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
1126f971622SJuan Castillo  *   data: extension data. This data will be encapsulated in an Octet String
1136f971622SJuan Castillo  *
1146f971622SJuan Castillo  * Return: Extension address, NULL if error
1156f971622SJuan Castillo  */
1166f971622SJuan Castillo static
1176f971622SJuan Castillo X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len)
1186f971622SJuan Castillo {
1196f971622SJuan Castillo 	X509_EXTENSION *ex;
1206f971622SJuan Castillo 	ASN1_OCTET_STRING *ext_data;
1216f971622SJuan Castillo 
1226f971622SJuan Castillo 	/* Octet string containing the extension data */
1236f971622SJuan Castillo 	ext_data = ASN1_OCTET_STRING_new();
1246f971622SJuan Castillo 	ASN1_OCTET_STRING_set(ext_data, data, len);
1256f971622SJuan Castillo 
1266f971622SJuan Castillo 	/* Create the extension */
1276f971622SJuan Castillo 	ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data);
1286f971622SJuan Castillo 
1296f971622SJuan Castillo 	/* The extension makes a copy of the data, so we can free this object */
1306f971622SJuan Castillo 	ASN1_OCTET_STRING_free(ext_data);
1316f971622SJuan Castillo 
1326f971622SJuan Castillo 	return ex;
1336f971622SJuan Castillo }
1346f971622SJuan Castillo 
1356f971622SJuan Castillo /*
136c3da66b1SJuan Castillo  * Creates a x509v3 extension containing a hash
137c3da66b1SJuan Castillo  *
138c3da66b1SJuan Castillo  * DigestInfo ::= SEQUENCE {
139c3da66b1SJuan Castillo  *     digestAlgorithm  AlgorithmIdentifier,
140c3da66b1SJuan Castillo  *     digest           OCTET STRING
141c3da66b1SJuan Castillo  * }
142c3da66b1SJuan Castillo  *
143c3da66b1SJuan Castillo  * AlgorithmIdentifier ::=  SEQUENCE  {
144c3da66b1SJuan Castillo  *     algorithm        OBJECT IDENTIFIER,
145c3da66b1SJuan Castillo  *     parameters       ANY DEFINED BY algorithm OPTIONAL
146c3da66b1SJuan Castillo  * }
1476f971622SJuan Castillo  *
1486f971622SJuan Castillo  * Parameters:
1496f971622SJuan Castillo  *   nid: extension identifier
1506f971622SJuan Castillo  *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
151c3da66b1SJuan Castillo  *   md: hash algorithm
1526f971622SJuan Castillo  *   buf: pointer to the buffer that contains the hash
1536f971622SJuan Castillo  *   len: size of the hash in bytes
1546f971622SJuan Castillo  *
1556f971622SJuan Castillo  * Return: Extension address, NULL if error
1566f971622SJuan Castillo  */
157c3da66b1SJuan Castillo X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
158c3da66b1SJuan Castillo 		unsigned char *buf, size_t len)
1596f971622SJuan Castillo {
160c893c733SMasahiro Yamada 	X509_EXTENSION *ex;
161c893c733SMasahiro Yamada 	ASN1_OCTET_STRING *octet;
162c893c733SMasahiro Yamada 	HASH *hash;
163c893c733SMasahiro Yamada 	ASN1_OBJECT *algorithm;
164c893c733SMasahiro Yamada 	X509_ALGOR *x509_algor;
1656f971622SJuan Castillo 	unsigned char *p = NULL;
166c893c733SMasahiro Yamada 	int sz;
1676f971622SJuan Castillo 
168c3da66b1SJuan Castillo 	/* OBJECT_IDENTIFIER with hash algorithm */
169742c4e14SMichalis Pappas 	algorithm = OBJ_nid2obj(EVP_MD_type(md));
170c3da66b1SJuan Castillo 	if (algorithm == NULL) {
171c3da66b1SJuan Castillo 		return NULL;
172c3da66b1SJuan Castillo 	}
173c3da66b1SJuan Castillo 
174c3da66b1SJuan Castillo 	/* Create X509_ALGOR */
175c3da66b1SJuan Castillo 	x509_algor = X509_ALGOR_new();
176c3da66b1SJuan Castillo 	if (x509_algor == NULL) {
177c3da66b1SJuan Castillo 		return NULL;
178c3da66b1SJuan Castillo 	}
179c3da66b1SJuan Castillo 	x509_algor->algorithm = algorithm;
180c3da66b1SJuan Castillo 	x509_algor->parameter = ASN1_TYPE_new();
181c3da66b1SJuan Castillo 	ASN1_TYPE_set(x509_algor->parameter, V_ASN1_NULL, NULL);
182c3da66b1SJuan Castillo 
183c3da66b1SJuan Castillo 	/* OCTET_STRING with the actual hash */
184c3da66b1SJuan Castillo 	octet = ASN1_OCTET_STRING_new();
185c3da66b1SJuan Castillo 	if (octet == NULL) {
186c3da66b1SJuan Castillo 		X509_ALGOR_free(x509_algor);
187c3da66b1SJuan Castillo 		return NULL;
188c3da66b1SJuan Castillo 	}
189c3da66b1SJuan Castillo 	ASN1_OCTET_STRING_set(octet, buf, len);
190c3da66b1SJuan Castillo 
191c3da66b1SJuan Castillo 	/* HASH structure containing algorithm + hash */
192c3da66b1SJuan Castillo 	hash = HASH_new();
193c3da66b1SJuan Castillo 	if (hash == NULL) {
194c3da66b1SJuan Castillo 		ASN1_OCTET_STRING_free(octet);
195c3da66b1SJuan Castillo 		X509_ALGOR_free(x509_algor);
196c3da66b1SJuan Castillo 		return NULL;
197c3da66b1SJuan Castillo 	}
198c3da66b1SJuan Castillo 	hash->hashAlgorithm = x509_algor;
199c3da66b1SJuan Castillo 	hash->dataHash = octet;
200c3da66b1SJuan Castillo 
201c3da66b1SJuan Castillo 	/* DER encoded HASH */
202c3da66b1SJuan Castillo 	sz = i2d_HASH(hash, &p);
203c3da66b1SJuan Castillo 	if ((sz <= 0) || (p == NULL)) {
204c3da66b1SJuan Castillo 		HASH_free(hash);
205c3da66b1SJuan Castillo 		X509_ALGOR_free(x509_algor);
206c3da66b1SJuan Castillo 		return NULL;
207c3da66b1SJuan Castillo 	}
2086f971622SJuan Castillo 
2096f971622SJuan Castillo 	/* Create the extension */
2106f971622SJuan Castillo 	ex = ext_new(nid, crit, p, sz);
2116f971622SJuan Castillo 
2126f971622SJuan Castillo 	/* Clean up */
2136f971622SJuan Castillo 	OPENSSL_free(p);
214c3da66b1SJuan Castillo 	HASH_free(hash);
2156f971622SJuan Castillo 
2166f971622SJuan Castillo 	return ex;
2176f971622SJuan Castillo }
2186f971622SJuan Castillo 
2196f971622SJuan Castillo /*
2206f971622SJuan Castillo  * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1
2216f971622SJuan Castillo  * Integer
2226f971622SJuan Castillo  *
2236f971622SJuan Castillo  * Parameters:
2246f971622SJuan Castillo  *   pex: OpenSSL extension pointer (output parameter)
2256f971622SJuan Castillo  *   nid: extension identifier
2266f971622SJuan Castillo  *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
2276f971622SJuan Castillo  *   value: nvcounter value
2286f971622SJuan Castillo  *
2296f971622SJuan Castillo  * Return: Extension address, NULL if error
2306f971622SJuan Castillo  */
2316f971622SJuan Castillo X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value)
2326f971622SJuan Castillo {
233c893c733SMasahiro Yamada 	X509_EXTENSION *ex;
234c893c733SMasahiro Yamada 	ASN1_INTEGER *counter;
2356f971622SJuan Castillo 	unsigned char *p = NULL;
236c893c733SMasahiro Yamada 	int sz;
2376f971622SJuan Castillo 
2386f971622SJuan Castillo 	/* Encode counter */
2396f971622SJuan Castillo 	counter = ASN1_INTEGER_new();
2406f971622SJuan Castillo 	ASN1_INTEGER_set(counter, value);
241559eb8b7SMasahiro Yamada 	sz = i2d_ASN1_INTEGER(counter, &p);
2426f971622SJuan Castillo 
2436f971622SJuan Castillo 	/* Create the extension */
2446f971622SJuan Castillo 	ex = ext_new(nid, crit, p, sz);
2456f971622SJuan Castillo 
2466f971622SJuan Castillo 	/* Free objects */
2476f971622SJuan Castillo 	OPENSSL_free(p);
2486f971622SJuan Castillo 	ASN1_INTEGER_free(counter);
2496f971622SJuan Castillo 
2506f971622SJuan Castillo 	return ex;
2516f971622SJuan Castillo }
2526f971622SJuan Castillo 
2536f971622SJuan Castillo /*
2546f971622SJuan Castillo  * Creates a x509v3 extension containing a public key in DER format:
2556f971622SJuan Castillo  *
2566f971622SJuan Castillo  *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
2576f971622SJuan Castillo  *       algorithm            AlgorithmIdentifier,
2586f971622SJuan Castillo  *       subjectPublicKey     BIT STRING }
2596f971622SJuan Castillo  *
2606f971622SJuan Castillo  * Parameters:
2616f971622SJuan Castillo  *   pex: OpenSSL extension pointer (output parameter)
2626f971622SJuan Castillo  *   nid: extension identifier
2636f971622SJuan Castillo  *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
2646f971622SJuan Castillo  *   k: key
2656f971622SJuan Castillo  *
2666f971622SJuan Castillo  * Return: Extension address, NULL if error
2676f971622SJuan Castillo  */
2686f971622SJuan Castillo X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k)
2696f971622SJuan Castillo {
270c893c733SMasahiro Yamada 	X509_EXTENSION *ex;
271c893c733SMasahiro Yamada 	unsigned char *p;
272c893c733SMasahiro Yamada 	int sz;
2736f971622SJuan Castillo 
2746f971622SJuan Castillo 	/* Encode key */
2756f971622SJuan Castillo 	BIO *mem = BIO_new(BIO_s_mem());
2766f971622SJuan Castillo 	if (i2d_PUBKEY_bio(mem, k) <= 0) {
2776f971622SJuan Castillo 		ERR_print_errors_fp(stderr);
2786f971622SJuan Castillo 		return NULL;
2796f971622SJuan Castillo 	}
2806f971622SJuan Castillo 	p = (unsigned char *)OPENSSL_malloc(4096);
2816f971622SJuan Castillo 	sz = BIO_read(mem, p, 4096);
2826f971622SJuan Castillo 
2836f971622SJuan Castillo 	/* Create the extension */
2846f971622SJuan Castillo 	ex = ext_new(nid, crit, p, sz);
2856f971622SJuan Castillo 
2866f971622SJuan Castillo 	/* Clean up */
28765ec13bcSJustin Chadwell 	BIO_free(mem);
2886f971622SJuan Castillo 	OPENSSL_free(p);
2896f971622SJuan Castillo 
2906f971622SJuan Castillo 	return ex;
2916f971622SJuan Castillo }
292ad2c1a9aSJuan Castillo 
293ad2c1a9aSJuan Castillo ext_t *ext_get_by_opt(const char *opt)
294ad2c1a9aSJuan Castillo {
295c893c733SMasahiro Yamada 	ext_t *ext;
296ad2c1a9aSJuan Castillo 	unsigned int i;
297ad2c1a9aSJuan Castillo 
298ad2c1a9aSJuan Castillo 	/* Sequential search. This is not a performance concern since the number
299ad2c1a9aSJuan Castillo 	 * of extensions is bounded and the code runs on a host machine */
300ad2c1a9aSJuan Castillo 	for (i = 0; i < num_extensions; i++) {
301ad2c1a9aSJuan Castillo 		ext = &extensions[i];
302ad2c1a9aSJuan Castillo 		if (ext->opt && !strcmp(ext->opt, opt)) {
303ad2c1a9aSJuan Castillo 			return ext;
304ad2c1a9aSJuan Castillo 		}
305ad2c1a9aSJuan Castillo 	}
306ad2c1a9aSJuan Castillo 
307ad2c1a9aSJuan Castillo 	return NULL;
308ad2c1a9aSJuan Castillo }
309