16f971622SJuan Castillo /*
2*cf2dd17dSJuan Pablo Conde * Copyright (c) 2015-2022, 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"
16b94bf967SPankaj Gupta #include "debug.h"
176f971622SJuan Castillo #include "ext.h"
186f971622SJuan Castillo
19b94bf967SPankaj Gupta ext_t *extensions;
20b94bf967SPankaj Gupta unsigned int num_extensions;
21b94bf967SPankaj Gupta
226f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_INTEGER)
23c3da66b1SJuan Castillo DECLARE_ASN1_ITEM(X509_ALGOR)
246f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_OCTET_STRING)
256f971622SJuan Castillo
26c3da66b1SJuan Castillo typedef struct {
27c3da66b1SJuan Castillo X509_ALGOR *hashAlgorithm;
28c3da66b1SJuan Castillo ASN1_OCTET_STRING *dataHash;
29c3da66b1SJuan Castillo } HASH;
30c3da66b1SJuan Castillo
31c3da66b1SJuan Castillo ASN1_SEQUENCE(HASH) = {
32c3da66b1SJuan Castillo ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR),
33c3da66b1SJuan Castillo ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING),
34c3da66b1SJuan Castillo } ASN1_SEQUENCE_END(HASH)
35c3da66b1SJuan Castillo
36c3da66b1SJuan Castillo DECLARE_ASN1_FUNCTIONS(HASH)
37c3da66b1SJuan Castillo IMPLEMENT_ASN1_FUNCTIONS(HASH)
38c3da66b1SJuan Castillo
396f971622SJuan Castillo /*
40067f7e9cSSandrine Bailleux * This function adds the CoT extensions to the internal extension list
416f971622SJuan Castillo * maintained by OpenSSL so they can be used later.
426f971622SJuan Castillo *
436f971622SJuan Castillo * It also initializes the methods to print the contents of the extension. If an
44067f7e9cSSandrine Bailleux * alias is specified in the CoT extension, we reuse the methods of the alias.
456f971622SJuan Castillo * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are
466f971622SJuan Castillo * provided. Any other type will be printed as a raw ascii string.
476f971622SJuan Castillo *
486f971622SJuan Castillo * Return: 0 = success, Otherwise: error
496f971622SJuan Castillo */
50ad2c1a9aSJuan Castillo int ext_init(void)
516f971622SJuan Castillo {
52159807e2SJuan Castillo cmd_opt_t cmd_opt;
536f971622SJuan Castillo ext_t *ext;
546f971622SJuan Castillo X509V3_EXT_METHOD *m;
55ad2c1a9aSJuan Castillo int nid, ret;
56ad2c1a9aSJuan Castillo unsigned int i;
576f971622SJuan Castillo
58b94bf967SPankaj Gupta extensions = malloc((num_def_extensions * sizeof(def_extensions[0]))
59b94bf967SPankaj Gupta #ifdef PDEF_EXTS
60b94bf967SPankaj Gupta + (num_pdef_extensions * sizeof(pdef_extensions[0]))
61b94bf967SPankaj Gupta #endif
62b94bf967SPankaj Gupta );
63b94bf967SPankaj Gupta if (extensions == NULL) {
64b94bf967SPankaj Gupta ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
65b94bf967SPankaj Gupta return 1;
66b94bf967SPankaj Gupta }
67b94bf967SPankaj Gupta
68b94bf967SPankaj Gupta memcpy(&extensions[0], &def_extensions[0],
69b94bf967SPankaj Gupta (num_def_extensions * sizeof(def_extensions[0])));
70b94bf967SPankaj Gupta #ifdef PDEF_EXTS
71b94bf967SPankaj Gupta memcpy(&extensions[num_def_extensions], &pdef_extensions[0],
72b94bf967SPankaj Gupta (num_pdef_extensions * sizeof(pdef_extensions[0])));
73b94bf967SPankaj Gupta num_extensions = num_def_extensions + num_pdef_extensions;
74b94bf967SPankaj Gupta #else
75b94bf967SPankaj Gupta num_extensions = num_def_extensions;
76b94bf967SPankaj Gupta #endif
77b94bf967SPankaj Gupta
78ad2c1a9aSJuan Castillo for (i = 0; i < num_extensions; i++) {
79ad2c1a9aSJuan Castillo ext = &extensions[i];
80ad2c1a9aSJuan Castillo /* Register command line option */
81ad2c1a9aSJuan Castillo if (ext->opt) {
82159807e2SJuan Castillo cmd_opt.long_opt.name = ext->opt;
83159807e2SJuan Castillo cmd_opt.long_opt.has_arg = required_argument;
84159807e2SJuan Castillo cmd_opt.long_opt.flag = NULL;
85159807e2SJuan Castillo cmd_opt.long_opt.val = CMD_OPT_EXT;
86159807e2SJuan Castillo cmd_opt.help_msg = ext->help_msg;
87159807e2SJuan Castillo cmd_opt_add(&cmd_opt);
88ad2c1a9aSJuan Castillo }
89ad2c1a9aSJuan Castillo /* Register the extension OID in OpenSSL */
90ad2c1a9aSJuan Castillo if (ext->oid == NULL) {
91ad2c1a9aSJuan Castillo continue;
92ad2c1a9aSJuan Castillo }
936f971622SJuan Castillo nid = OBJ_create(ext->oid, ext->sn, ext->ln);
946f971622SJuan Castillo if (ext->alias) {
956f971622SJuan Castillo X509V3_EXT_add_alias(nid, ext->alias);
966f971622SJuan Castillo } else {
976f971622SJuan Castillo m = &ext->method;
986f971622SJuan Castillo memset(m, 0x0, sizeof(X509V3_EXT_METHOD));
9955e291a4SJuan Castillo switch (ext->asn1_type) {
1006f971622SJuan Castillo case V_ASN1_INTEGER:
1016f971622SJuan Castillo m->it = ASN1_ITEM_ref(ASN1_INTEGER);
1026f971622SJuan Castillo m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER;
1036f971622SJuan Castillo m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER;
1046f971622SJuan Castillo break;
1056f971622SJuan Castillo case V_ASN1_OCTET_STRING:
1066f971622SJuan Castillo m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING);
1076f971622SJuan Castillo m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING;
1086f971622SJuan Castillo m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING;
1096f971622SJuan Castillo break;
1106f971622SJuan Castillo default:
1116f971622SJuan Castillo continue;
1126f971622SJuan Castillo }
1136f971622SJuan Castillo m->ext_nid = nid;
1146f971622SJuan Castillo ret = X509V3_EXT_add(m);
1156f971622SJuan Castillo if (!ret) {
1166f971622SJuan Castillo ERR_print_errors_fp(stdout);
1176f971622SJuan Castillo return 1;
1186f971622SJuan Castillo }
1196f971622SJuan Castillo }
1206f971622SJuan Castillo }
1216f971622SJuan Castillo return 0;
1226f971622SJuan Castillo }
1236f971622SJuan Castillo
1246f971622SJuan Castillo /*
1256f971622SJuan Castillo * Create a new extension
1266f971622SJuan Castillo *
1276f971622SJuan Castillo * Extension ::= SEQUENCE {
1286f971622SJuan Castillo * id OBJECT IDENTIFIER,
1296f971622SJuan Castillo * critical BOOLEAN DEFAULT FALSE,
1306f971622SJuan Castillo * value OCTET STRING }
1316f971622SJuan Castillo *
1326f971622SJuan Castillo * Parameters:
1336f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter)
1346f971622SJuan Castillo * nid: extension identifier
1356f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
1366f971622SJuan Castillo * data: extension data. This data will be encapsulated in an Octet String
1376f971622SJuan Castillo *
1386f971622SJuan Castillo * Return: Extension address, NULL if error
1396f971622SJuan Castillo */
1406f971622SJuan Castillo static
ext_new(int nid,int crit,unsigned char * data,int len)1416f971622SJuan Castillo X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len)
1426f971622SJuan Castillo {
1436f971622SJuan Castillo X509_EXTENSION *ex;
1446f971622SJuan Castillo ASN1_OCTET_STRING *ext_data;
1456f971622SJuan Castillo
1466f971622SJuan Castillo /* Octet string containing the extension data */
1476f971622SJuan Castillo ext_data = ASN1_OCTET_STRING_new();
1486f971622SJuan Castillo ASN1_OCTET_STRING_set(ext_data, data, len);
1496f971622SJuan Castillo
1506f971622SJuan Castillo /* Create the extension */
1516f971622SJuan Castillo ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data);
1526f971622SJuan Castillo
1536f971622SJuan Castillo /* The extension makes a copy of the data, so we can free this object */
1546f971622SJuan Castillo ASN1_OCTET_STRING_free(ext_data);
1556f971622SJuan Castillo
1566f971622SJuan Castillo return ex;
1576f971622SJuan Castillo }
1586f971622SJuan Castillo
1596f971622SJuan Castillo /*
160c3da66b1SJuan Castillo * Creates a x509v3 extension containing a hash
161c3da66b1SJuan Castillo *
162c3da66b1SJuan Castillo * DigestInfo ::= SEQUENCE {
163c3da66b1SJuan Castillo * digestAlgorithm AlgorithmIdentifier,
164c3da66b1SJuan Castillo * digest OCTET STRING
165c3da66b1SJuan Castillo * }
166c3da66b1SJuan Castillo *
167c3da66b1SJuan Castillo * AlgorithmIdentifier ::= SEQUENCE {
168c3da66b1SJuan Castillo * algorithm OBJECT IDENTIFIER,
169c3da66b1SJuan Castillo * parameters ANY DEFINED BY algorithm OPTIONAL
170c3da66b1SJuan Castillo * }
1716f971622SJuan Castillo *
1726f971622SJuan Castillo * Parameters:
1736f971622SJuan Castillo * nid: extension identifier
1746f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
175c3da66b1SJuan Castillo * md: hash algorithm
1766f971622SJuan Castillo * buf: pointer to the buffer that contains the hash
1776f971622SJuan Castillo * len: size of the hash in bytes
1786f971622SJuan Castillo *
1796f971622SJuan Castillo * Return: Extension address, NULL if error
1806f971622SJuan Castillo */
ext_new_hash(int nid,int crit,const EVP_MD * md,unsigned char * buf,size_t len)181c3da66b1SJuan Castillo X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
182c3da66b1SJuan Castillo unsigned char *buf, size_t len)
1836f971622SJuan Castillo {
184c893c733SMasahiro Yamada X509_EXTENSION *ex;
185c893c733SMasahiro Yamada HASH *hash;
186c893c733SMasahiro Yamada ASN1_OBJECT *algorithm;
1876f971622SJuan Castillo unsigned char *p = NULL;
188c893c733SMasahiro Yamada int sz;
1896f971622SJuan Castillo
190c3da66b1SJuan Castillo /* HASH structure containing algorithm + hash */
191c3da66b1SJuan Castillo hash = HASH_new();
192c3da66b1SJuan Castillo if (hash == NULL) {
193c3da66b1SJuan Castillo return NULL;
194c3da66b1SJuan Castillo }
195bcad2030SJimmy Brisson
196bcad2030SJimmy Brisson /* OBJECT_IDENTIFIER with hash algorithm */
197bcad2030SJimmy Brisson algorithm = OBJ_nid2obj(EVP_MD_type(md));
198bcad2030SJimmy Brisson if (algorithm == NULL) {
199bcad2030SJimmy Brisson HASH_free(hash);
200bcad2030SJimmy Brisson return NULL;
201bcad2030SJimmy Brisson }
202bcad2030SJimmy Brisson
203bcad2030SJimmy Brisson /* Create X509_ALGOR */
204bcad2030SJimmy Brisson hash->hashAlgorithm->algorithm = algorithm;
205bcad2030SJimmy Brisson hash->hashAlgorithm->parameter = ASN1_TYPE_new();
206bcad2030SJimmy Brisson ASN1_TYPE_set(hash->hashAlgorithm->parameter, V_ASN1_NULL, NULL);
207bcad2030SJimmy Brisson
208bcad2030SJimmy Brisson /* OCTET_STRING with the actual hash */
209bcad2030SJimmy Brisson ASN1_OCTET_STRING_set(hash->dataHash, buf, len);
210c3da66b1SJuan Castillo
211c3da66b1SJuan Castillo /* DER encoded HASH */
212c3da66b1SJuan Castillo sz = i2d_HASH(hash, &p);
213c3da66b1SJuan Castillo if ((sz <= 0) || (p == NULL)) {
214c3da66b1SJuan Castillo HASH_free(hash);
215c3da66b1SJuan Castillo return NULL;
216c3da66b1SJuan Castillo }
2176f971622SJuan Castillo
2186f971622SJuan Castillo /* Create the extension */
2196f971622SJuan Castillo ex = ext_new(nid, crit, p, sz);
2206f971622SJuan Castillo
2216f971622SJuan Castillo /* Clean up */
2226f971622SJuan Castillo OPENSSL_free(p);
223c3da66b1SJuan Castillo HASH_free(hash);
2246f971622SJuan Castillo
2256f971622SJuan Castillo return ex;
2266f971622SJuan Castillo }
2276f971622SJuan Castillo
2286f971622SJuan Castillo /*
2296f971622SJuan Castillo * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1
2306f971622SJuan Castillo * Integer
2316f971622SJuan Castillo *
2326f971622SJuan Castillo * Parameters:
2336f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter)
2346f971622SJuan Castillo * nid: extension identifier
2356f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
2366f971622SJuan Castillo * value: nvcounter value
2376f971622SJuan Castillo *
2386f971622SJuan Castillo * Return: Extension address, NULL if error
2396f971622SJuan Castillo */
ext_new_nvcounter(int nid,int crit,int value)2406f971622SJuan Castillo X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value)
2416f971622SJuan Castillo {
242c893c733SMasahiro Yamada X509_EXTENSION *ex;
243c893c733SMasahiro Yamada ASN1_INTEGER *counter;
2446f971622SJuan Castillo unsigned char *p = NULL;
245c893c733SMasahiro Yamada int sz;
2466f971622SJuan Castillo
2476f971622SJuan Castillo /* Encode counter */
2486f971622SJuan Castillo counter = ASN1_INTEGER_new();
2496f971622SJuan Castillo ASN1_INTEGER_set(counter, value);
250559eb8b7SMasahiro Yamada sz = i2d_ASN1_INTEGER(counter, &p);
2516f971622SJuan Castillo
2526f971622SJuan Castillo /* Create the extension */
2536f971622SJuan Castillo ex = ext_new(nid, crit, p, sz);
2546f971622SJuan Castillo
2556f971622SJuan Castillo /* Free objects */
2566f971622SJuan Castillo OPENSSL_free(p);
2576f971622SJuan Castillo ASN1_INTEGER_free(counter);
2586f971622SJuan Castillo
2596f971622SJuan Castillo return ex;
2606f971622SJuan Castillo }
2616f971622SJuan Castillo
2626f971622SJuan Castillo /*
2636f971622SJuan Castillo * Creates a x509v3 extension containing a public key in DER format:
2646f971622SJuan Castillo *
2656f971622SJuan Castillo * SubjectPublicKeyInfo ::= SEQUENCE {
2666f971622SJuan Castillo * algorithm AlgorithmIdentifier,
2676f971622SJuan Castillo * subjectPublicKey BIT STRING }
2686f971622SJuan Castillo *
2696f971622SJuan Castillo * Parameters:
2706f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter)
2716f971622SJuan Castillo * nid: extension identifier
2726f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
2736f971622SJuan Castillo * k: key
2746f971622SJuan Castillo *
2756f971622SJuan Castillo * Return: Extension address, NULL if error
2766f971622SJuan Castillo */
ext_new_key(int nid,int crit,EVP_PKEY * k)2776f971622SJuan Castillo X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k)
2786f971622SJuan Castillo {
279c893c733SMasahiro Yamada X509_EXTENSION *ex;
280c893c733SMasahiro Yamada unsigned char *p;
281c893c733SMasahiro Yamada int sz;
2826f971622SJuan Castillo
2836f971622SJuan Castillo /* Encode key */
2846f971622SJuan Castillo BIO *mem = BIO_new(BIO_s_mem());
2856f971622SJuan Castillo if (i2d_PUBKEY_bio(mem, k) <= 0) {
2866f971622SJuan Castillo ERR_print_errors_fp(stderr);
2876f971622SJuan Castillo return NULL;
2886f971622SJuan Castillo }
2896f971622SJuan Castillo p = (unsigned char *)OPENSSL_malloc(4096);
2906f971622SJuan Castillo sz = BIO_read(mem, p, 4096);
2916f971622SJuan Castillo
2926f971622SJuan Castillo /* Create the extension */
2936f971622SJuan Castillo ex = ext_new(nid, crit, p, sz);
2946f971622SJuan Castillo
2956f971622SJuan Castillo /* Clean up */
29665ec13bcSJustin Chadwell BIO_free(mem);
2976f971622SJuan Castillo OPENSSL_free(p);
2986f971622SJuan Castillo
2996f971622SJuan Castillo return ex;
3006f971622SJuan Castillo }
301ad2c1a9aSJuan Castillo
ext_get_by_opt(const char * opt)302ad2c1a9aSJuan Castillo ext_t *ext_get_by_opt(const char *opt)
303ad2c1a9aSJuan Castillo {
304c893c733SMasahiro Yamada ext_t *ext;
305ad2c1a9aSJuan Castillo unsigned int i;
306ad2c1a9aSJuan Castillo
307ad2c1a9aSJuan Castillo /* Sequential search. This is not a performance concern since the number
308ad2c1a9aSJuan Castillo * of extensions is bounded and the code runs on a host machine */
309ad2c1a9aSJuan Castillo for (i = 0; i < num_extensions; i++) {
310ad2c1a9aSJuan Castillo ext = &extensions[i];
311ad2c1a9aSJuan Castillo if (ext->opt && !strcmp(ext->opt, opt)) {
312ad2c1a9aSJuan Castillo return ext;
313ad2c1a9aSJuan Castillo }
314ad2c1a9aSJuan Castillo }
315ad2c1a9aSJuan Castillo
316ad2c1a9aSJuan Castillo return NULL;
317ad2c1a9aSJuan Castillo }
318*cf2dd17dSJuan Pablo Conde
ext_cleanup(void)319*cf2dd17dSJuan Pablo Conde void ext_cleanup(void)
320*cf2dd17dSJuan Pablo Conde {
321*cf2dd17dSJuan Pablo Conde unsigned int i;
322*cf2dd17dSJuan Pablo Conde
323*cf2dd17dSJuan Pablo Conde for (i = 0; i < num_extensions; i++) {
324*cf2dd17dSJuan Pablo Conde if (extensions[i].arg != NULL) {
325*cf2dd17dSJuan Pablo Conde void *ptr = (void *)extensions[i].arg;
326*cf2dd17dSJuan Pablo Conde
327*cf2dd17dSJuan Pablo Conde extensions[i].arg = NULL;
328*cf2dd17dSJuan Pablo Conde free(ptr);
329*cf2dd17dSJuan Pablo Conde }
330*cf2dd17dSJuan Pablo Conde }
331*cf2dd17dSJuan Pablo Conde free(extensions);
332*cf2dd17dSJuan Pablo Conde X509V3_EXT_cleanup();
333*cf2dd17dSJuan Pablo Conde }
334*cf2dd17dSJuan Pablo Conde
335