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