blob: bf526451388afc2650ae869e2f15fc3ec4b23a7e [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
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"
Juan Castillo1218dd52015-07-03 16:23:16 +010042#include "cmd_opt.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010043#include "debug.h"
44#include "key.h"
45#include "platform_oid.h"
46#include "sha.h"
47
48#define SERIAL_RAND_BITS 64
49
50int 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
69error:
70
71 if (!b)
72 BN_free(btmp);
73
74 return ret;
75}
76
77int 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
100int cert_new(cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk)
101{
Juan Castilloe6d30e92015-06-12 11:27:59 +0100102 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;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100106 X509 *x = NULL;
107 X509_EXTENSION *ex = NULL;
108 X509_NAME *name = NULL;
109 ASN1_INTEGER *sno = NULL;
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,
Juan Castilloe6d30e92015-06-12 11:27:59 +0100152 (const unsigned char *)issuer_cert->cn, -1, -1, 0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100153 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 */
Juan Castillo271a5ac2015-02-16 10:34:28 +0000175 if (!X509_sign(x, ikey, EVP_sha256())) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100176 ERR_print_errors_fp(stdout);
177 return 0;
178 }
179
180 cert->x = x;
181 return 1;
182}
Juan Castillo1218dd52015-07-03 16:23:16 +0100183
184int cert_init(void)
185{
186 cert_t *cert;
187 int rc = 0;
188 unsigned int i;
189
190 for (i = 0; i < num_certs; i++) {
191 cert = &certs[i];
192 rc = cmd_opt_add(cert->opt, required_argument, CMD_OPT_CERT);
193 if (rc != 0) {
194 break;
195 }
196 }
197
198 return rc;
199}
200
201cert_t *cert_get_by_opt(const char *opt)
202{
203 cert_t *cert = NULL;
204 unsigned int i;
205
206 for (i = 0; i < num_certs; i++) {
207 cert = &certs[i];
208 if (0 == strcmp(cert->opt, opt)) {
209 return cert;
210 }
211 }
212
213 return NULL;
214}