]>
Commit | Line | Data |
---|---|---|
e85d19c6 | 1 | /* |
7e06a675 | 2 | * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. |
e85d19c6 AI |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include <string.h> | |
11 | #include <openssl/x509v3.h> | |
12 | #include <openssl/err.h> | |
13 | #include <openssl/ess.h> | |
25f2138b | 14 | #include "crypto/ess.h" |
6725682d | 15 | #include "crypto/x509.h" |
e85d19c6 | 16 | |
852c2ed2 RS |
17 | DEFINE_STACK_OF(ESS_CERT_ID) |
18 | DEFINE_STACK_OF(ESS_CERT_ID_V2) | |
852c2ed2 | 19 | DEFINE_STACK_OF(GENERAL_NAME) |
9e3c510b | 20 | DEFINE_STACK_OF(X509) |
852c2ed2 | 21 | |
e85d19c6 AI |
22 | static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed); |
23 | static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg, | |
24 | X509 *cert, int issuer_needed); | |
25 | ||
26 | ESS_SIGNING_CERT *ESS_SIGNING_CERT_new_init(X509 *signcert, | |
27 | STACK_OF(X509) *certs, | |
28 | int issuer_needed) | |
29 | { | |
30 | ESS_CERT_ID *cid = NULL; | |
31 | ESS_SIGNING_CERT *sc; | |
32 | int i; | |
33 | ||
34 | if ((sc = ESS_SIGNING_CERT_new()) == NULL) | |
35 | goto err; | |
36 | if (sc->cert_ids == NULL | |
37 | && (sc->cert_ids = sk_ESS_CERT_ID_new_null()) == NULL) | |
38 | goto err; | |
39 | ||
40 | if ((cid = ESS_CERT_ID_new_init(signcert, issuer_needed)) == NULL | |
41 | || !sk_ESS_CERT_ID_push(sc->cert_ids, cid)) | |
42 | goto err; | |
43 | for (i = 0; i < sk_X509_num(certs); ++i) { | |
44 | X509 *cert = sk_X509_value(certs, i); | |
45 | if ((cid = ESS_CERT_ID_new_init(cert, 1)) == NULL | |
46 | || !sk_ESS_CERT_ID_push(sc->cert_ids, cid)) | |
47 | goto err; | |
48 | } | |
49 | ||
50 | return sc; | |
51 | err: | |
52 | ESS_SIGNING_CERT_free(sc); | |
53 | ESS_CERT_ID_free(cid); | |
54 | ESSerr(ESS_F_ESS_SIGNING_CERT_NEW_INIT, ERR_R_MALLOC_FAILURE); | |
55 | return NULL; | |
56 | } | |
57 | ||
58 | static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed) | |
59 | { | |
60 | ESS_CERT_ID *cid = NULL; | |
61 | GENERAL_NAME *name = NULL; | |
62 | unsigned char cert_sha1[SHA_DIGEST_LENGTH]; | |
63 | ||
64 | /* Call for side-effect of computing hash and caching extensions */ | |
6725682d | 65 | if (!x509v3_cache_extensions(cert)) |
9e3c510b F |
66 | return NULL; |
67 | ||
e85d19c6 AI |
68 | if ((cid = ESS_CERT_ID_new()) == NULL) |
69 | goto err; | |
9e3c510b | 70 | /* TODO(3.0): fetch sha1 algorithm from providers */ |
7e06a675 BE |
71 | if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL)) |
72 | goto err; | |
e85d19c6 AI |
73 | if (!ASN1_OCTET_STRING_set(cid->hash, cert_sha1, SHA_DIGEST_LENGTH)) |
74 | goto err; | |
75 | ||
76 | /* Setting the issuer/serial if requested. */ | |
77 | if (!issuer_needed) | |
78 | return cid; | |
79 | ||
80 | if (cid->issuer_serial == NULL | |
81 | && (cid->issuer_serial = ESS_ISSUER_SERIAL_new()) == NULL) | |
82 | goto err; | |
83 | if ((name = GENERAL_NAME_new()) == NULL) | |
84 | goto err; | |
85 | name->type = GEN_DIRNAME; | |
86 | if ((name->d.dirn = X509_NAME_dup(X509_get_issuer_name(cert))) == NULL) | |
87 | goto err; | |
88 | if (!sk_GENERAL_NAME_push(cid->issuer_serial->issuer, name)) | |
89 | goto err; | |
90 | name = NULL; /* Ownership is lost. */ | |
91 | ASN1_INTEGER_free(cid->issuer_serial->serial); | |
9e3c510b | 92 | if ((cid->issuer_serial->serial = |
1337a3a9 | 93 | ASN1_INTEGER_dup(X509_get0_serialNumber(cert))) == NULL) |
e85d19c6 AI |
94 | goto err; |
95 | ||
96 | return cid; | |
97 | err: | |
98 | GENERAL_NAME_free(name); | |
99 | ESS_CERT_ID_free(cid); | |
100 | ESSerr(ESS_F_ESS_CERT_ID_NEW_INIT, ERR_R_MALLOC_FAILURE); | |
101 | return NULL; | |
102 | } | |
103 | ||
104 | ESS_SIGNING_CERT_V2 *ESS_SIGNING_CERT_V2_new_init(const EVP_MD *hash_alg, | |
105 | X509 *signcert, | |
106 | STACK_OF(X509) *certs, | |
107 | int issuer_needed) | |
108 | { | |
109 | ESS_CERT_ID_V2 *cid = NULL; | |
110 | ESS_SIGNING_CERT_V2 *sc; | |
111 | int i; | |
112 | ||
113 | if ((sc = ESS_SIGNING_CERT_V2_new()) == NULL) | |
114 | goto err; | |
115 | if ((cid = ESS_CERT_ID_V2_new_init(hash_alg, signcert, issuer_needed)) == NULL) | |
116 | goto err; | |
117 | if (!sk_ESS_CERT_ID_V2_push(sc->cert_ids, cid)) | |
118 | goto err; | |
119 | cid = NULL; | |
120 | ||
121 | for (i = 0; i < sk_X509_num(certs); ++i) { | |
122 | X509 *cert = sk_X509_value(certs, i); | |
123 | ||
124 | if ((cid = ESS_CERT_ID_V2_new_init(hash_alg, cert, 1)) == NULL) | |
125 | goto err; | |
126 | if (!sk_ESS_CERT_ID_V2_push(sc->cert_ids, cid)) | |
127 | goto err; | |
128 | cid = NULL; | |
129 | } | |
130 | ||
131 | return sc; | |
132 | err: | |
133 | ESS_SIGNING_CERT_V2_free(sc); | |
134 | ESS_CERT_ID_V2_free(cid); | |
135 | ESSerr(ESS_F_ESS_SIGNING_CERT_V2_NEW_INIT, ERR_R_MALLOC_FAILURE); | |
136 | return NULL; | |
137 | } | |
138 | ||
139 | static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg, | |
140 | X509 *cert, int issuer_needed) | |
141 | { | |
142 | ESS_CERT_ID_V2 *cid; | |
143 | GENERAL_NAME *name = NULL; | |
144 | unsigned char hash[EVP_MAX_MD_SIZE]; | |
145 | unsigned int hash_len = sizeof(hash); | |
146 | X509_ALGOR *alg = NULL; | |
147 | ||
148 | memset(hash, 0, sizeof(hash)); | |
149 | ||
150 | if ((cid = ESS_CERT_ID_V2_new()) == NULL) | |
151 | goto err; | |
152 | ||
153 | if (hash_alg != EVP_sha256()) { | |
154 | alg = X509_ALGOR_new(); | |
155 | if (alg == NULL) | |
156 | goto err; | |
157 | X509_ALGOR_set_md(alg, hash_alg); | |
158 | if (alg->algorithm == NULL) | |
159 | goto err; | |
160 | cid->hash_alg = alg; | |
161 | alg = NULL; | |
162 | } else { | |
163 | cid->hash_alg = NULL; | |
164 | } | |
165 | ||
9e3c510b | 166 | /* TODO(3.0): fetch sha1 algorithm from providers */ |
e85d19c6 AI |
167 | if (!X509_digest(cert, hash_alg, hash, &hash_len)) |
168 | goto err; | |
169 | ||
170 | if (!ASN1_OCTET_STRING_set(cid->hash, hash, hash_len)) | |
171 | goto err; | |
172 | ||
173 | if (!issuer_needed) | |
174 | return cid; | |
175 | ||
176 | if ((cid->issuer_serial = ESS_ISSUER_SERIAL_new()) == NULL) | |
177 | goto err; | |
178 | if ((name = GENERAL_NAME_new()) == NULL) | |
179 | goto err; | |
180 | name->type = GEN_DIRNAME; | |
181 | if ((name->d.dirn = X509_NAME_dup(X509_get_issuer_name(cert))) == NULL) | |
182 | goto err; | |
183 | if (!sk_GENERAL_NAME_push(cid->issuer_serial->issuer, name)) | |
184 | goto err; | |
185 | name = NULL; /* Ownership is lost. */ | |
186 | ASN1_INTEGER_free(cid->issuer_serial->serial); | |
1337a3a9 | 187 | cid->issuer_serial->serial = ASN1_INTEGER_dup(X509_get0_serialNumber(cert)); |
e85d19c6 AI |
188 | if (cid->issuer_serial->serial == NULL) |
189 | goto err; | |
190 | ||
191 | return cid; | |
192 | err: | |
193 | X509_ALGOR_free(alg); | |
194 | GENERAL_NAME_free(name); | |
195 | ESS_CERT_ID_V2_free(cid); | |
196 | ESSerr(ESS_F_ESS_CERT_ID_V2_NEW_INIT, ERR_R_MALLOC_FAILURE); | |
197 | return NULL; | |
198 | } | |
199 | ||
200 | ESS_SIGNING_CERT *ESS_SIGNING_CERT_get(PKCS7_SIGNER_INFO *si) | |
201 | { | |
202 | ASN1_TYPE *attr; | |
203 | const unsigned char *p; | |
9e3c510b | 204 | |
e85d19c6 | 205 | attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate); |
9e3c510b | 206 | if (attr == NULL) |
e85d19c6 AI |
207 | return NULL; |
208 | p = attr->value.sequence->data; | |
209 | return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length); | |
210 | } | |
211 | ||
212 | ESS_SIGNING_CERT_V2 *ESS_SIGNING_CERT_V2_get(PKCS7_SIGNER_INFO *si) | |
213 | { | |
214 | ASN1_TYPE *attr; | |
215 | const unsigned char *p; | |
216 | ||
217 | attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificateV2); | |
218 | if (attr == NULL) | |
219 | return NULL; | |
220 | p = attr->value.sequence->data; | |
221 | return d2i_ESS_SIGNING_CERT_V2(NULL, &p, attr->value.sequence->length); | |
222 | } | |
223 | ||
224 | int ESS_SIGNING_CERT_add(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc) | |
225 | { | |
226 | ASN1_STRING *seq = NULL; | |
227 | unsigned char *p, *pp = NULL; | |
228 | int len; | |
229 | ||
230 | len = i2d_ESS_SIGNING_CERT(sc, NULL); | |
231 | if ((pp = OPENSSL_malloc(len)) == NULL) { | |
232 | ESSerr(ESS_F_ESS_SIGNING_CERT_ADD, ERR_R_MALLOC_FAILURE); | |
233 | goto err; | |
234 | } | |
235 | p = pp; | |
236 | i2d_ESS_SIGNING_CERT(sc, &p); | |
237 | if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) { | |
238 | ESSerr(ESS_F_ESS_SIGNING_CERT_ADD, ERR_R_MALLOC_FAILURE); | |
239 | goto err; | |
240 | } | |
241 | OPENSSL_free(pp); | |
242 | pp = NULL; | |
243 | return PKCS7_add_signed_attribute(si, | |
244 | NID_id_smime_aa_signingCertificate, | |
245 | V_ASN1_SEQUENCE, seq); | |
246 | err: | |
247 | ASN1_STRING_free(seq); | |
248 | OPENSSL_free(pp); | |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | int ESS_SIGNING_CERT_V2_add(PKCS7_SIGNER_INFO *si, | |
254 | ESS_SIGNING_CERT_V2 *sc) | |
255 | { | |
256 | ASN1_STRING *seq = NULL; | |
257 | unsigned char *p, *pp = NULL; | |
258 | int len = i2d_ESS_SIGNING_CERT_V2(sc, NULL); | |
259 | ||
260 | if ((pp = OPENSSL_malloc(len)) == NULL) { | |
261 | ESSerr(ESS_F_ESS_SIGNING_CERT_V2_ADD, ERR_R_MALLOC_FAILURE); | |
262 | goto err; | |
263 | } | |
264 | ||
265 | p = pp; | |
266 | i2d_ESS_SIGNING_CERT_V2(sc, &p); | |
267 | if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) { | |
268 | ESSerr(ESS_F_ESS_SIGNING_CERT_V2_ADD, ERR_R_MALLOC_FAILURE); | |
269 | goto err; | |
270 | } | |
271 | ||
272 | OPENSSL_free(pp); | |
273 | pp = NULL; | |
274 | return PKCS7_add_signed_attribute(si, | |
275 | NID_id_smime_aa_signingCertificateV2, | |
276 | V_ASN1_SEQUENCE, seq); | |
277 | err: | |
278 | ASN1_STRING_free(seq); | |
279 | OPENSSL_free(pp); | |
280 | return 0; | |
281 | } | |
9e3c510b F |
282 | |
283 | static int ess_issuer_serial_cmp(const ESS_ISSUER_SERIAL *is, const X509 *cert) | |
284 | { | |
285 | GENERAL_NAME *issuer; | |
286 | ||
287 | if (is == NULL || cert == NULL || sk_GENERAL_NAME_num(is->issuer) != 1) | |
288 | return -1; | |
289 | ||
290 | issuer = sk_GENERAL_NAME_value(is->issuer, 0); | |
291 | if (issuer->type != GEN_DIRNAME | |
292 | || X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert)) != 0) | |
293 | return -1; | |
294 | ||
295 | return ASN1_INTEGER_cmp(is->serial, X509_get0_serialNumber(cert)); | |
296 | } | |
297 | ||
298 | /* Returns < 0 if certificate is not found, certificate index otherwise. */ | |
299 | int ess_find_cert(const STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert) | |
300 | { | |
301 | int i; | |
302 | unsigned char cert_sha1[SHA_DIGEST_LENGTH]; | |
303 | ||
304 | if (cert_ids == NULL || cert == NULL) | |
305 | return -1; | |
306 | ||
307 | /* Recompute SHA1 hash of certificate if necessary (side effect). */ | |
6725682d | 308 | if (!x509v3_cache_extensions(cert)) |
9e3c510b F |
309 | return -1; |
310 | ||
311 | /* TODO(3.0): fetch sha1 algorithm from providers */ | |
312 | if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL)) | |
313 | return -1; | |
314 | ||
315 | /* Look for cert in the cert_ids vector. */ | |
316 | for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) { | |
317 | const ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i); | |
318 | ||
319 | if (cid->hash->length == SHA_DIGEST_LENGTH | |
320 | && memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) { | |
321 | const ESS_ISSUER_SERIAL *is = cid->issuer_serial; | |
322 | ||
323 | if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0) | |
324 | return i; | |
325 | } | |
326 | } | |
327 | ||
328 | return -1; | |
329 | } | |
330 | ||
331 | /* Returns < 0 if certificate is not found, certificate index otherwise. */ | |
332 | int ess_find_cert_v2(const STACK_OF(ESS_CERT_ID_V2) *cert_ids, const X509 *cert) | |
333 | { | |
334 | int i; | |
335 | unsigned char cert_digest[EVP_MAX_MD_SIZE]; | |
336 | unsigned int len; | |
337 | ||
338 | /* Look for cert in the cert_ids vector. */ | |
339 | for (i = 0; i < sk_ESS_CERT_ID_V2_num(cert_ids); ++i) { | |
340 | const ESS_CERT_ID_V2 *cid = sk_ESS_CERT_ID_V2_value(cert_ids, i); | |
341 | const EVP_MD *md; | |
342 | ||
5999d20e SL |
343 | if (cid == NULL) |
344 | return -1; | |
345 | if (cid->hash_alg != NULL) | |
9e3c510b F |
346 | md = EVP_get_digestbyobj(cid->hash_alg->algorithm); |
347 | else | |
348 | md = EVP_sha256(); | |
349 | ||
350 | /* TODO(3.0): fetch sha1 algorithm from providers */ | |
351 | if (!X509_digest(cert, md, cert_digest, &len)) | |
352 | return -1; | |
353 | ||
354 | if (cid->hash->length != (int)len) | |
355 | return -1; | |
356 | ||
357 | if (memcmp(cid->hash->data, cert_digest, cid->hash->length) == 0) { | |
358 | const ESS_ISSUER_SERIAL *is = cid->issuer_serial; | |
359 | ||
360 | if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0) | |
361 | return i; | |
362 | } | |
363 | } | |
364 | ||
365 | return -1; | |
366 | } |