Line data Source code
1 : /*
2 : * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "hx_locl.h"
35 :
36 : /**
37 : * @page page_cms CMS/PKCS7 message functions.
38 : *
39 : * CMS is defined in RFC 3369 and is an continuation of the RSA Labs
40 : * standard PKCS7. The basic messages in CMS is
41 : *
42 : * - SignedData
43 : * Data signed with private key (RSA, DSA, ECDSA) or secret
44 : * (symmetric) key
45 : * - EnvelopedData
46 : * Data encrypted with private key (RSA)
47 : * - EncryptedData
48 : * Data encrypted with secret (symmetric) key.
49 : * - ContentInfo
50 : * Wrapper structure including type and data.
51 : *
52 : *
53 : * See the library functions here: @ref hx509_cms
54 : */
55 :
56 : #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
57 : #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
58 :
59 : /**
60 : * Wrap data and oid in a ContentInfo and encode it.
61 : *
62 : * @param oid type of the content.
63 : * @param buf data to be wrapped. If a NULL pointer is passed in, the
64 : * optional content field in the ContentInfo is not going be filled
65 : * in.
66 : * @param res the encoded buffer, the result should be freed with
67 : * der_free_octet_string().
68 : *
69 : * @return Returns an hx509 error code.
70 : *
71 : * @ingroup hx509_cms
72 : */
73 :
74 : HX509_LIB_FUNCTION int HX509_LIB_CALL
75 77 : hx509_cms_wrap_ContentInfo(const heim_oid *oid,
76 : const heim_octet_string *buf,
77 : heim_octet_string *res)
78 : {
79 : ContentInfo ci;
80 : size_t size;
81 : int ret;
82 :
83 77 : memset(res, 0, sizeof(*res));
84 77 : memset(&ci, 0, sizeof(ci));
85 :
86 77 : ret = der_copy_oid(oid, &ci.contentType);
87 77 : if (ret)
88 0 : return ret;
89 77 : if (buf) {
90 77 : ALLOC(ci.content, 1);
91 77 : if (ci.content == NULL) {
92 0 : free_ContentInfo(&ci);
93 0 : return ENOMEM;
94 : }
95 77 : ci.content->data = malloc(buf->length);
96 77 : if (ci.content->data == NULL) {
97 0 : free_ContentInfo(&ci);
98 0 : return ENOMEM;
99 : }
100 77 : memcpy(ci.content->data, buf->data, buf->length);
101 77 : ci.content->length = buf->length;
102 : }
103 :
104 77 : ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
105 77 : free_ContentInfo(&ci);
106 77 : if (ret)
107 0 : return ret;
108 77 : if (res->length != size)
109 0 : _hx509_abort("internal ASN.1 encoder error");
110 :
111 77 : return 0;
112 : }
113 :
114 : /**
115 : * Decode an ContentInfo and unwrap data and oid it.
116 : *
117 : * @param in the encoded buffer.
118 : * @param oid type of the content.
119 : * @param out data to be wrapped.
120 : * @param have_data since the data is optional, this flags show dthe
121 : * diffrence between no data and the zero length data.
122 : *
123 : * @return Returns an hx509 error code.
124 : *
125 : * @ingroup hx509_cms
126 : */
127 :
128 : HX509_LIB_FUNCTION int HX509_LIB_CALL
129 0 : hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
130 : heim_oid *oid,
131 : heim_octet_string *out,
132 : int *have_data)
133 : {
134 : ContentInfo ci;
135 : size_t size;
136 : int ret;
137 :
138 0 : memset(oid, 0, sizeof(*oid));
139 0 : memset(out, 0, sizeof(*out));
140 :
141 0 : ret = decode_ContentInfo(in->data, in->length, &ci, &size);
142 0 : if (ret)
143 0 : return ret;
144 :
145 0 : ret = der_copy_oid(&ci.contentType, oid);
146 0 : if (ret) {
147 0 : free_ContentInfo(&ci);
148 0 : return ret;
149 : }
150 0 : if (ci.content) {
151 0 : ret = der_copy_octet_string(ci.content, out);
152 0 : if (ret) {
153 0 : der_free_oid(oid);
154 0 : free_ContentInfo(&ci);
155 0 : return ret;
156 : }
157 : } else
158 0 : memset(out, 0, sizeof(*out));
159 :
160 0 : if (have_data)
161 0 : *have_data = (ci.content != NULL) ? 1 : 0;
162 :
163 0 : free_ContentInfo(&ci);
164 :
165 0 : return 0;
166 : }
167 :
168 : #define CMS_ID_SKI 0
169 : #define CMS_ID_NAME 1
170 :
171 : static int
172 0 : fill_CMSIdentifier(const hx509_cert cert,
173 : int type,
174 : CMSIdentifier *id)
175 : {
176 : int ret;
177 :
178 0 : switch (type) {
179 0 : case CMS_ID_SKI:
180 0 : id->element = choice_CMSIdentifier_subjectKeyIdentifier;
181 0 : ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
182 : &id->u.subjectKeyIdentifier);
183 0 : if (ret == 0)
184 0 : break;
185 : fallthrough;
186 : case CMS_ID_NAME: {
187 : hx509_name name;
188 :
189 0 : id->element = choice_CMSIdentifier_issuerAndSerialNumber;
190 0 : ret = hx509_cert_get_issuer(cert, &name);
191 0 : if (ret)
192 0 : return ret;
193 0 : ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
194 0 : hx509_name_free(&name);
195 0 : if (ret)
196 0 : return ret;
197 :
198 0 : ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
199 0 : break;
200 : }
201 0 : default:
202 0 : _hx509_abort("CMS fill identifier with unknown type");
203 : }
204 0 : return ret;
205 : }
206 :
207 : static int
208 0 : unparse_CMSIdentifier(hx509_context context,
209 : CMSIdentifier *id,
210 : char **str)
211 : {
212 0 : int ret = -1;
213 :
214 0 : *str = NULL;
215 0 : switch (id->element) {
216 0 : case choice_CMSIdentifier_issuerAndSerialNumber: {
217 : IssuerAndSerialNumber *iasn;
218 : char *serial, *name;
219 :
220 0 : iasn = &id->u.issuerAndSerialNumber;
221 :
222 0 : ret = _hx509_Name_to_string(&iasn->issuer, &name);
223 0 : if(ret)
224 0 : return ret;
225 0 : ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
226 0 : if (ret) {
227 0 : free(name);
228 0 : return ret;
229 : }
230 0 : ret = asprintf(str, "certificate issued by %s with serial number %s",
231 : name, serial);
232 0 : free(name);
233 0 : free(serial);
234 0 : break;
235 : }
236 0 : case choice_CMSIdentifier_subjectKeyIdentifier: {
237 0 : KeyIdentifier *ki = &id->u.subjectKeyIdentifier;
238 : char *keyid;
239 : ssize_t len;
240 :
241 0 : len = hex_encode(ki->data, ki->length, &keyid);
242 0 : if (len < 0)
243 0 : return ENOMEM;
244 :
245 0 : ret = asprintf(str, "certificate with id %s", keyid);
246 0 : free(keyid);
247 0 : break;
248 : }
249 0 : default:
250 0 : ret = asprintf(str, "certificate have unknown CMSidentifier type");
251 0 : break;
252 : }
253 : /*
254 : * In the following if, we check ret and *str which should be returned/set
255 : * by asprintf(3) in every branch of the switch statement.
256 : */
257 0 : if (ret == -1 || *str == NULL)
258 0 : return ENOMEM;
259 0 : return 0;
260 : }
261 :
262 : static int
263 0 : find_CMSIdentifier(hx509_context context,
264 : CMSIdentifier *client,
265 : hx509_certs certs,
266 : time_t time_now,
267 : hx509_cert *signer_cert,
268 : int match)
269 : {
270 : hx509_query q;
271 : hx509_cert cert;
272 : Certificate c;
273 : int ret;
274 :
275 0 : memset(&c, 0, sizeof(c));
276 0 : _hx509_query_clear(&q);
277 :
278 0 : *signer_cert = NULL;
279 :
280 0 : switch (client->element) {
281 0 : case choice_CMSIdentifier_issuerAndSerialNumber:
282 0 : q.serial = &client->u.issuerAndSerialNumber.serialNumber;
283 0 : q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
284 0 : q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
285 0 : break;
286 0 : case choice_CMSIdentifier_subjectKeyIdentifier:
287 0 : q.subject_id = &client->u.subjectKeyIdentifier;
288 0 : q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
289 0 : break;
290 0 : default:
291 0 : hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
292 : "unknown CMS identifier element");
293 0 : return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
294 : }
295 :
296 0 : q.match |= match;
297 :
298 0 : q.match |= HX509_QUERY_MATCH_TIME;
299 0 : if (time_now)
300 0 : q.timenow = time_now;
301 : else
302 0 : q.timenow = time(NULL);
303 :
304 0 : ret = hx509_certs_find(context, certs, &q, &cert);
305 0 : if (ret == HX509_CERT_NOT_FOUND) {
306 : char *str;
307 :
308 0 : ret = unparse_CMSIdentifier(context, client, &str);
309 0 : if (ret == 0) {
310 0 : hx509_set_error_string(context, 0,
311 : HX509_CMS_NO_RECIPIENT_CERTIFICATE,
312 : "Failed to find %s", str);
313 : } else
314 0 : hx509_clear_error_string(context);
315 0 : return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
316 0 : } else if (ret) {
317 0 : hx509_set_error_string(context, HX509_ERROR_APPEND,
318 : HX509_CMS_NO_RECIPIENT_CERTIFICATE,
319 : "Failed to find CMS id in cert store");
320 0 : return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
321 : }
322 :
323 0 : *signer_cert = cert;
324 :
325 0 : return 0;
326 : }
327 :
328 : /**
329 : * Decode and unencrypt EnvelopedData.
330 : *
331 : * Extract data and parameteres from from the EnvelopedData. Also
332 : * supports using detached EnvelopedData.
333 : *
334 : * @param context A hx509 context.
335 : * @param certs Certificate that can decrypt the EnvelopedData
336 : * encryption key.
337 : * @param flags HX509_CMS_UE flags to control the behavior.
338 : * @param data pointer the structure the contains the DER/BER encoded
339 : * EnvelopedData stucture.
340 : * @param length length of the data that data point to.
341 : * @param encryptedContent in case of detached signature, this
342 : * contains the actual encrypted data, othersize its should be NULL.
343 : * @param time_now set the current time, if zero the library uses now as the date.
344 : * @param contentType output type oid, should be freed with der_free_oid().
345 : * @param content the data, free with der_free_octet_string().
346 : *
347 : * @return an hx509 error code.
348 : *
349 : * @ingroup hx509_cms
350 : */
351 :
352 : HX509_LIB_FUNCTION int HX509_LIB_CALL
353 0 : hx509_cms_unenvelope(hx509_context context,
354 : hx509_certs certs,
355 : int flags,
356 : const void *data,
357 : size_t length,
358 : const heim_octet_string *encryptedContent,
359 : time_t time_now,
360 : heim_oid *contentType,
361 : heim_octet_string *content)
362 : {
363 : heim_octet_string key;
364 : EnvelopedData ed;
365 : hx509_cert cert;
366 : AlgorithmIdentifier *ai;
367 : const heim_octet_string *enccontent;
368 : heim_octet_string *params, params_data;
369 : heim_octet_string ivec;
370 : size_t size;
371 0 : int ret, matched = 0, findflags = 0;
372 : size_t i;
373 :
374 :
375 0 : memset(&key, 0, sizeof(key));
376 0 : memset(&ed, 0, sizeof(ed));
377 0 : memset(&ivec, 0, sizeof(ivec));
378 0 : memset(content, 0, sizeof(*content));
379 0 : memset(contentType, 0, sizeof(*contentType));
380 :
381 0 : if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
382 0 : findflags |= HX509_QUERY_KU_ENCIPHERMENT;
383 :
384 0 : ret = decode_EnvelopedData(data, length, &ed, &size);
385 0 : if (ret) {
386 0 : hx509_set_error_string(context, 0, ret,
387 : "Failed to decode EnvelopedData");
388 0 : return ret;
389 : }
390 :
391 0 : if (ed.recipientInfos.len == 0) {
392 0 : ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
393 0 : hx509_set_error_string(context, 0, ret,
394 : "No recipient info in enveloped data");
395 0 : goto out;
396 : }
397 :
398 0 : enccontent = ed.encryptedContentInfo.encryptedContent;
399 0 : if (enccontent == NULL) {
400 0 : if (encryptedContent == NULL) {
401 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
402 0 : hx509_set_error_string(context, 0, ret,
403 : "Content missing from encrypted data");
404 0 : goto out;
405 : }
406 0 : enccontent = encryptedContent;
407 0 : } else if (encryptedContent != NULL) {
408 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
409 0 : hx509_set_error_string(context, 0, ret,
410 : "Both internal and external encrypted data");
411 0 : goto out;
412 : }
413 :
414 0 : cert = NULL;
415 0 : for (i = 0; i < ed.recipientInfos.len; i++) {
416 : KeyTransRecipientInfo *ri;
417 : char *str;
418 : int ret2;
419 :
420 0 : ri = &ed.recipientInfos.val[i];
421 :
422 0 : ret = find_CMSIdentifier(context, &ri->rid, certs,
423 : time_now, &cert,
424 : HX509_QUERY_PRIVATE_KEY|findflags);
425 0 : if (ret)
426 0 : continue;
427 :
428 0 : matched = 1; /* found a matching certificate, let decrypt */
429 :
430 0 : ret = _hx509_cert_private_decrypt(context,
431 0 : &ri->encryptedKey,
432 0 : &ri->keyEncryptionAlgorithm.algorithm,
433 : cert, &key);
434 :
435 0 : hx509_cert_free(cert);
436 0 : if (ret == 0)
437 0 : break; /* succuessfully decrypted cert */
438 0 : cert = NULL;
439 0 : ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
440 0 : if (ret2 == 0) {
441 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
442 : "Failed to decrypt with %s", str);
443 0 : free(str);
444 : }
445 : }
446 :
447 0 : if (!matched) {
448 0 : ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
449 0 : hx509_set_error_string(context, 0, ret,
450 : "No private key matched any certificate");
451 0 : goto out;
452 : }
453 :
454 0 : if (cert == NULL) {
455 0 : ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
456 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
457 : "No private key decrypted the transfer key");
458 0 : goto out;
459 : }
460 :
461 0 : ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
462 0 : if (ret) {
463 0 : hx509_set_error_string(context, 0, ret,
464 : "Failed to copy EnvelopedData content oid");
465 0 : goto out;
466 : }
467 :
468 0 : ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
469 0 : if (ai->parameters) {
470 0 : params_data.data = ai->parameters->data;
471 0 : params_data.length = ai->parameters->length;
472 0 : params = ¶ms_data;
473 : } else
474 0 : params = NULL;
475 :
476 : {
477 : hx509_crypto crypto;
478 :
479 0 : ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
480 0 : if (ret)
481 0 : goto out;
482 :
483 0 : if (flags & HX509_CMS_UE_ALLOW_WEAK)
484 0 : hx509_crypto_allow_weak(crypto);
485 :
486 0 : if (params) {
487 0 : ret = hx509_crypto_set_params(context, crypto, params, &ivec);
488 0 : if (ret) {
489 0 : hx509_crypto_destroy(crypto);
490 0 : goto out;
491 : }
492 : }
493 :
494 0 : ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
495 0 : if (ret) {
496 0 : hx509_crypto_destroy(crypto);
497 0 : hx509_set_error_string(context, 0, ret,
498 : "Failed to set key for decryption "
499 : "of EnvelopedData");
500 0 : goto out;
501 : }
502 :
503 0 : ret = hx509_crypto_decrypt(crypto,
504 0 : enccontent->data,
505 : enccontent->length,
506 0 : ivec.length ? &ivec : NULL,
507 : content);
508 0 : hx509_crypto_destroy(crypto);
509 0 : if (ret) {
510 0 : hx509_set_error_string(context, 0, ret,
511 : "Failed to decrypt EnvelopedData");
512 0 : goto out;
513 : }
514 : }
515 :
516 0 : out:
517 :
518 0 : free_EnvelopedData(&ed);
519 0 : der_free_octet_string(&key);
520 0 : if (ivec.length)
521 0 : der_free_octet_string(&ivec);
522 0 : if (ret) {
523 0 : der_free_oid(contentType);
524 0 : der_free_octet_string(content);
525 : }
526 :
527 0 : return ret;
528 : }
529 :
530 : /**
531 : * Encrypt end encode EnvelopedData.
532 : *
533 : * Encrypt and encode EnvelopedData. The data is encrypted with a
534 : * random key and the the random key is encrypted with the
535 : * certificates private key. This limits what private key type can be
536 : * used to RSA.
537 : *
538 : * @param context A hx509 context.
539 : * @param flags flags to control the behavior.
540 : * - HX509_CMS_EV_NO_KU_CHECK - Don't check KU on certificate
541 : * - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo
542 : * - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number
543 : * @param cert Certificate to encrypt the EnvelopedData encryption key
544 : * with.
545 : * @param data pointer the data to encrypt.
546 : * @param length length of the data that data point to.
547 : * @param encryption_type Encryption cipher to use for the bulk data,
548 : * use NULL to get default.
549 : * @param contentType type of the data that is encrypted
550 : * @param content the output of the function,
551 : * free with der_free_octet_string().
552 : *
553 : * @return an hx509 error code.
554 : *
555 : * @ingroup hx509_cms
556 : */
557 :
558 : HX509_LIB_FUNCTION int HX509_LIB_CALL
559 0 : hx509_cms_envelope_1(hx509_context context,
560 : int flags,
561 : hx509_cert cert,
562 : const void *data,
563 : size_t length,
564 : const heim_oid *encryption_type,
565 : const heim_oid *contentType,
566 : heim_octet_string *content)
567 : {
568 : KeyTransRecipientInfo *ri;
569 : heim_octet_string ivec;
570 : heim_octet_string key;
571 0 : hx509_crypto crypto = NULL;
572 : int ret, cmsidflag;
573 : EnvelopedData ed;
574 : size_t size;
575 :
576 0 : memset(&ivec, 0, sizeof(ivec));
577 0 : memset(&key, 0, sizeof(key));
578 0 : memset(&ed, 0, sizeof(ed));
579 0 : memset(content, 0, sizeof(*content));
580 :
581 0 : if (encryption_type == NULL)
582 0 : encryption_type = &asn1_oid_id_aes_256_cbc;
583 :
584 0 : if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
585 0 : ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
586 0 : if (ret)
587 0 : goto out;
588 : }
589 :
590 0 : ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
591 0 : if (ret)
592 0 : goto out;
593 :
594 0 : if (flags & HX509_CMS_EV_ALLOW_WEAK)
595 0 : hx509_crypto_allow_weak(crypto);
596 :
597 0 : ret = hx509_crypto_set_random_key(crypto, &key);
598 0 : if (ret) {
599 0 : hx509_set_error_string(context, 0, ret,
600 : "Create random key for EnvelopedData content");
601 0 : goto out;
602 : }
603 :
604 0 : ret = hx509_crypto_random_iv(crypto, &ivec);
605 0 : if (ret) {
606 0 : hx509_set_error_string(context, 0, ret,
607 : "Failed to create a random iv");
608 0 : goto out;
609 : }
610 :
611 0 : ret = hx509_crypto_encrypt(crypto,
612 : data,
613 : length,
614 : &ivec,
615 : &ed.encryptedContentInfo.encryptedContent);
616 0 : if (ret) {
617 0 : hx509_set_error_string(context, 0, ret,
618 : "Failed to encrypt EnvelopedData content");
619 0 : goto out;
620 : }
621 :
622 : {
623 : AlgorithmIdentifier *enc_alg;
624 0 : enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
625 0 : ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
626 0 : if (ret) {
627 0 : hx509_set_error_string(context, 0, ret,
628 : "Failed to set crypto oid "
629 : "for EnvelopedData");
630 0 : goto out;
631 : }
632 0 : ALLOC(enc_alg->parameters, 1);
633 0 : if (enc_alg->parameters == NULL) {
634 0 : ret = ENOMEM;
635 0 : hx509_set_error_string(context, 0, ret,
636 : "Failed to allocate crypto parameters "
637 : "for EnvelopedData");
638 0 : goto out;
639 : }
640 :
641 0 : ret = hx509_crypto_get_params(context,
642 : crypto,
643 : &ivec,
644 0 : enc_alg->parameters);
645 0 : if (ret) {
646 0 : goto out;
647 : }
648 : }
649 :
650 0 : ALLOC_SEQ(&ed.recipientInfos, 1);
651 0 : if (ed.recipientInfos.val == NULL) {
652 0 : ret = ENOMEM;
653 0 : hx509_set_error_string(context, 0, ret,
654 : "Failed to allocate recipients info "
655 : "for EnvelopedData");
656 0 : goto out;
657 : }
658 :
659 0 : ri = &ed.recipientInfos.val[0];
660 :
661 0 : if (flags & HX509_CMS_EV_ID_NAME) {
662 0 : ri->version = 0;
663 0 : cmsidflag = CMS_ID_NAME;
664 : } else {
665 0 : ri->version = 2;
666 0 : cmsidflag = CMS_ID_SKI;
667 : }
668 :
669 0 : ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
670 0 : if (ret) {
671 0 : hx509_set_error_string(context, 0, ret,
672 : "Failed to set CMS identifier info "
673 : "for EnvelopedData");
674 0 : goto out;
675 : }
676 :
677 0 : ret = hx509_cert_public_encrypt(context,
678 : &key, cert,
679 : &ri->keyEncryptionAlgorithm.algorithm,
680 0 : &ri->encryptedKey);
681 0 : if (ret) {
682 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
683 : "Failed to encrypt transport key for "
684 : "EnvelopedData");
685 0 : goto out;
686 : }
687 :
688 : /*
689 : *
690 : */
691 :
692 0 : ed.version = 0;
693 0 : ed.originatorInfo = NULL;
694 :
695 0 : ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
696 0 : if (ret) {
697 0 : hx509_set_error_string(context, 0, ret,
698 : "Failed to copy content oid for "
699 : "EnvelopedData");
700 0 : goto out;
701 : }
702 :
703 0 : ed.unprotectedAttrs = NULL;
704 :
705 0 : ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
706 : &ed, &size, ret);
707 0 : if (ret) {
708 0 : hx509_set_error_string(context, 0, ret,
709 : "Failed to encode EnvelopedData");
710 0 : goto out;
711 : }
712 0 : if (size != content->length)
713 0 : _hx509_abort("internal ASN.1 encoder error");
714 :
715 0 : out:
716 0 : if (crypto)
717 0 : hx509_crypto_destroy(crypto);
718 0 : if (ret)
719 0 : der_free_octet_string(content);
720 0 : der_free_octet_string(&key);
721 0 : der_free_octet_string(&ivec);
722 0 : free_EnvelopedData(&ed);
723 :
724 0 : return ret;
725 : }
726 :
727 : static int
728 0 : any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
729 : {
730 : int ret;
731 : size_t i;
732 :
733 0 : if (sd->certificates == NULL)
734 0 : return 0;
735 :
736 0 : for (i = 0; i < sd->certificates->len; i++) {
737 : heim_error_t error;
738 : hx509_cert c;
739 :
740 0 : c = hx509_cert_init_data(context,
741 0 : sd->certificates->val[i].data,
742 0 : sd->certificates->val[i].length,
743 : &error);
744 0 : if (c == NULL) {
745 0 : ret = heim_error_get_code(error);
746 0 : heim_release(error);
747 0 : return ret;
748 : }
749 0 : ret = hx509_certs_add(context, certs, c);
750 0 : hx509_cert_free(c);
751 0 : if (ret)
752 0 : return ret;
753 : }
754 :
755 0 : return 0;
756 : }
757 :
758 : static const Attribute *
759 0 : find_attribute(const CMSAttributes *attr, const heim_oid *oid)
760 : {
761 : size_t i;
762 0 : for (i = 0; i < attr->len; i++)
763 0 : if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
764 0 : return &attr->val[i];
765 0 : return NULL;
766 : }
767 :
768 : /**
769 : * Decode SignedData and verify that the signature is correct.
770 : *
771 : * @param context A hx509 context.
772 : * @param ctx a hx509 verify context.
773 : * @param flags to control the behaivor of the function.
774 : * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
775 : * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
776 : * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
777 : * @param data pointer to CMS SignedData encoded data.
778 : * @param length length of the data that data point to.
779 : * @param signedContent external data used for signature.
780 : * @param pool certificate pool to build certificates paths.
781 : * @param contentType free with der_free_oid().
782 : * @param content the output of the function, free with
783 : * der_free_octet_string().
784 : * @param signer_certs list of the cerficates used to sign this
785 : * request, free with hx509_certs_free().
786 : *
787 : * @return an hx509 error code.
788 : *
789 : * @ingroup hx509_cms
790 : */
791 :
792 : HX509_LIB_FUNCTION int HX509_LIB_CALL
793 0 : hx509_cms_verify_signed(hx509_context context,
794 : hx509_verify_ctx ctx,
795 : unsigned int flags,
796 : const void *data,
797 : size_t length,
798 : const heim_octet_string *signedContent,
799 : hx509_certs pool,
800 : heim_oid *contentType,
801 : heim_octet_string *content,
802 : hx509_certs *signer_certs)
803 : {
804 : unsigned int verify_flags;
805 :
806 0 : return hx509_cms_verify_signed_ext(context,
807 : ctx,
808 : flags,
809 : data,
810 : length,
811 : signedContent,
812 : pool,
813 : contentType,
814 : content,
815 : signer_certs,
816 : &verify_flags);
817 : }
818 :
819 : /**
820 : * Decode SignedData and verify that the signature is correct.
821 : *
822 : * @param context A hx509 context.
823 : * @param ctx a hx509 verify context.
824 : * @param flags to control the behaivor of the function.
825 : * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
826 : * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
827 : * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
828 : * @param data pointer to CMS SignedData encoded data.
829 : * @param length length of the data that data point to.
830 : * @param signedContent external data used for signature.
831 : * @param pool certificate pool to build certificates paths.
832 : * @param contentType free with der_free_oid().
833 : * @param content the output of the function, free with
834 : * der_free_octet_string().
835 : * @param signer_certs list of the cerficates used to sign this
836 : * request, free with hx509_certs_free().
837 : * @param verify_flags flags indicating whether the certificate
838 : * was verified or not
839 : *
840 : * @return an hx509 error code.
841 : *
842 : * @ingroup hx509_cms
843 : */
844 :
845 : HX509_LIB_FUNCTION int HX509_LIB_CALL
846 0 : hx509_cms_verify_signed_ext(hx509_context context,
847 : hx509_verify_ctx ctx,
848 : unsigned int flags,
849 : const void *data,
850 : size_t length,
851 : const heim_octet_string *signedContent,
852 : hx509_certs pool,
853 : heim_oid *contentType,
854 : heim_octet_string *content,
855 : hx509_certs *signer_certs,
856 : unsigned int *verify_flags)
857 : {
858 : SignerInfo *signer_info;
859 0 : hx509_cert cert = NULL;
860 0 : hx509_certs certs = NULL;
861 : SignedData sd;
862 : size_t size;
863 : int ret, found_valid_sig;
864 : size_t i;
865 :
866 0 : *signer_certs = NULL;
867 0 : *verify_flags = 0;
868 :
869 0 : content->data = NULL;
870 0 : content->length = 0;
871 0 : contentType->length = 0;
872 0 : contentType->components = NULL;
873 :
874 0 : memset(&sd, 0, sizeof(sd));
875 :
876 0 : ret = decode_SignedData(data, length, &sd, &size);
877 0 : if (ret) {
878 0 : hx509_set_error_string(context, 0, ret,
879 : "Failed to decode SignedData");
880 0 : goto out;
881 : }
882 :
883 0 : if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
884 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
885 0 : hx509_set_error_string(context, 0, ret,
886 : "No content data in SignedData");
887 0 : goto out;
888 : }
889 0 : if (sd.encapContentInfo.eContent && signedContent) {
890 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
891 0 : hx509_set_error_string(context, 0, ret,
892 : "Both external and internal SignedData");
893 0 : goto out;
894 : }
895 :
896 0 : if (sd.encapContentInfo.eContent)
897 0 : ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
898 : else
899 0 : ret = der_copy_octet_string(signedContent, content);
900 0 : if (ret) {
901 0 : hx509_set_error_string(context, 0, ret, "malloc: out of memory");
902 0 : goto out;
903 : }
904 :
905 0 : ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
906 : 0, NULL, &certs);
907 0 : if (ret)
908 0 : goto out;
909 :
910 0 : ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
911 : 0, NULL, signer_certs);
912 0 : if (ret)
913 0 : goto out;
914 :
915 : /* XXX Check CMS version */
916 :
917 0 : ret = any_to_certs(context, &sd, certs);
918 0 : if (ret)
919 0 : goto out;
920 :
921 0 : if (pool) {
922 0 : ret = hx509_certs_merge(context, certs, pool);
923 0 : if (ret)
924 0 : goto out;
925 : }
926 :
927 0 : for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
928 0 : heim_octet_string signed_data = { 0, 0 };
929 : const heim_oid *match_oid;
930 : heim_oid decode_oid;
931 :
932 0 : signer_info = &sd.signerInfos.val[i];
933 0 : match_oid = NULL;
934 :
935 0 : if (signer_info->signature.length == 0) {
936 0 : ret = HX509_CMS_MISSING_SIGNER_DATA;
937 0 : hx509_set_error_string(context, 0, ret,
938 : "SignerInfo %d in SignedData "
939 : "missing sigature", i);
940 0 : continue;
941 : }
942 :
943 0 : ret = find_CMSIdentifier(context, &signer_info->sid, certs,
944 : _hx509_verify_get_time(ctx), &cert,
945 : HX509_QUERY_KU_DIGITALSIGNATURE);
946 0 : if (ret) {
947 : /**
948 : * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
949 : * search for matching certificates by not considering
950 : * KeyUsage bits on the certificates.
951 : */
952 0 : if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
953 0 : continue;
954 :
955 0 : ret = find_CMSIdentifier(context, &signer_info->sid, certs,
956 : _hx509_verify_get_time(ctx), &cert,
957 : 0);
958 0 : if (ret)
959 0 : continue;
960 :
961 : }
962 :
963 0 : if (signer_info->signedAttrs) {
964 : const Attribute *attr;
965 :
966 : CMSAttributes sa;
967 : heim_octet_string os;
968 :
969 0 : sa.val = signer_info->signedAttrs->val;
970 0 : sa.len = signer_info->signedAttrs->len;
971 :
972 : /* verify that sigature exists */
973 0 : attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
974 0 : if (attr == NULL) {
975 0 : ret = HX509_CRYPTO_SIGNATURE_MISSING;
976 0 : hx509_set_error_string(context, 0, ret,
977 : "SignerInfo have signed attributes "
978 : "but messageDigest (signature) "
979 : "is missing");
980 0 : goto next_sigature;
981 : }
982 0 : if (attr->value.len != 1) {
983 0 : ret = HX509_CRYPTO_SIGNATURE_MISSING;
984 0 : hx509_set_error_string(context, 0, ret,
985 : "SignerInfo have more then one "
986 : "messageDigest (signature)");
987 0 : goto next_sigature;
988 : }
989 :
990 0 : ret = decode_MessageDigest(attr->value.val[0].data,
991 0 : attr->value.val[0].length,
992 : &os,
993 : &size);
994 0 : if (ret) {
995 0 : hx509_set_error_string(context, 0, ret,
996 : "Failed to decode "
997 : "messageDigest (signature)");
998 0 : goto next_sigature;
999 : }
1000 :
1001 0 : ret = _hx509_verify_signature(context,
1002 : NULL,
1003 0 : &signer_info->digestAlgorithm,
1004 : content,
1005 : &os);
1006 0 : der_free_octet_string(&os);
1007 0 : if (ret) {
1008 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1009 : "Failed to verify messageDigest");
1010 0 : goto next_sigature;
1011 : }
1012 :
1013 : /*
1014 : * Fetch content oid inside signedAttrs or set it to
1015 : * id-pkcs7-data.
1016 : */
1017 0 : attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
1018 0 : if (attr == NULL) {
1019 0 : match_oid = &asn1_oid_id_pkcs7_data;
1020 : } else {
1021 0 : if (attr->value.len != 1) {
1022 0 : ret = HX509_CMS_DATA_OID_MISMATCH;
1023 0 : hx509_set_error_string(context, 0, ret,
1024 : "More then one oid in signedAttrs");
1025 0 : goto next_sigature;
1026 :
1027 : }
1028 0 : ret = decode_ContentType(attr->value.val[0].data,
1029 0 : attr->value.val[0].length,
1030 : &decode_oid,
1031 : &size);
1032 0 : if (ret) {
1033 0 : hx509_set_error_string(context, 0, ret,
1034 : "Failed to decode "
1035 : "oid in signedAttrs");
1036 0 : goto next_sigature;
1037 : }
1038 0 : match_oid = &decode_oid;
1039 : }
1040 :
1041 0 : ASN1_MALLOC_ENCODE(CMSAttributes,
1042 : signed_data.data,
1043 : signed_data.length,
1044 : &sa,
1045 : &size, ret);
1046 0 : if (ret) {
1047 0 : if (match_oid == &decode_oid)
1048 0 : der_free_oid(&decode_oid);
1049 0 : hx509_clear_error_string(context);
1050 0 : goto next_sigature;
1051 : }
1052 0 : if (size != signed_data.length)
1053 0 : _hx509_abort("internal ASN.1 encoder error");
1054 :
1055 : } else {
1056 0 : signed_data.data = content->data;
1057 0 : signed_data.length = content->length;
1058 0 : match_oid = &asn1_oid_id_pkcs7_data;
1059 : }
1060 :
1061 : /**
1062 : * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
1063 : * encapContentInfo mismatch with the oid in signedAttributes
1064 : * (or if no signedAttributes where use, pkcs7-data oid).
1065 : * This is only needed to work with broken CMS implementations
1066 : * that doesn't follow CMS signedAttributes rules.
1067 : */
1068 :
1069 0 : if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
1070 0 : (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
1071 0 : ret = HX509_CMS_DATA_OID_MISMATCH;
1072 0 : hx509_set_error_string(context, 0, ret,
1073 : "Oid in message mismatch from the expected");
1074 : }
1075 0 : if (match_oid == &decode_oid)
1076 0 : der_free_oid(&decode_oid);
1077 :
1078 0 : if (ret == 0) {
1079 0 : ret = hx509_verify_signature(context,
1080 : cert,
1081 0 : &signer_info->signatureAlgorithm,
1082 : &signed_data,
1083 0 : &signer_info->signature);
1084 0 : if (ret)
1085 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1086 : "Failed to verify signature in "
1087 : "CMS SignedData");
1088 : }
1089 0 : if (signed_data.data != NULL && content->data != signed_data.data) {
1090 0 : free(signed_data.data);
1091 0 : signed_data.data = NULL;
1092 : }
1093 0 : if (ret)
1094 0 : goto next_sigature;
1095 :
1096 : /**
1097 : * If HX509_CMS_VS_NO_VALIDATE flags is set, return the signer
1098 : * certificate unconditionally but do not set HX509_CMS_VSE_VALIDATED.
1099 : */
1100 0 : ret = hx509_verify_path(context, ctx, cert, certs);
1101 0 : if (ret == 0 || (flags & HX509_CMS_VS_NO_VALIDATE)) {
1102 0 : if (ret == 0)
1103 0 : *verify_flags |= HX509_CMS_VSE_VALIDATED;
1104 :
1105 0 : ret = hx509_certs_add(context, *signer_certs, cert);
1106 0 : if (ret == 0)
1107 0 : found_valid_sig++;
1108 : }
1109 :
1110 0 : next_sigature:
1111 0 : if (cert)
1112 0 : hx509_cert_free(cert);
1113 0 : cert = NULL;
1114 : }
1115 : /**
1116 : * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
1117 : * SignerInfo (no signatures). If SignedData have no signatures,
1118 : * the function will return 0 with signer_certs set to NULL. Zero
1119 : * signers is allowed by the standard, but since its only useful
1120 : * in corner cases, it make into a flag that the caller have to
1121 : * turn on.
1122 : */
1123 0 : if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
1124 0 : if (*signer_certs)
1125 0 : hx509_certs_free(signer_certs);
1126 0 : } else if (found_valid_sig == 0) {
1127 0 : if (ret == 0) {
1128 0 : ret = HX509_CMS_SIGNER_NOT_FOUND;
1129 0 : hx509_set_error_string(context, 0, ret,
1130 : "No signers where found");
1131 : }
1132 0 : goto out;
1133 : }
1134 :
1135 0 : ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
1136 0 : if (ret) {
1137 0 : hx509_clear_error_string(context);
1138 0 : goto out;
1139 : }
1140 :
1141 0 : out:
1142 0 : free_SignedData(&sd);
1143 0 : if (certs)
1144 0 : hx509_certs_free(&certs);
1145 0 : if (ret) {
1146 0 : if (content->data)
1147 0 : der_free_octet_string(content);
1148 0 : if (*signer_certs)
1149 0 : hx509_certs_free(signer_certs);
1150 0 : der_free_oid(contentType);
1151 0 : der_free_octet_string(content);
1152 : }
1153 :
1154 0 : return ret;
1155 : }
1156 :
1157 : static int
1158 0 : add_one_attribute(Attribute **attr,
1159 : unsigned int *len,
1160 : const heim_oid *oid,
1161 : heim_octet_string *data)
1162 : {
1163 : void *d;
1164 : int ret;
1165 :
1166 0 : d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
1167 0 : if (d == NULL)
1168 0 : return ENOMEM;
1169 0 : (*attr) = d;
1170 :
1171 0 : ret = der_copy_oid(oid, &(*attr)[*len].type);
1172 0 : if (ret)
1173 0 : return ret;
1174 :
1175 0 : ALLOC_SEQ(&(*attr)[*len].value, 1);
1176 0 : if ((*attr)[*len].value.val == NULL) {
1177 0 : der_free_oid(&(*attr)[*len].type);
1178 0 : return ENOMEM;
1179 : }
1180 :
1181 0 : (*attr)[*len].value.val[0].data = data->data;
1182 0 : (*attr)[*len].value.val[0].length = data->length;
1183 :
1184 0 : *len += 1;
1185 :
1186 0 : return 0;
1187 : }
1188 :
1189 : /**
1190 : * Decode SignedData and verify that the signature is correct.
1191 : *
1192 : * @param context A hx509 context.
1193 : * @param flags
1194 : * @param eContentType the type of the data.
1195 : * @param data data to sign
1196 : * @param length length of the data that data point to.
1197 : * @param digest_alg digest algorithm to use, use NULL to get the
1198 : * default or the peer determined algorithm.
1199 : * @param cert certificate to use for sign the data.
1200 : * @param peer info about the peer the message to send the message to,
1201 : * like what digest algorithm to use.
1202 : * @param anchors trust anchors that the client will use, used to
1203 : * polulate the certificates included in the message
1204 : * @param pool certificates to use in try to build the path to the
1205 : * trust anchors.
1206 : * @param signed_data the output of the function, free with
1207 : * der_free_octet_string().
1208 : *
1209 : * @return Returns an hx509 error code.
1210 : *
1211 : * @ingroup hx509_cms
1212 : */
1213 :
1214 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1215 77 : hx509_cms_create_signed_1(hx509_context context,
1216 : int flags,
1217 : const heim_oid *eContentType,
1218 : const void *data, size_t length,
1219 : const AlgorithmIdentifier *digest_alg,
1220 : hx509_cert cert,
1221 : hx509_peer_info peer,
1222 : hx509_certs anchors,
1223 : hx509_certs pool,
1224 : heim_octet_string *signed_data)
1225 : {
1226 : hx509_certs certs;
1227 77 : int ret = 0;
1228 :
1229 77 : signed_data->data = NULL;
1230 77 : signed_data->length = 0;
1231 :
1232 77 : ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
1233 77 : if (ret)
1234 0 : return ret;
1235 77 : ret = hx509_certs_add(context, certs, cert);
1236 77 : if (ret)
1237 0 : goto out;
1238 :
1239 77 : ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
1240 : digest_alg, certs, peer, anchors, pool,
1241 : signed_data);
1242 :
1243 77 : out:
1244 77 : hx509_certs_free(&certs);
1245 77 : return ret;
1246 : }
1247 :
1248 : struct sigctx {
1249 : SignedData sd;
1250 : const AlgorithmIdentifier *digest_alg;
1251 : const heim_oid *eContentType;
1252 : heim_octet_string content;
1253 : hx509_peer_info peer;
1254 : int cmsidflag;
1255 : int leafonly;
1256 : hx509_certs certs;
1257 : hx509_certs anchors;
1258 : hx509_certs pool;
1259 : };
1260 :
1261 : static int HX509_LIB_CALL
1262 0 : sig_process(hx509_context context, void *ctx, hx509_cert cert)
1263 : {
1264 0 : struct sigctx *sigctx = ctx;
1265 0 : heim_octet_string buf, sigdata = { 0, NULL };
1266 0 : SignerInfo *signer_info = NULL;
1267 : AlgorithmIdentifier digest;
1268 : size_t size;
1269 : void *ptr;
1270 : int ret;
1271 0 : SignedData *sd = &sigctx->sd;
1272 : hx509_path path;
1273 :
1274 0 : memset(&digest, 0, sizeof(digest));
1275 0 : memset(&path, 0, sizeof(path));
1276 :
1277 0 : if (_hx509_cert_private_key(cert) == NULL) {
1278 0 : hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1279 : "Private key missing for signing");
1280 0 : return HX509_PRIVATE_KEY_MISSING;
1281 : }
1282 :
1283 0 : if (sigctx->digest_alg) {
1284 0 : ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
1285 0 : if (ret)
1286 0 : hx509_clear_error_string(context);
1287 : } else {
1288 0 : ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
1289 : _hx509_cert_private_key(cert),
1290 : sigctx->peer, &digest);
1291 : }
1292 0 : if (ret)
1293 0 : goto out;
1294 :
1295 : /*
1296 : * Allocate on more signerInfo and do the signature processing
1297 : */
1298 :
1299 0 : ptr = realloc(sd->signerInfos.val,
1300 0 : (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
1301 0 : if (ptr == NULL) {
1302 0 : ret = ENOMEM;
1303 0 : goto out;
1304 : }
1305 0 : sd->signerInfos.val = ptr;
1306 :
1307 0 : signer_info = &sd->signerInfos.val[sd->signerInfos.len];
1308 :
1309 0 : memset(signer_info, 0, sizeof(*signer_info));
1310 :
1311 0 : signer_info->version = 1;
1312 :
1313 0 : ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
1314 0 : if (ret) {
1315 0 : hx509_clear_error_string(context);
1316 0 : goto out;
1317 : }
1318 :
1319 0 : signer_info->signedAttrs = NULL;
1320 0 : signer_info->unsignedAttrs = NULL;
1321 :
1322 0 : ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1323 0 : if (ret) {
1324 0 : hx509_clear_error_string(context);
1325 0 : goto out;
1326 : }
1327 :
1328 : /*
1329 : * If it isn't pkcs7-data send signedAttributes
1330 : */
1331 :
1332 0 : if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) {
1333 : CMSAttributes sa;
1334 : heim_octet_string sig;
1335 :
1336 0 : ALLOC(signer_info->signedAttrs, 1);
1337 0 : if (signer_info->signedAttrs == NULL) {
1338 0 : ret = ENOMEM;
1339 0 : goto out;
1340 : }
1341 :
1342 0 : ret = _hx509_create_signature(context,
1343 : NULL,
1344 : &digest,
1345 0 : &sigctx->content,
1346 : NULL,
1347 : &sig);
1348 0 : if (ret)
1349 0 : goto out;
1350 :
1351 0 : ASN1_MALLOC_ENCODE(MessageDigest,
1352 : buf.data,
1353 : buf.length,
1354 : &sig,
1355 : &size,
1356 : ret);
1357 0 : der_free_octet_string(&sig);
1358 0 : if (ret) {
1359 0 : hx509_clear_error_string(context);
1360 0 : goto out;
1361 : }
1362 0 : if (size != buf.length)
1363 0 : _hx509_abort("internal ASN.1 encoder error");
1364 :
1365 0 : ret = add_one_attribute(&signer_info->signedAttrs->val,
1366 0 : &signer_info->signedAttrs->len,
1367 : &asn1_oid_id_pkcs9_messageDigest,
1368 : &buf);
1369 0 : if (ret) {
1370 0 : free(buf.data);
1371 0 : hx509_clear_error_string(context);
1372 0 : goto out;
1373 : }
1374 :
1375 :
1376 0 : ASN1_MALLOC_ENCODE(ContentType,
1377 : buf.data,
1378 : buf.length,
1379 : sigctx->eContentType,
1380 : &size,
1381 : ret);
1382 0 : if (ret)
1383 0 : goto out;
1384 0 : if (size != buf.length)
1385 0 : _hx509_abort("internal ASN.1 encoder error");
1386 :
1387 0 : ret = add_one_attribute(&signer_info->signedAttrs->val,
1388 0 : &signer_info->signedAttrs->len,
1389 : &asn1_oid_id_pkcs9_contentType,
1390 : &buf);
1391 0 : if (ret) {
1392 0 : free(buf.data);
1393 0 : hx509_clear_error_string(context);
1394 0 : goto out;
1395 : }
1396 :
1397 0 : sa.val = signer_info->signedAttrs->val;
1398 0 : sa.len = signer_info->signedAttrs->len;
1399 :
1400 0 : ASN1_MALLOC_ENCODE(CMSAttributes,
1401 : sigdata.data,
1402 : sigdata.length,
1403 : &sa,
1404 : &size,
1405 : ret);
1406 0 : if (ret) {
1407 0 : hx509_clear_error_string(context);
1408 0 : goto out;
1409 : }
1410 0 : if (size != sigdata.length)
1411 0 : _hx509_abort("internal ASN.1 encoder error");
1412 : } else {
1413 0 : sigdata.data = sigctx->content.data;
1414 0 : sigdata.length = sigctx->content.length;
1415 : }
1416 :
1417 : {
1418 : AlgorithmIdentifier sigalg;
1419 :
1420 0 : ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1421 : _hx509_cert_private_key(cert), sigctx->peer,
1422 : &sigalg);
1423 0 : if (ret)
1424 0 : goto out;
1425 :
1426 0 : ret = _hx509_create_signature(context,
1427 : _hx509_cert_private_key(cert),
1428 : &sigalg,
1429 : &sigdata,
1430 0 : &signer_info->signatureAlgorithm,
1431 0 : &signer_info->signature);
1432 0 : free_AlgorithmIdentifier(&sigalg);
1433 0 : if (ret)
1434 0 : goto out;
1435 : }
1436 :
1437 0 : sigctx->sd.signerInfos.len++;
1438 0 : signer_info = NULL;
1439 :
1440 : /*
1441 : * Provide best effort path
1442 : */
1443 0 : if (sigctx->certs) {
1444 : unsigned int i;
1445 :
1446 0 : if (sigctx->pool && sigctx->leafonly == 0) {
1447 0 : _hx509_calculate_path(context,
1448 : HX509_CALCULATE_PATH_NO_ANCHOR,
1449 : time(NULL),
1450 : sigctx->anchors,
1451 : 0,
1452 : cert,
1453 : sigctx->pool,
1454 : &path);
1455 : } else
1456 0 : _hx509_path_append(context, &path, cert);
1457 :
1458 0 : for (i = 0; i < path.len; i++) {
1459 : /* XXX remove dups */
1460 0 : ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
1461 0 : if (ret) {
1462 0 : hx509_clear_error_string(context);
1463 0 : goto out;
1464 : }
1465 : }
1466 : }
1467 :
1468 0 : out:
1469 0 : if (signer_info)
1470 0 : free_SignerInfo(signer_info);
1471 0 : if (sigdata.data != sigctx->content.data)
1472 0 : der_free_octet_string(&sigdata);
1473 0 : _hx509_path_free(&path);
1474 0 : free_AlgorithmIdentifier(&digest);
1475 :
1476 0 : return ret;
1477 : }
1478 :
1479 : static int HX509_LIB_CALL
1480 0 : cert_process(hx509_context context, void *ctx, hx509_cert cert)
1481 : {
1482 0 : struct sigctx *sigctx = ctx;
1483 0 : const unsigned int i = sigctx->sd.certificates->len;
1484 : void *ptr;
1485 : int ret;
1486 :
1487 0 : ptr = realloc(sigctx->sd.certificates->val,
1488 0 : (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
1489 0 : if (ptr == NULL)
1490 0 : return ENOMEM;
1491 0 : sigctx->sd.certificates->val = ptr;
1492 :
1493 0 : ret = hx509_cert_binary(context, cert,
1494 0 : &sigctx->sd.certificates->val[i]);
1495 0 : if (ret == 0)
1496 0 : sigctx->sd.certificates->len++;
1497 :
1498 0 : return ret;
1499 : }
1500 :
1501 : static int
1502 0 : cmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q)
1503 : {
1504 0 : return der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1505 : }
1506 :
1507 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1508 77 : hx509_cms_create_signed(hx509_context context,
1509 : int flags,
1510 : const heim_oid *eContentType,
1511 : const void *data, size_t length,
1512 : const AlgorithmIdentifier *digest_alg,
1513 : hx509_certs certs,
1514 : hx509_peer_info peer,
1515 : hx509_certs anchors,
1516 : hx509_certs pool,
1517 : heim_octet_string *signed_data)
1518 : {
1519 : unsigned int i, j;
1520 : hx509_name name;
1521 : int ret;
1522 : size_t size;
1523 : struct sigctx sigctx;
1524 :
1525 77 : memset(&sigctx, 0, sizeof(sigctx));
1526 77 : memset(&name, 0, sizeof(name));
1527 :
1528 77 : if (eContentType == NULL)
1529 0 : eContentType = &asn1_oid_id_pkcs7_data;
1530 :
1531 77 : sigctx.digest_alg = digest_alg;
1532 77 : sigctx.content.data = rk_UNCONST(data);
1533 77 : sigctx.content.length = length;
1534 77 : sigctx.eContentType = eContentType;
1535 77 : sigctx.peer = peer;
1536 : /**
1537 : * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
1538 : * and serial number if possible. Otherwise subject key identifier
1539 : * will preferred.
1540 : */
1541 77 : if (flags & HX509_CMS_SIGNATURE_ID_NAME)
1542 0 : sigctx.cmsidflag = CMS_ID_NAME;
1543 : else
1544 77 : sigctx.cmsidflag = CMS_ID_SKI;
1545 :
1546 : /**
1547 : * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
1548 : * certificates to be added to the SignedData.
1549 : */
1550 77 : sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;
1551 :
1552 : /**
1553 : * Use HX509_CMS_NO_CERTS to make the SignedData contain no
1554 : * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
1555 : */
1556 :
1557 77 : if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
1558 77 : ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
1559 77 : if (ret)
1560 0 : return ret;
1561 : }
1562 :
1563 77 : sigctx.anchors = anchors;
1564 77 : sigctx.pool = pool;
1565 :
1566 77 : sigctx.sd.version = cMSVersion_v3;
1567 :
1568 77 : ret = der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
1569 77 : if (ret)
1570 0 : goto out;
1571 :
1572 : /**
1573 : * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
1574 : */
1575 77 : if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
1576 77 : ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
1577 77 : if (sigctx.sd.encapContentInfo.eContent == NULL) {
1578 0 : hx509_clear_error_string(context);
1579 0 : ret = ENOMEM;
1580 0 : goto out;
1581 : }
1582 :
1583 77 : sigctx.sd.encapContentInfo.eContent->data = malloc(length);
1584 77 : if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
1585 0 : hx509_clear_error_string(context);
1586 0 : ret = ENOMEM;
1587 0 : goto out;
1588 : }
1589 77 : memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
1590 77 : sigctx.sd.encapContentInfo.eContent->length = length;
1591 : }
1592 :
1593 : /**
1594 : * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
1595 : * signatures).
1596 : */
1597 77 : if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
1598 0 : ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
1599 0 : if (ret)
1600 0 : goto out;
1601 : }
1602 :
1603 77 : if (sigctx.sd.signerInfos.len) {
1604 :
1605 : /*
1606 : * For each signerInfo, collect all different digest types.
1607 : */
1608 0 : for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
1609 0 : AlgorithmIdentifier *di =
1610 0 : &sigctx.sd.signerInfos.val[i].digestAlgorithm;
1611 :
1612 0 : for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
1613 0 : if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
1614 0 : break;
1615 0 : if (j == sigctx.sd.digestAlgorithms.len) {
1616 0 : ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
1617 0 : if (ret) {
1618 0 : hx509_clear_error_string(context);
1619 0 : goto out;
1620 : }
1621 : }
1622 : }
1623 : }
1624 :
1625 : /*
1626 : * Add certs we think are needed, build as part of sig_process
1627 : */
1628 77 : if (sigctx.certs) {
1629 77 : ALLOC(sigctx.sd.certificates, 1);
1630 77 : if (sigctx.sd.certificates == NULL) {
1631 0 : hx509_clear_error_string(context);
1632 0 : ret = ENOMEM;
1633 0 : goto out;
1634 : }
1635 :
1636 77 : ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
1637 77 : if (ret)
1638 0 : goto out;
1639 : }
1640 :
1641 77 : ASN1_MALLOC_ENCODE(SignedData,
1642 : signed_data->data, signed_data->length,
1643 : &sigctx.sd, &size, ret);
1644 77 : if (ret) {
1645 0 : hx509_clear_error_string(context);
1646 0 : goto out;
1647 : }
1648 77 : if (signed_data->length != size)
1649 0 : _hx509_abort("internal ASN.1 encoder error");
1650 :
1651 154 : out:
1652 77 : hx509_certs_free(&sigctx.certs);
1653 77 : free_SignedData(&sigctx.sd);
1654 :
1655 77 : return ret;
1656 : }
1657 :
1658 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1659 0 : hx509_cms_decrypt_encrypted(hx509_context context,
1660 : hx509_lock lock,
1661 : const void *data,
1662 : size_t length,
1663 : heim_oid *contentType,
1664 : heim_octet_string *content)
1665 : {
1666 : heim_octet_string cont;
1667 : CMSEncryptedData ed;
1668 : AlgorithmIdentifier *ai;
1669 : int ret;
1670 :
1671 0 : memset(content, 0, sizeof(*content));
1672 0 : memset(&cont, 0, sizeof(cont));
1673 :
1674 0 : ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1675 0 : if (ret) {
1676 0 : hx509_set_error_string(context, 0, ret,
1677 : "Failed to decode CMSEncryptedData");
1678 0 : return ret;
1679 : }
1680 :
1681 0 : if (ed.encryptedContentInfo.encryptedContent == NULL) {
1682 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
1683 0 : hx509_set_error_string(context, 0, ret,
1684 : "No content in EncryptedData");
1685 0 : goto out;
1686 : }
1687 :
1688 0 : ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1689 0 : if (ret) {
1690 0 : hx509_clear_error_string(context);
1691 0 : goto out;
1692 : }
1693 :
1694 0 : ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1695 0 : if (ai->parameters == NULL) {
1696 0 : ret = HX509_ALG_NOT_SUPP;
1697 0 : hx509_clear_error_string(context);
1698 0 : goto out;
1699 : }
1700 :
1701 0 : ret = _hx509_pbe_decrypt(context,
1702 : lock,
1703 : ai,
1704 0 : ed.encryptedContentInfo.encryptedContent,
1705 : &cont);
1706 0 : if (ret)
1707 0 : goto out;
1708 :
1709 0 : *content = cont;
1710 :
1711 0 : out:
1712 0 : if (ret) {
1713 0 : if (cont.data)
1714 0 : free(cont.data);
1715 : }
1716 0 : free_CMSEncryptedData(&ed);
1717 0 : return ret;
1718 : }
|