63de9d1cde05c127fc4d6205a69305f657b37d20
[strongswan.git] / src / libstrongswan / plugins / pkcs7 / pkcs7_signed_data.c
1 /*
2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pkcs7_signed_data.h"
17
18 #include <time.h>
19
20 #include <utils/debug.h>
21 #include <asn1/oid.h>
22 #include <asn1/asn1.h>
23 #include <asn1/asn1_parser.h>
24 #include <crypto/pkcs9.h>
25 #include <credentials/sets/mem_cred.h>
26 #include <credentials/certificates/x509.h>
27 #include <credentials/keys/private_key.h>
28
29 typedef struct private_pkcs7_signed_data_t private_pkcs7_signed_data_t;
30
31 /**
32 * Private data of a PKCS#7 signed-data container.
33 */
34 struct private_pkcs7_signed_data_t {
35
36 /**
37 * Implements pkcs7_t.
38 */
39 pkcs7_t public;
40
41 /**
42 * Signed content data
43 */
44 container_t *content;
45
46 /**
47 * Encoded PKCS#7 signed-data
48 */
49 chunk_t encoding;
50
51 /**
52 * Attributes of first signerInfo
53 */
54 pkcs9_t *attributes;
55
56 /**
57 * Trustchain, if signature valid
58 */
59 auth_cfg_t *auth;
60 };
61
62 /**
63 * ASN.1 definition of the PKCS#7 signedData type
64 */
65 static const asn1Object_t signedDataObjects[] = {
66 { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
67 { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
68 { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
69 { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
70 { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
71 { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
72 { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
73 ASN1_LOOP }, /* 6 */
74 { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
75 { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
76 { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
77 ASN1_LOOP }, /* 9 */
78 { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
79 { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
80 { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
81 { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
82 { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
83 { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
84 { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
85 { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
86 { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
87 { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
88 ASN1_OBJ }, /* 19 */
89 { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
90 { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
91 { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
92 { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
93 { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
94 { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
95 { 0, "exit", ASN1_EOC, ASN1_EXIT }
96 };
97 #define PKCS7_VERSION 1
98 #define PKCS7_DIGEST_ALG 3
99 #define PKCS7_CONTENT_INFO 5
100 #define PKCS7_CERT 7
101 #define PKCS7_SIGNER_INFO 13
102 #define PKCS7_SIGNER_INFO_VERSION 14
103 #define PKCS7_ISSUER 16
104 #define PKCS7_SERIAL_NUMBER 17
105 #define PKCS7_DIGEST_ALGORITHM 18
106 #define PKCS7_AUTH_ATTRIBUTES 19
107 #define PKCS7_DIGEST_ENC_ALGORITHM 21
108 #define PKCS7_ENCRYPTED_DIGEST 22
109
110 METHOD(container_t, get_type, container_type_t,
111 private_pkcs7_signed_data_t *this)
112 {
113 return CONTAINER_PKCS7_SIGNED_DATA;
114 }
115
116 METHOD(container_t, create_signature_enumerator, enumerator_t*,
117 private_pkcs7_signed_data_t *this)
118 {
119 if (this->auth)
120 {
121 return enumerator_create_single(this->auth, NULL);
122 }
123 return enumerator_create_empty();
124 }
125
126 METHOD(container_t, get_data, bool,
127 private_pkcs7_signed_data_t *this, chunk_t *data)
128 {
129 if (this->content)
130 {
131 return this->content->get_data(this->content, data);
132 }
133 return FALSE;
134 }
135
136 METHOD(container_t, get_encoding, bool,
137 private_pkcs7_signed_data_t *this, chunk_t *data)
138 {
139 *data = chunk_clone(this->encoding);
140 return TRUE;
141 }
142
143 METHOD(container_t, destroy, void,
144 private_pkcs7_signed_data_t *this)
145 {
146 DESTROY_IF(this->auth);
147 DESTROY_IF(this->attributes);
148 DESTROY_IF(this->content);
149 free(this->encoding.ptr);
150 free(this);
151 }
152
153 /**
154 * Create an empty PKCS#7 signed-data container.
155 */
156 static private_pkcs7_signed_data_t* create_empty()
157 {
158 private_pkcs7_signed_data_t *this;
159
160 INIT(this,
161 .public = {
162 .container = {
163 .get_type = _get_type,
164 .create_signature_enumerator = _create_signature_enumerator,
165 .get_data = _get_data,
166 .get_encoding = _get_encoding,
167 .destroy = _destroy,
168 },
169 },
170 );
171
172 return this;
173 }
174
175 /**
176 * Verify signature
177 */
178 static bool verify_signature(private_pkcs7_signed_data_t *this, int signerInfos,
179 identification_t *serial, identification_t *issuer,
180 chunk_t digest, int digest_alg, int enc_alg)
181 {
182 signature_scheme_t scheme;
183 enumerator_t *enumerator;
184 certificate_t *cert;
185 public_key_t *key;
186 auth_cfg_t *auth;
187 chunk_t chunk;
188
189 scheme = signature_scheme_from_oid(digest_alg);
190 if (scheme == SIGN_UNKNOWN)
191 {
192 DBG1(DBG_LIB, "unsupported signature scheme");
193 return FALSE;
194 }
195 if (this->attributes == NULL)
196 {
197 DBG1(DBG_LIB, "no authenticatedAttributes object found");
198 return FALSE;
199 }
200 if (enc_alg != OID_RSA_ENCRYPTION)
201 {
202 DBG1(DBG_LIB, "only RSA digest encryption supported");
203 return FALSE;
204 }
205 if (signerInfos == 0)
206 {
207 DBG1(DBG_LIB, "no signerInfo object found");
208 return FALSE;
209 }
210 else if (signerInfos > 1)
211 {
212 DBG1(DBG_LIB, "more than one signerInfo object found");
213 return FALSE;
214 }
215
216 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
217 KEY_RSA, serial, FALSE);
218 while (enumerator->enumerate(enumerator, &cert, &auth))
219 {
220 if (issuer->equals(issuer, cert->get_issuer(cert)))
221 {
222 key = cert->get_public_key(cert);
223 if (key)
224 {
225 chunk = this->attributes->get_encoding(this->attributes);
226 if (key->verify(key, scheme, chunk, digest))
227 {
228 this->auth = auth->clone(auth);
229 break;
230 }
231 }
232 }
233 }
234 enumerator->destroy(enumerator);
235
236 if (this->content)
237 {
238 hash_algorithm_t algorithm;
239 hasher_t *hasher;
240 chunk_t hash, content;
241 bool valid;
242
243 chunk = this->attributes->get_attribute(this->attributes,
244 OID_PKCS9_MESSAGE_DIGEST);
245 if (chunk.ptr == NULL)
246 {
247 DBG1(DBG_LIB, "messageDigest attribute not found");
248 return FALSE;
249 }
250 if (!this->content->get_data(this->content, &content))
251 {
252 return FALSE;
253 }
254
255 algorithm = hasher_algorithm_from_oid(digest_alg);
256 hasher = lib->crypto->create_hasher(lib->crypto, algorithm);
257 if (!hasher || !hasher->allocate_hash(hasher, content, &hash))
258 {
259 free(content.ptr);
260 DESTROY_IF(hasher);
261 DBG1(DBG_LIB, "hash algorithm %N not supported",
262 hash_algorithm_names, algorithm);
263 return FALSE;
264 }
265 free(content.ptr);
266 hasher->destroy(hasher);
267 DBG3(DBG_LIB, "hash: %B", &hash);
268
269 valid = chunk_equals(chunk, hash);
270 free(hash.ptr);
271 if (valid)
272 {
273 DBG2(DBG_LIB, "messageDigest is valid");
274 }
275 else
276 {
277 DBG1(DBG_LIB, "invalid messageDigest");
278 return FALSE;
279 }
280 }
281 return TRUE;
282 }
283
284 /**
285 * Parse PKCS#7 signed data
286 */
287 static bool parse(private_pkcs7_signed_data_t *this, chunk_t content)
288 {
289 asn1_parser_t *parser;
290 identification_t *issuer = NULL, *serial = NULL;
291 chunk_t object, encrypted_digest = chunk_empty;
292 int objectID, version, digest_alg = OID_UNKNOWN, enc_alg = OID_UNKNOWN;
293 int signerInfos = 0;
294 bool success = FALSE;
295 mem_cred_t *creds;
296
297 creds = mem_cred_create();
298
299 parser = asn1_parser_create(signedDataObjects, content);
300 parser->set_top_level(parser, 0);
301 while (parser->iterate(parser, &objectID, &object))
302 {
303 u_int level = parser->get_level(parser);
304
305 switch (objectID)
306 {
307 case PKCS7_VERSION:
308 version = object.len ? (int)*object.ptr : 0;
309 DBG2(DBG_LIB, " v%d", version);
310 break;
311 case PKCS7_DIGEST_ALG:
312 digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
313 break;
314 case PKCS7_CONTENT_INFO:
315 this->content = lib->creds->create(lib->creds,
316 CRED_CONTAINER, CONTAINER_PKCS7,
317 BUILD_BLOB_ASN1_DER, object, BUILD_END);
318 break;
319 case PKCS7_CERT:
320 {
321 certificate_t *cert;
322
323 DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate");
324 cert = lib->creds->create(lib->creds,
325 CRED_CERTIFICATE, CERT_X509,
326 BUILD_BLOB_ASN1_DER, object,
327 BUILD_END);
328 if (cert)
329 {
330 creds->add_cert(creds, FALSE, cert);
331 }
332 break;
333 }
334 case PKCS7_SIGNER_INFO:
335 signerInfos++;
336 break;
337 case PKCS7_SIGNER_INFO_VERSION:
338 version = object.len ? (int)*object.ptr : 0;
339 DBG2(DBG_LIB, " v%d", version);
340 break;
341 case PKCS7_ISSUER:
342 if (!issuer)
343 {
344 issuer = identification_create_from_encoding(ID_DER_ASN1_DN,
345 object);
346 }
347 break;
348 case PKCS7_SERIAL_NUMBER:
349 if (!serial)
350 {
351 serial = identification_create_from_encoding(ID_KEY_ID,
352 object);
353 }
354 break;
355 case PKCS7_AUTH_ATTRIBUTES:
356 *object.ptr = ASN1_SET;
357 this->attributes = pkcs9_create_from_chunk(object, 1);
358 *object.ptr = ASN1_CONTEXT_C_0;
359 break;
360 case PKCS7_DIGEST_ALGORITHM:
361 digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
362 break;
363 case PKCS7_DIGEST_ENC_ALGORITHM:
364 enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
365 break;
366 case PKCS7_ENCRYPTED_DIGEST:
367 encrypted_digest = object;
368 break;
369 }
370 }
371 success = parser->success(parser);
372 parser->destroy(parser);
373
374 if (issuer)
375 {
376 if (serial)
377 {
378 if (success)
379 {
380 lib->credmgr->add_local_set(lib->credmgr, &creds->set, FALSE);
381 success = verify_signature(this, signerInfos, serial, issuer,
382 encrypted_digest, digest_alg, enc_alg);
383 lib->credmgr->remove_local_set(lib->credmgr, &creds->set);
384 }
385 serial->destroy(serial);
386 }
387 issuer->destroy(issuer);
388 }
389 creds->destroy(creds);
390
391 return success;
392 }
393
394 /**
395 * See header.
396 */
397 pkcs7_t *pkcs7_signed_data_load(chunk_t encoding, chunk_t content)
398 {
399 private_pkcs7_signed_data_t *this = create_empty();
400
401 this->encoding = chunk_clone(encoding);
402 if (!parse(this, content))
403 {
404 destroy(this);
405 return NULL;
406 }
407 return &this->public;
408 }
409
410 /**
411 * build a DER-encoded issuerAndSerialNumber object
412 */
413 static chunk_t build_issuerAndSerialNumber(certificate_t *cert)
414 {
415 identification_t *issuer = cert->get_issuer(cert);
416 chunk_t serial = chunk_empty;
417
418 if (cert->get_type(cert) == CERT_X509)
419 {
420 x509_t *x509 = (x509_t*)cert;
421 serial = x509->get_serial(x509);
422 }
423
424 return asn1_wrap(ASN1_SEQUENCE, "cm",
425 issuer->get_encoding(issuer),
426 asn1_integer("c", serial));
427 }
428
429 /**
430 * Generate a new PKCS#7 signed-data container
431 */
432 static bool generate(private_pkcs7_signed_data_t *this, private_key_t *key,
433 certificate_t *cert, hash_algorithm_t alg)
434 {
435 chunk_t authenticatedAttributes = chunk_empty;
436 chunk_t encryptedDigest = chunk_empty;
437 chunk_t data, signerInfo, encoding = chunk_empty;
438 chunk_t messageDigest, signingTime, attributes;
439 signature_scheme_t scheme;
440 hasher_t *hasher;
441 time_t now;
442 int digest_oid;
443
444 digest_oid = hasher_algorithm_to_oid(alg);
445 scheme = signature_scheme_from_oid(digest_oid);
446
447 if (!this->content->get_data(this->content, &data))
448 {
449 return FALSE;
450 }
451
452 hasher = lib->crypto->create_hasher(lib->crypto, alg);
453 if (!hasher || !hasher->allocate_hash(hasher, data, &messageDigest))
454 {
455 DESTROY_IF(hasher);
456 DBG1(DBG_LIB, " hash algorithm %N not support",
457 hash_algorithm_names, alg);
458 free(data.ptr);
459 return FALSE;
460 }
461 hasher->destroy(hasher);
462 this->attributes->add_attribute(this->attributes,
463 OID_PKCS9_MESSAGE_DIGEST,
464 asn1_wrap(ASN1_OCTET_STRING, "m", messageDigest));
465
466 /* take the current time as signingTime */
467 now = time(NULL);
468 signingTime = asn1_from_time(&now, ASN1_UTCTIME);
469 this->attributes->add_attribute(this->attributes,
470 OID_PKCS9_SIGNING_TIME, signingTime);
471 this->attributes->add_attribute(this->attributes,
472 OID_PKCS9_CONTENT_TYPE,
473 asn1_build_known_oid(OID_PKCS7_DATA));
474
475 attributes = this->attributes->get_encoding(this->attributes);
476
477 if (!key->sign(key, scheme, attributes, &encryptedDigest))
478 {
479 free(data.ptr);
480 return FALSE;
481 }
482 authenticatedAttributes = chunk_clone(attributes);
483 *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
484
485 free(data.ptr);
486 if (encryptedDigest.ptr)
487 {
488 encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", encryptedDigest);
489 }
490 signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm",
491 ASN1_INTEGER_1,
492 build_issuerAndSerialNumber(cert),
493 asn1_algorithmIdentifier(digest_oid),
494 authenticatedAttributes,
495 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
496 encryptedDigest);
497
498 if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
499 {
500 free(signerInfo.ptr);
501 return FALSE;
502 }
503 if (!this->content->get_encoding(this->content, &data))
504 {
505 free(encoding.ptr);
506 free(signerInfo.ptr);
507 return FALSE;
508 }
509
510 this->encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
511 asn1_build_known_oid(OID_PKCS7_SIGNED_DATA),
512 asn1_wrap(ASN1_CONTEXT_C_0, "m",
513 asn1_wrap(ASN1_SEQUENCE, "cmmmm",
514 ASN1_INTEGER_1,
515 asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_oid)),
516 data,
517 asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding),
518 asn1_wrap(ASN1_SET, "m", signerInfo))));
519
520 return TRUE;
521 }
522
523 /**
524 * See header.
525 */
526 pkcs7_t *pkcs7_signed_data_gen(container_type_t type, va_list args)
527 {
528 private_pkcs7_signed_data_t *this;
529 chunk_t blob = chunk_empty;
530 hash_algorithm_t alg = HASH_SHA1;
531 private_key_t *key = NULL;
532 certificate_t *cert = NULL;
533 pkcs9_t *pkcs9;
534 chunk_t value;
535 int oid;
536
537 pkcs9 = pkcs9_create();
538
539 while (TRUE)
540 {
541 switch (va_arg(args, builder_part_t))
542 {
543 case BUILD_SIGNING_KEY:
544 key = va_arg(args, private_key_t*);
545 continue;
546 case BUILD_SIGNING_CERT:
547 cert = va_arg(args, certificate_t*);
548 continue;
549 case BUILD_DIGEST_ALG:
550 alg = va_arg(args, int);
551 continue;
552 case BUILD_BLOB:
553 blob = va_arg(args, chunk_t);
554 continue;
555 case BUILD_PKCS7_ATTRIBUTE:
556 oid = va_arg(args, int);
557 value = va_arg(args, chunk_t);
558 pkcs9->add_attribute(pkcs9, oid, value);
559 continue;
560 case BUILD_END:
561 break;
562 default:
563 pkcs9->destroy(pkcs9);
564 return NULL;
565 }
566 break;
567 }
568 if (blob.len && key && cert)
569 {
570 this = create_empty();
571
572 this->attributes = pkcs9;
573 this->content = lib->creds->create(lib->creds,
574 CRED_CONTAINER, CONTAINER_PKCS7_DATA,
575 BUILD_BLOB, blob, BUILD_END);
576
577 if (this->content && generate(this, key, cert, alg))
578 {
579 return &this->public;
580 }
581 destroy(this);
582 }
583 else
584 {
585 pkcs9->destroy(pkcs9);
586 }
587 return NULL;
588 }