xref: /rk3399_ARM-atf/tools/cert_create/src/cert.c (revision 51faada71a219a8b94cd8d8e423f0f22e9da4d8f)
1 /*
2  * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <openssl/conf.h>
36 #include <openssl/err.h>
37 #include <openssl/pem.h>
38 #include <openssl/sha.h>
39 #include <openssl/x509v3.h>
40 
41 #include "cert.h"
42 #include "cmd_opt.h"
43 #include "debug.h"
44 #include "key.h"
45 #include "platform_oid.h"
46 #include "sha.h"
47 
48 #define SERIAL_RAND_BITS	64
49 
50 int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
51 {
52 	BIGNUM *btmp;
53 	int ret = 0;
54 	if (b)
55 		btmp = b;
56 	else
57 		btmp = BN_new();
58 
59 	if (!btmp)
60 		return 0;
61 
62 	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
63 		goto error;
64 	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
65 		goto error;
66 
67 	ret = 1;
68 
69 error:
70 
71 	if (!b)
72 		BN_free(btmp);
73 
74 	return ret;
75 }
76 
77 int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
78 {
79 	X509_EXTENSION *ex;
80 	X509V3_CTX ctx;
81 
82 	/* No configuration database */
83 	X509V3_set_ctx_nodb(&ctx);
84 
85 	/* Set issuer and subject certificates in the context */
86 	X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
87 	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
88 	if (!ex) {
89 		ERR_print_errors_fp(stdout);
90 		return 0;
91 	}
92 
93 	X509_add_ext(subject, ex, -1);
94 	X509_EXTENSION_free(ex);
95 
96 	return 1;
97 }
98 
99 
100 int cert_new(cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk)
101 {
102 	EVP_PKEY *pkey = keys[cert->key].key;
103 	cert_t *issuer_cert = &certs[cert->issuer];
104 	EVP_PKEY *ikey = keys[issuer_cert->key].key;
105 	X509 *issuer = issuer_cert->x;
106 	X509 *x;
107 	X509_EXTENSION *ex;
108 	X509_NAME *name;
109 	ASN1_INTEGER *sno;
110 	int i, num;
111 
112 	/* Create the certificate structure */
113 	x = X509_new();
114 	if (!x) {
115 		return 0;
116 	}
117 
118 	/* If we do not have a key, use the issuer key (the certificate will
119 	 * become self signed). This happens in content certificates. */
120 	if (!pkey) {
121 		pkey = ikey;
122 	}
123 
124 	/* If we do not have an issuer certificate, use our own (the certificate
125 	 * will become self signed) */
126 	if (!issuer) {
127 		issuer = x;
128 	}
129 
130 	/* x509.v3 */
131 	X509_set_version(x, 2);
132 
133 	/* Random serial number */
134 	sno = ASN1_INTEGER_new();
135 	rand_serial(NULL, sno);
136 	X509_set_serialNumber(x, sno);
137 	ASN1_INTEGER_free(sno);
138 
139 	X509_gmtime_adj(X509_get_notBefore(x), 0);
140 	X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
141 	X509_set_pubkey(x, pkey);
142 
143 	/* Subject name */
144 	name = X509_get_subject_name(x);
145 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
146 			(const unsigned char *)cert->cn, -1, -1, 0);
147 	X509_set_subject_name(x, name);
148 
149 	/* Issuer name */
150 	name = X509_get_issuer_name(x);
151 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
152 			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
153 	X509_set_issuer_name(x, name);
154 
155 	/* Add various extensions: standard extensions */
156 	cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
157 	cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
158 	if (ca) {
159 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
160 		cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
161 	} else {
162 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
163 	}
164 
165 	/* Add custom extensions */
166 	if (sk != NULL) {
167 		num = sk_X509_EXTENSION_num(sk);
168 		for (i = 0; i < num; i++) {
169 			ex = sk_X509_EXTENSION_value(sk, i);
170 			X509_add_ext(x, ex, -1);
171 		}
172 	}
173 
174 	/* Sign the certificate with the issuer key */
175 	if (!X509_sign(x, ikey, EVP_sha256())) {
176 		ERR_print_errors_fp(stdout);
177 		return 0;
178 	}
179 
180 	cert->x = x;
181 	return 1;
182 }
183 
184 int cert_init(void)
185 {
186 	cmd_opt_t cmd_opt;
187 	cert_t *cert;
188 	unsigned int i;
189 
190 	for (i = 0; i < num_certs; i++) {
191 		cert = &certs[i];
192 		cmd_opt.long_opt.name = cert->opt;
193 		cmd_opt.long_opt.has_arg = required_argument;
194 		cmd_opt.long_opt.flag = NULL;
195 		cmd_opt.long_opt.val = CMD_OPT_CERT;
196 		cmd_opt.help_msg = cert->help_msg;
197 		cmd_opt_add(&cmd_opt);
198 	}
199 
200 	return 0;
201 }
202 
203 cert_t *cert_get_by_opt(const char *opt)
204 {
205 	cert_t *cert;
206 	unsigned int i;
207 
208 	for (i = 0; i < num_certs; i++) {
209 		cert = &certs[i];
210 		if (0 == strcmp(cert->opt, opt)) {
211 			return cert;
212 		}
213 	}
214 
215 	return NULL;
216 }
217