1 /* $OpenBSD: ct_sct_ctx.c,v 1.6 2022/06/30 11:14:47 tb Exp $ */
2 /*
3 * Written by Rob Stradling (rob@comodo.com) and Stephen Henson
4 * (steve@openssl.org) for the OpenSSL project 2014.
5 */
6 /* ====================================================================
7 * Copyright (c) 2014 The OpenSSL Project. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 * software must display the following acknowledgment:
23 * "This product includes software developed by the OpenSSL Project
24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For written permission, please contact
29 * licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 * nor may "OpenSSL" appear in their names without prior written
33 * permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 * acknowledgment:
37 * "This product includes software developed by the OpenSSL Project
38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com). This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60 #ifdef OPENSSL_NO_CT
61 # error "CT is disabled"
62 #endif
63
64 #include <stddef.h>
65 #include <string.h>
66
67 #include <openssl/err.h>
68 #include <openssl/objects.h>
69 #include <openssl/x509.h>
70
71 #include "ct_local.h"
72
73 SCT_CTX *
SCT_CTX_new(void)74 SCT_CTX_new(void)
75 {
76 SCT_CTX *sctx = calloc(1, sizeof(*sctx));
77
78 if (sctx == NULL)
79 CTerror(ERR_R_MALLOC_FAILURE);
80
81 return sctx;
82 }
83
84 void
SCT_CTX_free(SCT_CTX * sctx)85 SCT_CTX_free(SCT_CTX *sctx)
86 {
87 if (sctx == NULL)
88 return;
89 EVP_PKEY_free(sctx->pkey);
90 free(sctx->pkeyhash);
91 free(sctx->ihash);
92 free(sctx->certder);
93 free(sctx->preder);
94 free(sctx);
95 }
96
97 /*
98 * Finds the index of the first extension with the given NID in cert.
99 * If there is more than one extension with that NID, *is_duplicated is set to
100 * 1, otherwise 0 (unless it is NULL).
101 */
102 static int
ct_x509_get_ext(X509 * cert,int nid,int * is_duplicated)103 ct_x509_get_ext(X509 *cert, int nid, int *is_duplicated)
104 {
105 int ret = X509_get_ext_by_NID(cert, nid, -1);
106
107 if (is_duplicated != NULL)
108 *is_duplicated = ret >= 0 &&
109 X509_get_ext_by_NID(cert, nid, ret) >= 0;
110
111 return ret;
112 }
113
114 /*
115 * Modifies a certificate by deleting extensions and copying the issuer and
116 * AKID from the presigner certificate, if necessary.
117 * Returns 1 on success, 0 otherwise.
118 */
119 static int
ct_x509_cert_fixup(X509 * cert,X509 * presigner)120 ct_x509_cert_fixup(X509 *cert, X509 *presigner)
121 {
122 int preidx, certidx;
123 int pre_akid_ext_is_dup, cert_akid_ext_is_dup;
124
125 if (presigner == NULL)
126 return 1;
127
128 preidx = ct_x509_get_ext(presigner, NID_authority_key_identifier,
129 &pre_akid_ext_is_dup);
130 certidx = ct_x509_get_ext(cert, NID_authority_key_identifier,
131 &cert_akid_ext_is_dup);
132
133 /* An error occurred whilst searching for the extension */
134 if (preidx < -1 || certidx < -1)
135 return 0;
136 /* Invalid certificate if they contain duplicate extensions */
137 if (pre_akid_ext_is_dup || cert_akid_ext_is_dup)
138 return 0;
139 /* AKID must be present in both certificate or absent in both */
140 if (preidx >= 0 && certidx == -1)
141 return 0;
142 if (preidx == -1 && certidx >= 0)
143 return 0;
144 /* Copy issuer name */
145 if (!X509_set_issuer_name(cert, X509_get_issuer_name(presigner)))
146 return 0;
147 if (preidx != -1) {
148 /* Retrieve and copy AKID encoding */
149 X509_EXTENSION *preext = X509_get_ext(presigner, preidx);
150 X509_EXTENSION *certext = X509_get_ext(cert, certidx);
151 ASN1_OCTET_STRING *preextdata;
152
153 /* Should never happen */
154 if (preext == NULL || certext == NULL)
155 return 0;
156 preextdata = X509_EXTENSION_get_data(preext);
157 if (preextdata == NULL ||
158 !X509_EXTENSION_set_data(certext, preextdata))
159 return 0;
160 }
161 return 1;
162 }
163
164 int
SCT_CTX_set1_cert(SCT_CTX * sctx,X509 * cert,X509 * presigner)165 SCT_CTX_set1_cert(SCT_CTX *sctx, X509 *cert, X509 *presigner)
166 {
167 unsigned char *certder = NULL, *preder = NULL;
168 X509 *pretmp = NULL;
169 int certderlen = 0, prederlen = 0;
170 int idx = -1;
171 int poison_ext_is_dup, sct_ext_is_dup;
172 int poison_idx = ct_x509_get_ext(cert, NID_ct_precert_poison, &poison_ext_is_dup);
173
174 /* Duplicate poison extensions are present - error */
175 if (poison_ext_is_dup)
176 goto err;
177
178 /* If *cert doesn't have a poison extension, it isn't a precert */
179 if (poison_idx == -1) {
180 /* cert isn't a precert, so we shouldn't have a presigner */
181 if (presigner != NULL)
182 goto err;
183
184 certderlen = i2d_X509(cert, &certder);
185 if (certderlen < 0)
186 goto err;
187 }
188
189 /* See if cert has a precert SCTs extension */
190 idx = ct_x509_get_ext(cert, NID_ct_precert_scts, &sct_ext_is_dup);
191 /* Duplicate SCT extensions are present - error */
192 if (sct_ext_is_dup)
193 goto err;
194
195 if (idx >= 0 && poison_idx >= 0) {
196 /*
197 * cert can't both contain SCTs (i.e. have an SCT extension) and be a
198 * precert (i.e. have a poison extension).
199 */
200 goto err;
201 }
202
203 if (idx == -1) {
204 idx = poison_idx;
205 }
206
207 /*
208 * If either a poison or SCT extension is present, remove it before encoding
209 * cert. This, along with ct_x509_cert_fixup(), gets a TBSCertificate (see
210 * RFC5280) from cert, which is what the CT log signed when it produced the
211 * SCT.
212 */
213 if (idx >= 0) {
214 X509_EXTENSION *ext;
215
216 /* Take a copy of certificate so we don't modify passed version */
217 pretmp = X509_dup(cert);
218 if (pretmp == NULL)
219 goto err;
220
221 ext = X509_delete_ext(pretmp, idx);
222 X509_EXTENSION_free(ext);
223
224 if (!ct_x509_cert_fixup(pretmp, presigner))
225 goto err;
226
227 prederlen = i2d_re_X509_tbs(pretmp, &preder);
228 if (prederlen <= 0)
229 goto err;
230 }
231
232 X509_free(pretmp);
233
234 free(sctx->certder);
235 sctx->certder = certder;
236 sctx->certderlen = certderlen;
237
238 free(sctx->preder);
239 sctx->preder = preder;
240 sctx->prederlen = prederlen;
241
242 return 1;
243 err:
244 free(certder);
245 free(preder);
246 X509_free(pretmp);
247 return 0;
248 }
249
250 static int
ct_public_key_hash(X509_PUBKEY * pkey,unsigned char ** hash,size_t * hash_len)251 ct_public_key_hash(X509_PUBKEY *pkey, unsigned char **hash, size_t *hash_len)
252 {
253 int ret = 0;
254 unsigned char *md = NULL, *der = NULL;
255 int der_len;
256 unsigned int md_len;
257
258 /* Reuse buffer if possible */
259 if (*hash != NULL && *hash_len >= SHA256_DIGEST_LENGTH) {
260 md = *hash;
261 } else {
262 md = malloc(SHA256_DIGEST_LENGTH);
263 if (md == NULL)
264 goto err;
265 }
266
267 /* Calculate key hash */
268 der_len = i2d_X509_PUBKEY(pkey, &der);
269 if (der_len <= 0)
270 goto err;
271
272 if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha256(), NULL))
273 goto err;
274
275 if (md != *hash) {
276 free(*hash);
277 *hash = md;
278 *hash_len = SHA256_DIGEST_LENGTH;
279 }
280
281 md = NULL;
282 ret = 1;
283 err:
284 free(md);
285 free(der);
286 return ret;
287 }
288
289 int
SCT_CTX_set1_issuer(SCT_CTX * sctx,const X509 * issuer)290 SCT_CTX_set1_issuer(SCT_CTX *sctx, const X509 *issuer)
291 {
292 return SCT_CTX_set1_issuer_pubkey(sctx, X509_get_X509_PUBKEY(issuer));
293 }
294
295 int
SCT_CTX_set1_issuer_pubkey(SCT_CTX * sctx,X509_PUBKEY * pubkey)296 SCT_CTX_set1_issuer_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey)
297 {
298 return ct_public_key_hash(pubkey, &sctx->ihash, &sctx->ihashlen);
299 }
300
301 int
SCT_CTX_set1_pubkey(SCT_CTX * sctx,X509_PUBKEY * pubkey)302 SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey)
303 {
304 EVP_PKEY *pkey = X509_PUBKEY_get(pubkey);
305
306 if (pkey == NULL)
307 return 0;
308
309 if (!ct_public_key_hash(pubkey, &sctx->pkeyhash, &sctx->pkeyhashlen)) {
310 EVP_PKEY_free(pkey);
311 return 0;
312 }
313
314 EVP_PKEY_free(sctx->pkey);
315 sctx->pkey = pkey;
316 return 1;
317 }
318
319 void
SCT_CTX_set_time(SCT_CTX * sctx,uint64_t time_in_ms)320 SCT_CTX_set_time(SCT_CTX *sctx, uint64_t time_in_ms)
321 {
322 sctx->epoch_time_in_ms = time_in_ms;
323 }
324