]>
Commit | Line | Data |
---|---|---|
62867571 | 1 | /* |
454afd98 | 2 | * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
b7617a3a | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
62867571 RS |
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 | |
d02b48c6 RE |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
ec577822 BM |
12 | #include <openssl/rand.h> |
13 | #include <openssl/objects.h> | |
14 | #include <openssl/x509.h> | |
5a9a4b29 | 15 | #include <openssl/x509v3.h> |
8f2e4fdf | 16 | #include <openssl/err.h> |
90a1f2d7 | 17 | #include "pk7_local.h" |
d02b48c6 | 18 | |
b6436ff2 | 19 | static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, |
0f113f3e | 20 | void *value); |
b6436ff2 | 21 | static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid); |
dfeab068 | 22 | |
0f113f3e MC |
23 | static int PKCS7_type_is_other(PKCS7 *p7) |
24 | { | |
25 | int isOther = 1; | |
26 | ||
27 | int nid = OBJ_obj2nid(p7->type); | |
28 | ||
29 | switch (nid) { | |
30 | case NID_pkcs7_data: | |
31 | case NID_pkcs7_signed: | |
32 | case NID_pkcs7_enveloped: | |
33 | case NID_pkcs7_signedAndEnveloped: | |
34 | case NID_pkcs7_digest: | |
35 | case NID_pkcs7_encrypted: | |
36 | isOther = 0; | |
37 | break; | |
38 | default: | |
39 | isOther = 1; | |
40 | } | |
41 | ||
42 | return isOther; | |
43 | ||
44 | } | |
67fec850 | 45 | |
caf044cb | 46 | static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) |
0f113f3e MC |
47 | { |
48 | if (PKCS7_type_is_data(p7)) | |
49 | return p7->d.data; | |
50 | if (PKCS7_type_is_other(p7) && p7->d.other | |
51 | && (p7->d.other->type == V_ASN1_OCTET_STRING)) | |
52 | return p7->d.other->value.octet_string; | |
53 | return NULL; | |
54 | } | |
67fec850 | 55 | |
90a1f2d7 SL |
56 | static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg, |
57 | const PKCS7_CTX *ctx) | |
0f113f3e MC |
58 | { |
59 | BIO *btmp; | |
90a1f2d7 SL |
60 | const char *name; |
61 | EVP_MD *fetched = NULL; | |
bd1bbbfe | 62 | const EVP_MD *md; |
90a1f2d7 | 63 | |
0f113f3e MC |
64 | if ((btmp = BIO_new(BIO_f_md())) == NULL) { |
65 | PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB); | |
66 | goto err; | |
67 | } | |
68 | ||
90a1f2d7 | 69 | name = OBJ_nid2sn(OBJ_obj2nid(alg->algorithm)); |
bd1bbbfe DB |
70 | |
71 | (void)ERR_set_mark(); | |
90a1f2d7 | 72 | fetched = EVP_MD_fetch(ctx->libctx, name, ctx->propq); |
bd1bbbfe DB |
73 | if (fetched != NULL) |
74 | md = fetched; | |
75 | else | |
76 | md = EVP_get_digestbyname(name); | |
77 | ||
78 | if (md == NULL) { | |
79 | (void)ERR_clear_last_mark(); | |
0f113f3e MC |
80 | PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, PKCS7_R_UNKNOWN_DIGEST_TYPE); |
81 | goto err; | |
82 | } | |
bd1bbbfe | 83 | (void)ERR_pop_to_mark(); |
0f113f3e | 84 | |
bd1bbbfe | 85 | BIO_set_md(btmp, md); |
90a1f2d7 | 86 | EVP_MD_free(fetched); |
0f113f3e MC |
87 | if (*pbio == NULL) |
88 | *pbio = btmp; | |
89 | else if (!BIO_push(*pbio, btmp)) { | |
90 | PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB); | |
91 | goto err; | |
92 | } | |
93 | btmp = NULL; | |
94 | ||
95 | return 1; | |
96 | ||
97 | err: | |
ca3a82c3 | 98 | BIO_free(btmp); |
0f113f3e | 99 | return 0; |
0f113f3e | 100 | } |
399a6f0b | 101 | |
0f113f3e MC |
102 | static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, |
103 | unsigned char *key, int keylen) | |
104 | { | |
105 | EVP_PKEY_CTX *pctx = NULL; | |
106 | EVP_PKEY *pkey = NULL; | |
107 | unsigned char *ek = NULL; | |
108 | int ret = 0; | |
109 | size_t eklen; | |
90a1f2d7 | 110 | const PKCS7_CTX *ctx = ri->ctx; |
399a6f0b | 111 | |
8382fd3a | 112 | pkey = X509_get0_pubkey(ri->cert); |
12a765a5 | 113 | if (pkey == NULL) |
0f113f3e | 114 | return 0; |
399a6f0b | 115 | |
90a1f2d7 | 116 | pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkey, ctx->propq); |
12a765a5 | 117 | if (pctx == NULL) |
0f113f3e | 118 | return 0; |
399a6f0b | 119 | |
0f113f3e MC |
120 | if (EVP_PKEY_encrypt_init(pctx) <= 0) |
121 | goto err; | |
399a6f0b | 122 | |
0f113f3e MC |
123 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT, |
124 | EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0) { | |
125 | PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR); | |
126 | goto err; | |
127 | } | |
399a6f0b | 128 | |
0f113f3e MC |
129 | if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) |
130 | goto err; | |
399a6f0b | 131 | |
0f113f3e | 132 | ek = OPENSSL_malloc(eklen); |
399a6f0b | 133 | |
0f113f3e MC |
134 | if (ek == NULL) { |
135 | PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE); | |
136 | goto err; | |
137 | } | |
399a6f0b | 138 | |
0f113f3e MC |
139 | if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) |
140 | goto err; | |
399a6f0b | 141 | |
0f113f3e MC |
142 | ASN1_STRING_set0(ri->enc_key, ek, eklen); |
143 | ek = NULL; | |
399a6f0b | 144 | |
0f113f3e | 145 | ret = 1; |
399a6f0b | 146 | |
0f113f3e | 147 | err: |
c5ba2d99 | 148 | EVP_PKEY_CTX_free(pctx); |
b548a1f1 | 149 | OPENSSL_free(ek); |
0f113f3e | 150 | return ret; |
399a6f0b | 151 | |
0f113f3e | 152 | } |
399a6f0b | 153 | |
777c47ac | 154 | static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, |
5840ed0c BE |
155 | PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey, |
156 | size_t fixlen) | |
0f113f3e MC |
157 | { |
158 | EVP_PKEY_CTX *pctx = NULL; | |
159 | unsigned char *ek = NULL; | |
160 | size_t eklen; | |
0f113f3e | 161 | int ret = -1; |
90a1f2d7 | 162 | const PKCS7_CTX *ctx = ri->ctx; |
0f113f3e | 163 | |
90a1f2d7 | 164 | pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkey, ctx->propq); |
12a765a5 | 165 | if (pctx == NULL) |
0f113f3e MC |
166 | return -1; |
167 | ||
168 | if (EVP_PKEY_decrypt_init(pctx) <= 0) | |
169 | goto err; | |
170 | ||
171 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT, | |
172 | EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0) { | |
173 | PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR); | |
174 | goto err; | |
175 | } | |
176 | ||
177 | if (EVP_PKEY_decrypt(pctx, NULL, &eklen, | |
178 | ri->enc_key->data, ri->enc_key->length) <= 0) | |
179 | goto err; | |
180 | ||
181 | ek = OPENSSL_malloc(eklen); | |
182 | ||
183 | if (ek == NULL) { | |
184 | PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE); | |
185 | goto err; | |
186 | } | |
187 | ||
188 | if (EVP_PKEY_decrypt(pctx, ek, &eklen, | |
5840ed0c BE |
189 | ri->enc_key->data, ri->enc_key->length) <= 0 |
190 | || eklen == 0 | |
191 | || (fixlen != 0 && eklen != fixlen)) { | |
0f113f3e MC |
192 | ret = 0; |
193 | PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB); | |
194 | goto err; | |
195 | } | |
196 | ||
197 | ret = 1; | |
198 | ||
4b45c6e5 | 199 | OPENSSL_clear_free(*pek, *peklen); |
0f113f3e MC |
200 | *pek = ek; |
201 | *peklen = eklen; | |
202 | ||
203 | err: | |
c5ba2d99 | 204 | EVP_PKEY_CTX_free(pctx); |
b548a1f1 | 205 | if (!ret) |
0f113f3e MC |
206 | OPENSSL_free(ek); |
207 | ||
208 | return ret; | |
209 | } | |
399a6f0b | 210 | |
6b691a5c | 211 | BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) |
0f113f3e MC |
212 | { |
213 | int i; | |
214 | BIO *out = NULL, *btmp = NULL; | |
215 | X509_ALGOR *xa = NULL; | |
90a1f2d7 | 216 | EVP_CIPHER *fetched_cipher = NULL; |
835b2900 | 217 | const EVP_CIPHER *cipher; |
0f113f3e MC |
218 | const EVP_CIPHER *evp_cipher = NULL; |
219 | STACK_OF(X509_ALGOR) *md_sk = NULL; | |
220 | STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL; | |
221 | X509_ALGOR *xalg = NULL; | |
222 | PKCS7_RECIP_INFO *ri = NULL; | |
223 | ASN1_OCTET_STRING *os = NULL; | |
90a1f2d7 | 224 | const PKCS7_CTX *p7_ctx; |
0f113f3e | 225 | |
c225c3cf EK |
226 | if (p7 == NULL) { |
227 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER); | |
228 | return NULL; | |
229 | } | |
90a1f2d7 SL |
230 | p7_ctx = pkcs7_get0_ctx(p7); |
231 | ||
c225c3cf EK |
232 | /* |
233 | * The content field in the PKCS7 ContentInfo is optional, but that really | |
234 | * only applies to inner content (precisely, detached signatures). | |
235 | * | |
236 | * When reading content, missing outer content is therefore treated as an | |
237 | * error. | |
238 | * | |
239 | * When creating content, PKCS7_content_new() must be called before | |
240 | * calling this method, so a NULL p7->d is always an error. | |
241 | */ | |
242 | if (p7->d.ptr == NULL) { | |
243 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT); | |
244 | return NULL; | |
245 | } | |
246 | ||
0f113f3e MC |
247 | i = OBJ_obj2nid(p7->type); |
248 | p7->state = PKCS7_S_HEADER; | |
249 | ||
250 | switch (i) { | |
251 | case NID_pkcs7_signed: | |
252 | md_sk = p7->d.sign->md_algs; | |
253 | os = PKCS7_get_octet_string(p7->d.sign->contents); | |
254 | break; | |
255 | case NID_pkcs7_signedAndEnveloped: | |
256 | rsk = p7->d.signed_and_enveloped->recipientinfo; | |
257 | md_sk = p7->d.signed_and_enveloped->md_algs; | |
258 | xalg = p7->d.signed_and_enveloped->enc_data->algorithm; | |
259 | evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher; | |
260 | if (evp_cipher == NULL) { | |
261 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); | |
262 | goto err; | |
263 | } | |
264 | break; | |
265 | case NID_pkcs7_enveloped: | |
266 | rsk = p7->d.enveloped->recipientinfo; | |
267 | xalg = p7->d.enveloped->enc_data->algorithm; | |
268 | evp_cipher = p7->d.enveloped->enc_data->cipher; | |
269 | if (evp_cipher == NULL) { | |
270 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED); | |
271 | goto err; | |
272 | } | |
273 | break; | |
274 | case NID_pkcs7_digest: | |
275 | xa = p7->d.digest->md; | |
276 | os = PKCS7_get_octet_string(p7->d.digest->contents); | |
277 | break; | |
278 | case NID_pkcs7_data: | |
279 | break; | |
280 | default: | |
281 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); | |
282 | goto err; | |
283 | } | |
284 | ||
285 | for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) | |
90a1f2d7 | 286 | if (!pkcs7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i), p7_ctx)) |
0f113f3e MC |
287 | goto err; |
288 | ||
90a1f2d7 | 289 | if (xa && !pkcs7_bio_add_digest(&out, xa, p7_ctx)) |
0f113f3e MC |
290 | goto err; |
291 | ||
292 | if (evp_cipher != NULL) { | |
293 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
294 | unsigned char iv[EVP_MAX_IV_LENGTH]; | |
295 | int keylen, ivlen; | |
296 | EVP_CIPHER_CTX *ctx; | |
297 | ||
298 | if ((btmp = BIO_new(BIO_f_cipher())) == NULL) { | |
299 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, ERR_R_BIO_LIB); | |
300 | goto err; | |
301 | } | |
302 | BIO_get_cipher_ctx(btmp, &ctx); | |
303 | keylen = EVP_CIPHER_key_length(evp_cipher); | |
304 | ivlen = EVP_CIPHER_iv_length(evp_cipher); | |
305 | xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); | |
306 | if (ivlen > 0) | |
90a1f2d7 | 307 | if (RAND_bytes_ex(p7_ctx->libctx, iv, ivlen) <= 0) |
0f113f3e | 308 | goto err; |
90a1f2d7 | 309 | |
835b2900 | 310 | (void)ERR_set_mark(); |
90a1f2d7 SL |
311 | fetched_cipher = EVP_CIPHER_fetch(p7_ctx->libctx, |
312 | EVP_CIPHER_name(evp_cipher), | |
313 | p7_ctx->propq); | |
0f0b7dfb | 314 | (void)ERR_pop_to_mark(); |
835b2900 DB |
315 | if (fetched_cipher != NULL) |
316 | cipher = fetched_cipher; | |
317 | else | |
318 | cipher = evp_cipher; | |
319 | ||
835b2900 | 320 | if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 1) <= 0) |
90a1f2d7 SL |
321 | goto err; |
322 | ||
323 | EVP_CIPHER_free(fetched_cipher); | |
324 | fetched_cipher = NULL; | |
325 | ||
0f113f3e MC |
326 | if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) |
327 | goto err; | |
328 | if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) | |
329 | goto err; | |
330 | ||
331 | if (ivlen > 0) { | |
332 | if (xalg->parameter == NULL) { | |
333 | xalg->parameter = ASN1_TYPE_new(); | |
334 | if (xalg->parameter == NULL) | |
335 | goto err; | |
336 | } | |
337 | if (EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0) | |
338 | goto err; | |
339 | } | |
340 | ||
341 | /* Lets do the pub key stuff :-) */ | |
342 | for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { | |
343 | ri = sk_PKCS7_RECIP_INFO_value(rsk, i); | |
344 | if (pkcs7_encode_rinfo(ri, key, keylen) <= 0) | |
345 | goto err; | |
346 | } | |
347 | OPENSSL_cleanse(key, keylen); | |
348 | ||
349 | if (out == NULL) | |
350 | out = btmp; | |
351 | else | |
352 | BIO_push(out, btmp); | |
353 | btmp = NULL; | |
354 | } | |
355 | ||
356 | if (bio == NULL) { | |
4718f449 | 357 | if (PKCS7_is_detached(p7)) { |
0f113f3e | 358 | bio = BIO_new(BIO_s_null()); |
4718f449 | 359 | } else if (os && os->length > 0) { |
0f113f3e | 360 | bio = BIO_new_mem_buf(os->data, os->length); |
4718f449 | 361 | } else { |
0f113f3e MC |
362 | bio = BIO_new(BIO_s_mem()); |
363 | if (bio == NULL) | |
364 | goto err; | |
365 | BIO_set_mem_eof_return(bio, 0); | |
366 | } | |
4718f449 MC |
367 | if (bio == NULL) |
368 | goto err; | |
0f113f3e MC |
369 | } |
370 | if (out) | |
371 | BIO_push(out, bio); | |
372 | else | |
373 | out = bio; | |
ca3a82c3 RS |
374 | return out; |
375 | ||
0f113f3e | 376 | err: |
90a1f2d7 | 377 | EVP_CIPHER_free(fetched_cipher); |
ca3a82c3 RS |
378 | BIO_free_all(out); |
379 | BIO_free_all(btmp); | |
380 | return NULL; | |
0f113f3e | 381 | } |
dfeab068 | 382 | |
8f2e4fdf | 383 | static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) |
0f113f3e MC |
384 | { |
385 | int ret; | |
386 | ret = X509_NAME_cmp(ri->issuer_and_serial->issuer, | |
a8d8e06b | 387 | X509_get_issuer_name(pcert)); |
0f113f3e MC |
388 | if (ret) |
389 | return ret; | |
1337a3a9 | 390 | return ASN1_INTEGER_cmp(X509_get0_serialNumber(pcert), |
a8d8e06b | 391 | ri->issuer_and_serial->serial); |
0f113f3e | 392 | } |
8f2e4fdf | 393 | |
dfeab068 | 394 | /* int */ |
84fa704c | 395 | BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) |
0f113f3e | 396 | { |
90a1f2d7 | 397 | int i, len; |
0f113f3e MC |
398 | BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL; |
399 | X509_ALGOR *xa; | |
400 | ASN1_OCTET_STRING *data_body = NULL; | |
90a1f2d7 | 401 | EVP_MD *evp_md = NULL; |
bd1bbbfe | 402 | const EVP_MD *md; |
90a1f2d7 | 403 | EVP_CIPHER *evp_cipher = NULL; |
835b2900 | 404 | const EVP_CIPHER *cipher = NULL; |
0f113f3e MC |
405 | EVP_CIPHER_CTX *evp_ctx = NULL; |
406 | X509_ALGOR *enc_alg = NULL; | |
407 | STACK_OF(X509_ALGOR) *md_sk = NULL; | |
408 | STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL; | |
409 | PKCS7_RECIP_INFO *ri = NULL; | |
410 | unsigned char *ek = NULL, *tkey = NULL; | |
411 | int eklen = 0, tkeylen = 0; | |
90a1f2d7 SL |
412 | const char *name; |
413 | const PKCS7_CTX *p7_ctx; | |
0f113f3e | 414 | |
c225c3cf EK |
415 | if (p7 == NULL) { |
416 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); | |
417 | return NULL; | |
418 | } | |
419 | ||
90a1f2d7 SL |
420 | p7_ctx = pkcs7_get0_ctx(p7); |
421 | ||
c225c3cf EK |
422 | if (p7->d.ptr == NULL) { |
423 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); | |
424 | return NULL; | |
425 | } | |
426 | ||
0f113f3e MC |
427 | i = OBJ_obj2nid(p7->type); |
428 | p7->state = PKCS7_S_HEADER; | |
429 | ||
430 | switch (i) { | |
431 | case NID_pkcs7_signed: | |
59302b60 EK |
432 | /* |
433 | * p7->d.sign->contents is a PKCS7 structure consisting of a contentType | |
434 | * field and optional content. | |
435 | * data_body is NULL if that structure has no (=detached) content | |
436 | * or if the contentType is wrong (i.e., not "data"). | |
437 | */ | |
0f113f3e MC |
438 | data_body = PKCS7_get_octet_string(p7->d.sign->contents); |
439 | if (!PKCS7_is_detached(p7) && data_body == NULL) { | |
440 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, | |
441 | PKCS7_R_INVALID_SIGNED_DATA_TYPE); | |
442 | goto err; | |
443 | } | |
444 | md_sk = p7->d.sign->md_algs; | |
445 | break; | |
446 | case NID_pkcs7_signedAndEnveloped: | |
447 | rsk = p7->d.signed_and_enveloped->recipientinfo; | |
448 | md_sk = p7->d.signed_and_enveloped->md_algs; | |
59302b60 | 449 | /* data_body is NULL if the optional EncryptedContent is missing. */ |
0f113f3e MC |
450 | data_body = p7->d.signed_and_enveloped->enc_data->enc_data; |
451 | enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm; | |
90a1f2d7 SL |
452 | |
453 | name = OBJ_nid2sn(OBJ_obj2nid(enc_alg->algorithm)); | |
835b2900 DB |
454 | |
455 | (void)ERR_set_mark(); | |
90a1f2d7 | 456 | evp_cipher = EVP_CIPHER_fetch(p7_ctx->libctx, name, p7_ctx->propq); |
835b2900 DB |
457 | if (evp_cipher != NULL) |
458 | cipher = evp_cipher; | |
459 | else | |
460 | cipher = EVP_get_cipherbyname(name); | |
461 | ||
462 | if (cipher == NULL) { | |
463 | (void)ERR_clear_last_mark(); | |
0f113f3e MC |
464 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
465 | PKCS7_R_UNSUPPORTED_CIPHER_TYPE); | |
466 | goto err; | |
467 | } | |
835b2900 | 468 | (void)ERR_pop_to_mark(); |
0f113f3e MC |
469 | break; |
470 | case NID_pkcs7_enveloped: | |
471 | rsk = p7->d.enveloped->recipientinfo; | |
472 | enc_alg = p7->d.enveloped->enc_data->algorithm; | |
59302b60 | 473 | /* data_body is NULL if the optional EncryptedContent is missing. */ |
0f113f3e | 474 | data_body = p7->d.enveloped->enc_data->enc_data; |
90a1f2d7 | 475 | name = OBJ_nid2sn(OBJ_obj2nid(enc_alg->algorithm)); |
835b2900 DB |
476 | |
477 | (void)ERR_set_mark(); | |
90a1f2d7 | 478 | evp_cipher = EVP_CIPHER_fetch(p7_ctx->libctx, name, p7_ctx->propq); |
835b2900 DB |
479 | if (evp_cipher != NULL) |
480 | cipher = evp_cipher; | |
481 | else | |
482 | cipher = EVP_get_cipherbyname(name); | |
483 | ||
484 | if (cipher == NULL) { | |
485 | (void)ERR_clear_last_mark(); | |
0f113f3e MC |
486 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
487 | PKCS7_R_UNSUPPORTED_CIPHER_TYPE); | |
488 | goto err; | |
489 | } | |
835b2900 | 490 | (void)ERR_pop_to_mark(); |
0f113f3e MC |
491 | break; |
492 | default: | |
493 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); | |
494 | goto err; | |
495 | } | |
496 | ||
59302b60 EK |
497 | /* Detached content must be supplied via in_bio instead. */ |
498 | if (data_body == NULL && in_bio == NULL) { | |
499 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); | |
500 | goto err; | |
501 | } | |
502 | ||
0f113f3e MC |
503 | /* We will be checking the signature */ |
504 | if (md_sk != NULL) { | |
505 | for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) { | |
506 | xa = sk_X509_ALGOR_value(md_sk, i); | |
507 | if ((btmp = BIO_new(BIO_f_md())) == NULL) { | |
508 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB); | |
509 | goto err; | |
510 | } | |
511 | ||
90a1f2d7 | 512 | name = OBJ_nid2sn(OBJ_obj2nid(xa->algorithm)); |
bd1bbbfe DB |
513 | |
514 | (void)ERR_set_mark(); | |
90a1f2d7 | 515 | evp_md = EVP_MD_fetch(p7_ctx->libctx, name, p7_ctx->propq); |
bd1bbbfe DB |
516 | if (evp_md != NULL) |
517 | md = evp_md; | |
518 | else | |
519 | md = EVP_get_digestbyname(name); | |
520 | ||
521 | if (md == NULL) { | |
522 | (void)ERR_clear_last_mark(); | |
0f113f3e MC |
523 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
524 | PKCS7_R_UNKNOWN_DIGEST_TYPE); | |
525 | goto err; | |
526 | } | |
bd1bbbfe | 527 | (void)ERR_pop_to_mark(); |
0f113f3e | 528 | |
bd1bbbfe | 529 | BIO_set_md(btmp, md); |
90a1f2d7 | 530 | EVP_MD_free(evp_md); |
0f113f3e MC |
531 | if (out == NULL) |
532 | out = btmp; | |
533 | else | |
534 | BIO_push(out, btmp); | |
535 | btmp = NULL; | |
536 | } | |
537 | } | |
538 | ||
835b2900 | 539 | if (cipher != NULL) { |
0f113f3e MC |
540 | if ((etmp = BIO_new(BIO_f_cipher())) == NULL) { |
541 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB); | |
542 | goto err; | |
543 | } | |
544 | ||
545 | /* | |
546 | * It was encrypted, we need to decrypt the secret key with the | |
547 | * private key | |
548 | */ | |
549 | ||
550 | /* | |
551 | * Find the recipientInfo which matches the passed certificate (if | |
552 | * any) | |
553 | */ | |
554 | ||
555 | if (pcert) { | |
556 | for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { | |
557 | ri = sk_PKCS7_RECIP_INFO_value(rsk, i); | |
558 | if (!pkcs7_cmp_ri(ri, pcert)) | |
559 | break; | |
560 | ri = NULL; | |
561 | } | |
562 | if (ri == NULL) { | |
563 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, | |
564 | PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); | |
565 | goto err; | |
566 | } | |
567 | } | |
568 | ||
569 | /* If we haven't got a certificate try each ri in turn */ | |
570 | if (pcert == NULL) { | |
571 | /* | |
572 | * Always attempt to decrypt all rinfo even after success as a | |
573 | * defence against MMA timing attacks. | |
574 | */ | |
575 | for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { | |
576 | ri = sk_PKCS7_RECIP_INFO_value(rsk, i); | |
90a1f2d7 | 577 | ri->ctx = p7_ctx; |
5840ed0c | 578 | if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, |
835b2900 | 579 | EVP_CIPHER_key_length(cipher)) < 0) |
0f113f3e MC |
580 | goto err; |
581 | ERR_clear_error(); | |
582 | } | |
583 | } else { | |
90a1f2d7 | 584 | ri->ctx = p7_ctx; |
0f113f3e | 585 | /* Only exit on fatal errors, not decrypt failure */ |
5840ed0c | 586 | if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, 0) < 0) |
0f113f3e MC |
587 | goto err; |
588 | ERR_clear_error(); | |
589 | } | |
590 | ||
591 | evp_ctx = NULL; | |
592 | BIO_get_cipher_ctx(etmp, &evp_ctx); | |
835b2900 | 593 | if (EVP_CipherInit_ex(evp_ctx, cipher, NULL, NULL, NULL, 0) <= 0) |
0f113f3e MC |
594 | goto err; |
595 | if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) < 0) | |
596 | goto err; | |
597 | /* Generate random key as MMA defence */ | |
eae4a008 SL |
598 | len = EVP_CIPHER_CTX_key_length(evp_ctx); |
599 | if (len <= 0) | |
600 | goto err; | |
601 | tkeylen = (size_t)len; | |
0f113f3e | 602 | tkey = OPENSSL_malloc(tkeylen); |
90945fa3 | 603 | if (tkey == NULL) |
0f113f3e MC |
604 | goto err; |
605 | if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) | |
606 | goto err; | |
607 | if (ek == NULL) { | |
608 | ek = tkey; | |
609 | eklen = tkeylen; | |
610 | tkey = NULL; | |
611 | } | |
612 | ||
613 | if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) { | |
614 | /* | |
615 | * Some S/MIME clients don't use the same key and effective key | |
616 | * length. The key length is determined by the size of the | |
617 | * decrypted RSA key. | |
618 | */ | |
619 | if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) { | |
620 | /* Use random key as MMA defence */ | |
4b45c6e5 | 621 | OPENSSL_clear_free(ek, eklen); |
0f113f3e MC |
622 | ek = tkey; |
623 | eklen = tkeylen; | |
624 | tkey = NULL; | |
625 | } | |
626 | } | |
627 | /* Clear errors so we don't leak information useful in MMA */ | |
628 | ERR_clear_error(); | |
629 | if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0) | |
630 | goto err; | |
631 | ||
4b45c6e5 RS |
632 | OPENSSL_clear_free(ek, eklen); |
633 | ek = NULL; | |
634 | OPENSSL_clear_free(tkey, tkeylen); | |
635 | tkey = NULL; | |
0f113f3e MC |
636 | |
637 | if (out == NULL) | |
638 | out = etmp; | |
639 | else | |
640 | BIO_push(out, etmp); | |
641 | etmp = NULL; | |
642 | } | |
59302b60 | 643 | if (in_bio != NULL) { |
0f113f3e MC |
644 | bio = in_bio; |
645 | } else { | |
0f113f3e MC |
646 | if (data_body->length > 0) |
647 | bio = BIO_new_mem_buf(data_body->data, data_body->length); | |
648 | else { | |
649 | bio = BIO_new(BIO_s_mem()); | |
90945fa3 MC |
650 | if (bio == NULL) |
651 | goto err; | |
0f113f3e MC |
652 | BIO_set_mem_eof_return(bio, 0); |
653 | } | |
654 | if (bio == NULL) | |
655 | goto err; | |
0f113f3e MC |
656 | } |
657 | BIO_push(out, bio); | |
658 | bio = NULL; | |
90a1f2d7 | 659 | EVP_CIPHER_free(evp_cipher); |
4b45c6e5 RS |
660 | return out; |
661 | ||
0f113f3e | 662 | err: |
90a1f2d7 | 663 | EVP_CIPHER_free(evp_cipher); |
4b45c6e5 RS |
664 | OPENSSL_clear_free(ek, eklen); |
665 | OPENSSL_clear_free(tkey, tkeylen); | |
666 | BIO_free_all(out); | |
667 | BIO_free_all(btmp); | |
668 | BIO_free_all(etmp); | |
669 | BIO_free_all(bio); | |
02e112a8 | 670 | return NULL; |
0f113f3e | 671 | } |
d02b48c6 | 672 | |
c5a55463 | 673 | static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) |
0f113f3e MC |
674 | { |
675 | for (;;) { | |
676 | bio = BIO_find_type(bio, BIO_TYPE_MD); | |
677 | if (bio == NULL) { | |
678 | PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST, | |
679 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
680 | return NULL; | |
681 | } | |
682 | BIO_get_md_ctx(bio, pmd); | |
683 | if (*pmd == NULL) { | |
684 | PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST, ERR_R_INTERNAL_ERROR); | |
685 | return NULL; | |
686 | } | |
687 | if (EVP_MD_CTX_type(*pmd) == nid) | |
688 | return bio; | |
689 | bio = BIO_next(bio); | |
690 | } | |
691 | return NULL; | |
692 | } | |
c5a55463 | 693 | |
76fa8f18 | 694 | static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx) |
0f113f3e MC |
695 | { |
696 | unsigned char md_data[EVP_MAX_MD_SIZE]; | |
697 | unsigned int md_len; | |
698 | ||
699 | /* Add signing time if not already present */ | |
700 | if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) { | |
701 | if (!PKCS7_add0_attrib_signing_time(si, NULL)) { | |
702 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE); | |
703 | return 0; | |
704 | } | |
705 | } | |
706 | ||
707 | /* Add digest */ | |
708 | if (!EVP_DigestFinal_ex(mctx, md_data, &md_len)) { | |
709 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB); | |
710 | return 0; | |
711 | } | |
712 | if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) { | |
713 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE); | |
714 | return 0; | |
715 | } | |
716 | ||
717 | /* Now sign the attributes */ | |
718 | if (!PKCS7_SIGNER_INFO_sign(si)) | |
719 | return 0; | |
720 | ||
721 | return 1; | |
722 | } | |
723 | ||
6b691a5c | 724 | int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) |
0f113f3e MC |
725 | { |
726 | int ret = 0; | |
727 | int i, j; | |
728 | BIO *btmp; | |
729 | PKCS7_SIGNER_INFO *si; | |
6e59a892 | 730 | EVP_MD_CTX *mdc, *ctx_tmp; |
0f113f3e MC |
731 | STACK_OF(X509_ATTRIBUTE) *sk; |
732 | STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL; | |
733 | ASN1_OCTET_STRING *os = NULL; | |
90a1f2d7 | 734 | const PKCS7_CTX *p7_ctx; |
0f113f3e | 735 | |
c225c3cf EK |
736 | if (p7 == NULL) { |
737 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER); | |
738 | return 0; | |
739 | } | |
740 | ||
90a1f2d7 SL |
741 | p7_ctx = pkcs7_get0_ctx(p7); |
742 | ||
c225c3cf EK |
743 | if (p7->d.ptr == NULL) { |
744 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT); | |
745 | return 0; | |
746 | } | |
747 | ||
bfb0641f | 748 | ctx_tmp = EVP_MD_CTX_new(); |
6e59a892 RL |
749 | if (ctx_tmp == NULL) { |
750 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); | |
751 | return 0; | |
752 | } | |
753 | ||
0f113f3e MC |
754 | i = OBJ_obj2nid(p7->type); |
755 | p7->state = PKCS7_S_HEADER; | |
756 | ||
757 | switch (i) { | |
758 | case NID_pkcs7_data: | |
759 | os = p7->d.data; | |
760 | break; | |
761 | case NID_pkcs7_signedAndEnveloped: | |
762 | /* XXXXXXXXXXXXXXXX */ | |
763 | si_sk = p7->d.signed_and_enveloped->signer_info; | |
764 | os = p7->d.signed_and_enveloped->enc_data->enc_data; | |
90945fa3 | 765 | if (os == NULL) { |
f422a514 | 766 | os = ASN1_OCTET_STRING_new(); |
90945fa3 | 767 | if (os == NULL) { |
0f113f3e MC |
768 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); |
769 | goto err; | |
770 | } | |
771 | p7->d.signed_and_enveloped->enc_data->enc_data = os; | |
772 | } | |
773 | break; | |
774 | case NID_pkcs7_enveloped: | |
775 | /* XXXXXXXXXXXXXXXX */ | |
776 | os = p7->d.enveloped->enc_data->enc_data; | |
90945fa3 | 777 | if (os == NULL) { |
f422a514 | 778 | os = ASN1_OCTET_STRING_new(); |
90945fa3 | 779 | if (os == NULL) { |
0f113f3e MC |
780 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE); |
781 | goto err; | |
782 | } | |
783 | p7->d.enveloped->enc_data->enc_data = os; | |
784 | } | |
785 | break; | |
786 | case NID_pkcs7_signed: | |
787 | si_sk = p7->d.sign->signer_info; | |
788 | os = PKCS7_get_octet_string(p7->d.sign->contents); | |
789 | /* If detached data then the content is excluded */ | |
790 | if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) { | |
f422a514 | 791 | ASN1_OCTET_STRING_free(os); |
c225c3cf | 792 | os = NULL; |
0f113f3e MC |
793 | p7->d.sign->contents->d.data = NULL; |
794 | } | |
795 | break; | |
796 | ||
797 | case NID_pkcs7_digest: | |
798 | os = PKCS7_get_octet_string(p7->d.digest->contents); | |
799 | /* If detached data then the content is excluded */ | |
800 | if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) { | |
f422a514 | 801 | ASN1_OCTET_STRING_free(os); |
c225c3cf | 802 | os = NULL; |
0f113f3e MC |
803 | p7->d.digest->contents->d.data = NULL; |
804 | } | |
805 | break; | |
806 | ||
807 | default: | |
808 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); | |
809 | goto err; | |
810 | } | |
811 | ||
812 | if (si_sk != NULL) { | |
813 | for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(si_sk); i++) { | |
814 | si = sk_PKCS7_SIGNER_INFO_value(si_sk, i); | |
815 | if (si->pkey == NULL) | |
816 | continue; | |
817 | ||
818 | j = OBJ_obj2nid(si->digest_alg->algorithm); | |
819 | ||
820 | btmp = bio; | |
821 | ||
822 | btmp = PKCS7_find_digest(&mdc, btmp, j); | |
823 | ||
824 | if (btmp == NULL) | |
825 | goto err; | |
826 | ||
827 | /* | |
828 | * We now have the EVP_MD_CTX, lets do the signing. | |
829 | */ | |
6e59a892 | 830 | if (!EVP_MD_CTX_copy_ex(ctx_tmp, mdc)) |
0f113f3e MC |
831 | goto err; |
832 | ||
833 | sk = si->auth_attr; | |
834 | ||
835 | /* | |
836 | * If there are attributes, we add the digest attribute and only | |
837 | * sign the attributes | |
838 | */ | |
839 | if (sk_X509_ATTRIBUTE_num(sk) > 0) { | |
6e59a892 | 840 | if (!do_pkcs7_signed_attrib(si, ctx_tmp)) |
0f113f3e MC |
841 | goto err; |
842 | } else { | |
843 | unsigned char *abuf = NULL; | |
844 | unsigned int abuflen; | |
845 | abuflen = EVP_PKEY_size(si->pkey); | |
846 | abuf = OPENSSL_malloc(abuflen); | |
90945fa3 | 847 | if (abuf == NULL) |
0f113f3e MC |
848 | goto err; |
849 | ||
90a1f2d7 SL |
850 | if (!EVP_SignFinal_with_libctx(ctx_tmp, abuf, &abuflen, si->pkey, |
851 | p7_ctx->libctx, p7_ctx->propq)) { | |
d54ac5c4 | 852 | OPENSSL_free(abuf); |
0f113f3e MC |
853 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB); |
854 | goto err; | |
855 | } | |
856 | ASN1_STRING_set0(si->enc_digest, abuf, abuflen); | |
857 | } | |
858 | } | |
859 | } else if (i == NID_pkcs7_digest) { | |
860 | unsigned char md_data[EVP_MAX_MD_SIZE]; | |
861 | unsigned int md_len; | |
862 | if (!PKCS7_find_digest(&mdc, bio, | |
863 | OBJ_obj2nid(p7->d.digest->md->algorithm))) | |
864 | goto err; | |
865 | if (!EVP_DigestFinal_ex(mdc, md_data, &md_len)) | |
866 | goto err; | |
d356dc56 MC |
867 | if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) |
868 | goto err; | |
0f113f3e MC |
869 | } |
870 | ||
c225c3cf | 871 | if (!PKCS7_is_detached(p7)) { |
0f113f3e | 872 | /* |
c225c3cf EK |
873 | * NOTE(emilia): I think we only reach os == NULL here because detached |
874 | * digested data support is broken. | |
0f113f3e | 875 | */ |
c225c3cf EK |
876 | if (os == NULL) |
877 | goto err; | |
878 | if (!(os->flags & ASN1_STRING_FLAG_NDEF)) { | |
879 | char *cont; | |
880 | long contlen; | |
881 | btmp = BIO_find_type(bio, BIO_TYPE_MEM); | |
882 | if (btmp == NULL) { | |
883 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO); | |
884 | goto err; | |
885 | } | |
886 | contlen = BIO_get_mem_data(btmp, &cont); | |
887 | /* | |
888 | * Mark the BIO read only then we can use its copy of the data | |
889 | * instead of making an extra copy. | |
890 | */ | |
891 | BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); | |
892 | BIO_set_mem_eof_return(btmp, 0); | |
893 | ASN1_STRING_set0(os, (unsigned char *)cont, contlen); | |
894 | } | |
0f113f3e MC |
895 | } |
896 | ret = 1; | |
897 | err: | |
bfb0641f | 898 | EVP_MD_CTX_free(ctx_tmp); |
26a7d938 | 899 | return ret; |
0f113f3e | 900 | } |
d02b48c6 | 901 | |
76fa8f18 | 902 | int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) |
0f113f3e | 903 | { |
6e59a892 | 904 | EVP_MD_CTX *mctx; |
e6803117 | 905 | EVP_PKEY_CTX *pctx = NULL; |
0f113f3e MC |
906 | unsigned char *abuf = NULL; |
907 | int alen; | |
908 | size_t siglen; | |
909 | const EVP_MD *md = NULL; | |
90a1f2d7 | 910 | const PKCS7_CTX *ctx = si->ctx; |
0f113f3e MC |
911 | |
912 | md = EVP_get_digestbyobj(si->digest_alg->algorithm); | |
913 | if (md == NULL) | |
914 | return 0; | |
915 | ||
bfb0641f | 916 | mctx = EVP_MD_CTX_new(); |
6e59a892 | 917 | if (mctx == NULL) { |
90a1f2d7 | 918 | PKCS7err(0, ERR_R_MALLOC_FAILURE); |
6e59a892 RL |
919 | goto err; |
920 | } | |
921 | ||
90a1f2d7 SL |
922 | if (EVP_DigestSignInit_with_libctx(mctx, &pctx, |
923 | EVP_MD_name(md), ctx->libctx, ctx->propq, | |
924 | si->pkey) <= 0) | |
0f113f3e MC |
925 | goto err; |
926 | ||
dfcb5d29 MC |
927 | /* |
928 | * TODO(3.0): This causes problems when providers are in use, so disabled | |
929 | * for now. Can we get rid of this completely? AFAICT this ctrl has never | |
930 | * been used since it was first put in. All internal implementations just | |
931 | * return 1 and ignore this ctrl and have always done so by the looks of | |
932 | * things. To fix this we could convert this ctrl into a param, which would | |
933 | * require us to send all the signer info data as a set of params...but that | |
934 | * is non-trivial and since this isn't used by anything it may be better | |
935 | * just to remove it. The original commit that added it had this | |
936 | * justification in CHANGES: | |
937 | * | |
938 | * "During PKCS7 signing pass the PKCS7 SignerInfo structure to the | |
939 | * EVP_PKEY_METHOD before and after signing via the | |
940 | * EVP_PKEY_CTRL_PKCS7_SIGN ctrl. It can then customise the structure | |
941 | * before and/or after signing if necessary." | |
942 | */ | |
943 | #if 0 | |
0f113f3e MC |
944 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, |
945 | EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) { | |
90a1f2d7 | 946 | PKCS7err(0, PKCS7_R_CTRL_ERROR); |
0f113f3e MC |
947 | goto err; |
948 | } | |
dfcb5d29 | 949 | #endif |
0f113f3e MC |
950 | |
951 | alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr, &abuf, | |
952 | ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); | |
953 | if (!abuf) | |
954 | goto err; | |
6e59a892 | 955 | if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0) |
0f113f3e MC |
956 | goto err; |
957 | OPENSSL_free(abuf); | |
958 | abuf = NULL; | |
6e59a892 | 959 | if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0) |
0f113f3e MC |
960 | goto err; |
961 | abuf = OPENSSL_malloc(siglen); | |
90945fa3 | 962 | if (abuf == NULL) |
0f113f3e | 963 | goto err; |
6e59a892 | 964 | if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0) |
0f113f3e MC |
965 | goto err; |
966 | ||
dfcb5d29 MC |
967 | /* |
968 | * TODO(3.0): This causes problems when providers are in use, so disabled | |
969 | * for now. Can we get rid of this completely? AFAICT this ctrl has never | |
970 | * been used since it was first put in. All internal implementations just | |
971 | * return 1 and ignore this ctrl and have always done so by the looks of | |
972 | * things. To fix this we could convert this ctrl into a param, which would | |
973 | * require us to send all the signer info data as a set of params...but that | |
974 | * is non-trivial and since this isn't used by anything it may be better | |
975 | * just to remove it. The original commit that added it had this | |
976 | * justification in CHANGES: | |
977 | * | |
978 | * "During PKCS7 signing pass the PKCS7 SignerInfo structure to the | |
979 | * EVP_PKEY_METHOD before and after signing via the | |
980 | * EVP_PKEY_CTRL_PKCS7_SIGN ctrl. It can then customise the structure | |
981 | * before and/or after signing if necessary." | |
982 | */ | |
983 | #if 0 | |
0f113f3e MC |
984 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, |
985 | EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) { | |
90a1f2d7 | 986 | PKCS7err(0, PKCS7_R_CTRL_ERROR); |
0f113f3e MC |
987 | goto err; |
988 | } | |
dfcb5d29 | 989 | #endif |
0f113f3e | 990 | |
bfb0641f | 991 | EVP_MD_CTX_free(mctx); |
0f113f3e MC |
992 | |
993 | ASN1_STRING_set0(si->enc_digest, abuf, siglen); | |
994 | ||
995 | return 1; | |
996 | ||
997 | err: | |
b548a1f1 | 998 | OPENSSL_free(abuf); |
bfb0641f | 999 | EVP_MD_CTX_free(mctx); |
0f113f3e | 1000 | return 0; |
0f113f3e | 1001 | } |
76fa8f18 | 1002 | |
6b691a5c | 1003 | int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, |
0f113f3e MC |
1004 | PKCS7 *p7, PKCS7_SIGNER_INFO *si) |
1005 | { | |
1006 | PKCS7_ISSUER_AND_SERIAL *ias; | |
1007 | int ret = 0, i; | |
1008 | STACK_OF(X509) *cert; | |
1009 | X509 *x509; | |
1010 | ||
c225c3cf EK |
1011 | if (p7 == NULL) { |
1012 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER); | |
1013 | return 0; | |
1014 | } | |
1015 | ||
1016 | if (p7->d.ptr == NULL) { | |
1017 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT); | |
1018 | return 0; | |
1019 | } | |
1020 | ||
0f113f3e MC |
1021 | if (PKCS7_type_is_signed(p7)) { |
1022 | cert = p7->d.sign->cert; | |
1023 | } else if (PKCS7_type_is_signedAndEnveloped(p7)) { | |
1024 | cert = p7->d.signed_and_enveloped->cert; | |
1025 | } else { | |
1026 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); | |
1027 | goto err; | |
1028 | } | |
1029 | /* XXXXXXXXXXXXXXXXXXXXXXX */ | |
1030 | ias = si->issuer_and_serial; | |
1031 | ||
1032 | x509 = X509_find_by_issuer_and_serial(cert, ias->issuer, ias->serial); | |
1033 | ||
1034 | /* were we able to find the cert in passed to us */ | |
1035 | if (x509 == NULL) { | |
1036 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, | |
1037 | PKCS7_R_UNABLE_TO_FIND_CERTIFICATE); | |
1038 | goto err; | |
1039 | } | |
1040 | ||
1041 | /* Lets verify */ | |
1042 | if (!X509_STORE_CTX_init(ctx, cert_store, x509, cert)) { | |
1043 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB); | |
1044 | goto err; | |
1045 | } | |
1046 | X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN); | |
1047 | i = X509_verify_cert(ctx); | |
1048 | if (i <= 0) { | |
1049 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB); | |
1050 | X509_STORE_CTX_cleanup(ctx); | |
1051 | goto err; | |
1052 | } | |
1053 | X509_STORE_CTX_cleanup(ctx); | |
1054 | ||
1055 | return PKCS7_signatureVerify(bio, p7, si, x509); | |
1056 | err: | |
1057 | return ret; | |
1058 | } | |
170afce5 DSH |
1059 | |
1060 | int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, | |
0f113f3e | 1061 | X509 *x509) |
dfeab068 | 1062 | { |
0f113f3e | 1063 | ASN1_OCTET_STRING *os; |
6e59a892 | 1064 | EVP_MD_CTX *mdc_tmp, *mdc; |
bd1bbbfe | 1065 | const EVP_MD *md; |
90a1f2d7 | 1066 | EVP_MD *fetched_md = NULL; |
0f113f3e MC |
1067 | int ret = 0, i; |
1068 | int md_type; | |
1069 | STACK_OF(X509_ATTRIBUTE) *sk; | |
1070 | BIO *btmp; | |
1071 | EVP_PKEY *pkey; | |
90a1f2d7 | 1072 | const PKCS7_CTX *ctx = pkcs7_get0_ctx(p7); |
0f113f3e | 1073 | |
bfb0641f | 1074 | mdc_tmp = EVP_MD_CTX_new(); |
6e59a892 RL |
1075 | if (mdc_tmp == NULL) { |
1076 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_MALLOC_FAILURE); | |
1077 | goto err; | |
1078 | } | |
0f113f3e MC |
1079 | |
1080 | if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { | |
1081 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); | |
1082 | goto err; | |
1083 | } | |
1084 | ||
1085 | md_type = OBJ_obj2nid(si->digest_alg->algorithm); | |
1086 | ||
1087 | btmp = bio; | |
1088 | for (;;) { | |
1089 | if ((btmp == NULL) || | |
1090 | ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) { | |
1091 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, | |
1092 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
1093 | goto err; | |
1094 | } | |
1095 | BIO_get_md_ctx(btmp, &mdc); | |
1096 | if (mdc == NULL) { | |
1097 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR); | |
1098 | goto err; | |
1099 | } | |
1100 | if (EVP_MD_CTX_type(mdc) == md_type) | |
1101 | break; | |
1102 | /* | |
1103 | * Workaround for some broken clients that put the signature OID | |
1104 | * instead of the digest OID in digest_alg->algorithm | |
1105 | */ | |
1106 | if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) | |
1107 | break; | |
1108 | btmp = BIO_next(btmp); | |
1109 | } | |
1110 | ||
1111 | /* | |
1112 | * mdc is the digest ctx that we want, unless there are attributes, in | |
1113 | * which case the digest is the signed attributes | |
1114 | */ | |
6e59a892 | 1115 | if (!EVP_MD_CTX_copy_ex(mdc_tmp, mdc)) |
0f113f3e MC |
1116 | goto err; |
1117 | ||
1118 | sk = si->auth_attr; | |
1119 | if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { | |
1120 | unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; | |
1121 | unsigned int md_len; | |
1122 | int alen; | |
1123 | ASN1_OCTET_STRING *message_digest; | |
1124 | ||
6e59a892 | 1125 | if (!EVP_DigestFinal_ex(mdc_tmp, md_dat, &md_len)) |
0f113f3e MC |
1126 | goto err; |
1127 | message_digest = PKCS7_digest_from_attributes(sk); | |
1128 | if (!message_digest) { | |
1129 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, | |
1130 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
1131 | goto err; | |
1132 | } | |
1133 | if ((message_digest->length != (int)md_len) || | |
1134 | (memcmp(message_digest->data, md_dat, md_len))) { | |
0f113f3e MC |
1135 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE); |
1136 | ret = -1; | |
1137 | goto err; | |
1138 | } | |
1139 | ||
bd1bbbfe | 1140 | (void)ERR_set_mark(); |
90a1f2d7 | 1141 | fetched_md = EVP_MD_fetch(ctx->libctx, OBJ_nid2sn(md_type), ctx->propq); |
bd1bbbfe DB |
1142 | |
1143 | if (fetched_md != NULL) | |
1144 | md = fetched_md; | |
1145 | else | |
1146 | md = EVP_get_digestbynid(md_type); | |
1147 | ||
1148 | if (md == NULL || !EVP_VerifyInit_ex(mdc_tmp, md, NULL)) { | |
1149 | (void)ERR_clear_last_mark(); | |
0f113f3e | 1150 | goto err; |
bd1bbbfe DB |
1151 | } |
1152 | (void)ERR_pop_to_mark(); | |
0f113f3e MC |
1153 | |
1154 | alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, | |
1155 | ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY)); | |
1156 | if (alen <= 0) { | |
1157 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_ASN1_LIB); | |
1158 | ret = -1; | |
1159 | goto err; | |
1160 | } | |
6e59a892 | 1161 | if (!EVP_VerifyUpdate(mdc_tmp, abuf, alen)) |
0f113f3e MC |
1162 | goto err; |
1163 | ||
1164 | OPENSSL_free(abuf); | |
1165 | } | |
1166 | ||
1167 | os = si->enc_digest; | |
8382fd3a | 1168 | pkey = X509_get0_pubkey(x509); |
12a765a5 | 1169 | if (pkey == NULL) { |
0f113f3e MC |
1170 | ret = -1; |
1171 | goto err; | |
1172 | } | |
1173 | ||
90a1f2d7 SL |
1174 | i = EVP_VerifyFinal_with_libctx(mdc_tmp, os->data, os->length, pkey, |
1175 | ctx->libctx, ctx->propq); | |
0f113f3e MC |
1176 | if (i <= 0) { |
1177 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); | |
1178 | ret = -1; | |
1179 | goto err; | |
c5ba2d99 RS |
1180 | } |
1181 | ret = 1; | |
0f113f3e | 1182 | err: |
bfb0641f | 1183 | EVP_MD_CTX_free(mdc_tmp); |
90a1f2d7 | 1184 | EVP_MD_free(fetched_md); |
26a7d938 | 1185 | return ret; |
0f113f3e | 1186 | } |
d02b48c6 | 1187 | |
6b691a5c | 1188 | PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) |
0f113f3e MC |
1189 | { |
1190 | STACK_OF(PKCS7_RECIP_INFO) *rsk; | |
1191 | PKCS7_RECIP_INFO *ri; | |
1192 | int i; | |
1193 | ||
1194 | i = OBJ_obj2nid(p7->type); | |
1195 | if (i != NID_pkcs7_signedAndEnveloped) | |
1196 | return NULL; | |
1197 | if (p7->d.signed_and_enveloped == NULL) | |
1198 | return NULL; | |
1199 | rsk = p7->d.signed_and_enveloped->recipientinfo; | |
1200 | if (rsk == NULL) | |
1201 | return NULL; | |
0f113f3e | 1202 | if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) |
26a7d938 | 1203 | return NULL; |
0f113f3e | 1204 | ri = sk_PKCS7_RECIP_INFO_value(rsk, idx); |
26a7d938 | 1205 | return ri->issuer_and_serial; |
0f113f3e | 1206 | } |
dfeab068 | 1207 | |
6b691a5c | 1208 | ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) |
0f113f3e | 1209 | { |
26a7d938 | 1210 | return get_attribute(si->auth_attr, nid); |
0f113f3e | 1211 | } |
dfeab068 | 1212 | |
6b691a5c | 1213 | ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) |
0f113f3e | 1214 | { |
26a7d938 | 1215 | return get_attribute(si->unauth_attr, nid); |
0f113f3e | 1216 | } |
dfeab068 | 1217 | |
b6436ff2 | 1218 | static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) |
0f113f3e | 1219 | { |
9b0a4531 | 1220 | int idx; |
0f113f3e | 1221 | X509_ATTRIBUTE *xa; |
9b0a4531 DSH |
1222 | idx = X509at_get_attr_by_NID(sk, nid, -1); |
1223 | xa = X509at_get_attr(sk, idx); | |
1224 | return X509_ATTRIBUTE_get0_type(xa, 0); | |
0f113f3e | 1225 | } |
dfeab068 | 1226 | |
b6436ff2 | 1227 | ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) |
10243d97 | 1228 | { |
0f113f3e | 1229 | ASN1_TYPE *astype; |
75ebbd9a | 1230 | if ((astype = get_attribute(sk, NID_pkcs9_messageDigest)) == NULL) |
0f113f3e MC |
1231 | return NULL; |
1232 | return astype->value.octet_string; | |
10243d97 | 1233 | } |
dfeab068 | 1234 | |
b6436ff2 | 1235 | int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, |
0f113f3e MC |
1236 | STACK_OF(X509_ATTRIBUTE) *sk) |
1237 | { | |
1238 | int i; | |
1239 | ||
222561fe | 1240 | sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr, X509_ATTRIBUTE_free); |
0f113f3e MC |
1241 | p7si->auth_attr = sk_X509_ATTRIBUTE_dup(sk); |
1242 | if (p7si->auth_attr == NULL) | |
1243 | return 0; | |
1244 | for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) { | |
1245 | if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr, i, | |
1246 | X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value | |
1247 | (sk, i)))) | |
1248 | == NULL) | |
26a7d938 | 1249 | return 0; |
0f113f3e | 1250 | } |
208fb891 | 1251 | return 1; |
0f113f3e MC |
1252 | } |
1253 | ||
1254 | int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, | |
1255 | STACK_OF(X509_ATTRIBUTE) *sk) | |
1256 | { | |
1257 | int i; | |
1258 | ||
222561fe | 1259 | sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free); |
0f113f3e MC |
1260 | p7si->unauth_attr = sk_X509_ATTRIBUTE_dup(sk); |
1261 | if (p7si->unauth_attr == NULL) | |
1262 | return 0; | |
1263 | for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) { | |
1264 | if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr, i, | |
1265 | X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value | |
1266 | (sk, i)))) | |
1267 | == NULL) | |
26a7d938 | 1268 | return 0; |
0f113f3e | 1269 | } |
208fb891 | 1270 | return 1; |
0f113f3e | 1271 | } |
dfeab068 | 1272 | |
6b691a5c | 1273 | int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, |
0f113f3e MC |
1274 | void *value) |
1275 | { | |
26a7d938 | 1276 | return add_attribute(&(p7si->auth_attr), nid, atrtype, value); |
0f113f3e | 1277 | } |
dfeab068 | 1278 | |
6b691a5c | 1279 | int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, |
0f113f3e MC |
1280 | void *value) |
1281 | { | |
26a7d938 | 1282 | return add_attribute(&(p7si->unauth_attr), nid, atrtype, value); |
0f113f3e | 1283 | } |
dfeab068 | 1284 | |
b6436ff2 | 1285 | static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, |
0f113f3e MC |
1286 | void *value) |
1287 | { | |
1288 | X509_ATTRIBUTE *attr = NULL; | |
1289 | ||
1290 | if (*sk == NULL) { | |
75ebbd9a | 1291 | if ((*sk = sk_X509_ATTRIBUTE_new_null()) == NULL) |
0f113f3e MC |
1292 | return 0; |
1293 | new_attrib: | |
75ebbd9a | 1294 | if ((attr = X509_ATTRIBUTE_create(nid, atrtype, value)) == NULL) |
0f113f3e MC |
1295 | return 0; |
1296 | if (!sk_X509_ATTRIBUTE_push(*sk, attr)) { | |
1297 | X509_ATTRIBUTE_free(attr); | |
1298 | return 0; | |
1299 | } | |
1300 | } else { | |
1301 | int i; | |
1302 | ||
1303 | for (i = 0; i < sk_X509_ATTRIBUTE_num(*sk); i++) { | |
1304 | attr = sk_X509_ATTRIBUTE_value(*sk, i); | |
9b0a4531 | 1305 | if (OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)) == nid) { |
0f113f3e MC |
1306 | X509_ATTRIBUTE_free(attr); |
1307 | attr = X509_ATTRIBUTE_create(nid, atrtype, value); | |
1308 | if (attr == NULL) | |
1309 | return 0; | |
1310 | if (!sk_X509_ATTRIBUTE_set(*sk, i, attr)) { | |
1311 | X509_ATTRIBUTE_free(attr); | |
1312 | return 0; | |
1313 | } | |
1314 | goto end; | |
1315 | } | |
1316 | } | |
1317 | goto new_attrib; | |
1318 | } | |
1319 | end: | |
208fb891 | 1320 | return 1; |
0f113f3e | 1321 | } |