Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c, revision 1.1.1.1
1.1 misho 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: #include "pkcs7_attributes.h"
18:
19: #include <time.h>
20:
21: #include <utils/debug.h>
22: #include <asn1/oid.h>
23: #include <asn1/asn1.h>
24: #include <asn1/asn1_parser.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: * list of signerInfos, signerinfo_t
53: */
54: linked_list_t *signerinfos;
55:
56: /**
57: * Contained certificates
58: */
59: mem_cred_t *creds;
60: };
61:
62: /**
63: * A single signerInfo
64: */
65: typedef struct {
66:
67: /**
68: * Signed attributes of signerInfo
69: */
70: pkcs7_attributes_t *attributes;
71:
72: /**
73: * Serial of signing certificate
74: */
75: identification_t *serial;
76:
77: /**
78: * Issuer of signing certificate
79: */
80: identification_t *issuer;
81:
82: /**
83: * EncryptedDigest
84: */
85: chunk_t encrypted_digest;
86:
87: /**
88: * Digesting algorithm OID
89: */
90: int digest_alg;
91:
92: /**
93: * Public key encryption algorithm OID
94: */
95: int enc_alg;
96:
97: } signerinfo_t;
98:
99: /**
100: * Destroy a signerinfo_t entry
101: */
102: void signerinfo_destroy(signerinfo_t *this)
103: {
104: DESTROY_IF(this->attributes);
105: DESTROY_IF(this->serial);
106: DESTROY_IF(this->issuer);
107: free(this->encrypted_digest.ptr);
108: free(this);
109: }
110:
111: /**
112: * ASN.1 definition of the PKCS#7 signedData type
113: */
114: static const asn1Object_t signedDataObjects[] = {
115: { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
116: { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
117: { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
118: { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
119: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
120: { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
121: { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
122: ASN1_LOOP }, /* 6 */
123: { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
124: { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
125: { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
126: ASN1_LOOP }, /* 9 */
127: { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
128: { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
129: { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
130: { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
131: { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
132: { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
133: { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
134: { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
135: { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
136: { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
137: ASN1_OBJ }, /* 19 */
138: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
139: { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
140: { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
141: { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
142: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
143: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
144: { 0, "exit", ASN1_EOC, ASN1_EXIT }
145: };
146: #define PKCS7_VERSION 1
147: #define PKCS7_DIGEST_ALG 3
148: #define PKCS7_CONTENT_INFO 5
149: #define PKCS7_CERT 7
150: #define PKCS7_SIGNER_INFO 13
151: #define PKCS7_SIGNER_INFO_VERSION 14
152: #define PKCS7_ISSUER 16
153: #define PKCS7_SERIAL_NUMBER 17
154: #define PKCS7_DIGEST_ALGORITHM 18
155: #define PKCS7_AUTH_ATTRIBUTES 19
156: #define PKCS7_DIGEST_ENC_ALGORITHM 21
157: #define PKCS7_ENCRYPTED_DIGEST 22
158:
159: METHOD(container_t, get_type, container_type_t,
160: private_pkcs7_signed_data_t *this)
161: {
162: return CONTAINER_PKCS7_SIGNED_DATA;
163: }
164:
165: /**
166: * Signature enumerator implementation
167: */
168: typedef struct {
169: /** implements enumerator */
170: enumerator_t public;
171: /** inner signerinfos enumerator */
172: enumerator_t *inner;
173: /** currently enumerated auth_cfg */
174: auth_cfg_t *auth;
175: /** currently enumerating signerinfo */
176: signerinfo_t *info;
177: /** reference to container */
178: private_pkcs7_signed_data_t *this;
179: } signature_enumerator_t;
180:
181: METHOD(enumerator_t, enumerate, bool,
182: signature_enumerator_t *this, va_list args)
183: {
184: signerinfo_t *info;
185: signature_scheme_t scheme;
186: hash_algorithm_t algorithm;
187: enumerator_t *enumerator;
188: certificate_t *cert;
189: public_key_t *key;
190: auth_cfg_t *auth, **out;
191: chunk_t chunk, hash, content;
192: hasher_t *hasher;
193: bool valid;
194:
195: VA_ARGS_VGET(args, out);
196:
197: while (this->inner->enumerate(this->inner, &info))
198: {
199: /* clean up previous round */
200: DESTROY_IF(this->auth);
201: this->auth = NULL;
202:
203: scheme = signature_scheme_from_oid(info->digest_alg);
204: if (scheme == SIGN_UNKNOWN)
205: {
206: DBG1(DBG_LIB, "unsupported signature scheme");
207: continue;
208: }
209: if (!info->attributes)
210: {
211: DBG1(DBG_LIB, "no authenticatedAttributes object found");
212: continue;
213: }
214: if (info->enc_alg != OID_RSA_ENCRYPTION)
215: {
216: DBG1(DBG_LIB, "only RSA digest encryption supported");
217: continue;
218: }
219:
220: enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
221: KEY_RSA, info->serial, FALSE);
222: while (enumerator->enumerate(enumerator, &cert, &auth))
223: {
224: if (info->issuer->equals(info->issuer, cert->get_issuer(cert)))
225: {
226: key = cert->get_public_key(cert);
227: if (key)
228: {
229: chunk = info->attributes->get_encoding(info->attributes);
230: if (key->verify(key, scheme, NULL, chunk,
231: info->encrypted_digest))
232: {
233: this->auth = auth->clone(auth);
234: key->destroy(key);
235: break;
236: }
237: key->destroy(key);
238: }
239: }
240: }
241: enumerator->destroy(enumerator);
242:
243: if (!this->auth)
244: {
245: DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature");
246: continue;
247: }
248:
249: chunk = info->attributes->get_attribute(info->attributes,
250: OID_PKCS9_MESSAGE_DIGEST);
251: if (!chunk.len)
252: {
253: DBG1(DBG_LIB, "messageDigest attribute not found");
254: continue;
255: }
256: if (!this->this->content->get_data(this->this->content, &content))
257: {
258: continue;
259: }
260:
261: algorithm = hasher_algorithm_from_oid(info->digest_alg);
262: hasher = lib->crypto->create_hasher(lib->crypto, algorithm);
263: if (!hasher || !hasher->allocate_hash(hasher, content, &hash))
264: {
265: free(content.ptr);
266: DESTROY_IF(hasher);
267: DBG1(DBG_LIB, "hash algorithm %N not supported",
268: hash_algorithm_names, algorithm);
269: continue;
270: }
271: free(content.ptr);
272: hasher->destroy(hasher);
273: DBG3(DBG_LIB, "hash: %B", &hash);
274:
275: valid = chunk_equals_const(chunk, hash);
276: free(hash.ptr);
277: if (!valid)
278: {
279: DBG1(DBG_LIB, "invalid messageDigest");
280: continue;
281: }
282: *out = this->auth;
283: this->info = info;
284: return TRUE;
285: }
286: this->info = NULL;
287: return FALSE;
288: }
289:
290: METHOD(enumerator_t, enumerator_destroy, void,
291: signature_enumerator_t *this)
292: {
293: lib->credmgr->remove_local_set(lib->credmgr, &this->this->creds->set);
294: this->inner->destroy(this->inner);
295: DESTROY_IF(this->auth);
296: free(this);
297: }
298:
299: METHOD(container_t, create_signature_enumerator, enumerator_t*,
300: private_pkcs7_signed_data_t *this)
301: {
302: signature_enumerator_t *enumerator;
303:
304: INIT(enumerator,
305: .public = {
306: .enumerate = enumerator_enumerate_default,
307: .venumerate = _enumerate,
308: .destroy = _enumerator_destroy,
309: },
310: .inner = this->signerinfos->create_enumerator(this->signerinfos),
311: .this = this,
312: );
313:
314: lib->credmgr->add_local_set(lib->credmgr, &this->creds->set, FALSE);
315: return &enumerator->public;
316: }
317:
318: METHOD(pkcs7_t, get_attribute, bool,
319: private_pkcs7_signed_data_t *this, int oid, enumerator_t *enumerator, chunk_t *value)
320: {
321: signature_enumerator_t *e;
322: chunk_t chunk;
323:
324: e = (signature_enumerator_t*)enumerator;
325: if (e->info)
326: {
327: chunk = e->info->attributes->get_attribute(e->info->attributes, oid);
328: if (chunk.len)
329: {
330: *value = chunk_clone(chunk);
331: return TRUE;
332: }
333: }
334: return FALSE;
335: }
336:
337: METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*,
338: private_pkcs7_signed_data_t *this)
339: {
340: return this->creds->set.create_cert_enumerator(&this->creds->set,
341: CERT_ANY, KEY_ANY, NULL, FALSE);
342: }
343:
344: METHOD(container_t, get_data, bool,
345: private_pkcs7_signed_data_t *this, chunk_t *data)
346: {
347: if (this->content)
348: {
349: return this->content->get_data(this->content, data);
350: }
351: return FALSE;
352: }
353:
354: METHOD(container_t, get_encoding, bool,
355: private_pkcs7_signed_data_t *this, chunk_t *data)
356: {
357: *data = chunk_clone(this->encoding);
358: return TRUE;
359: }
360:
361: METHOD(container_t, destroy, void,
362: private_pkcs7_signed_data_t *this)
363: {
364: this->creds->destroy(this->creds);
365: this->signerinfos->destroy_function(this->signerinfos,
366: (void*)signerinfo_destroy);
367: DESTROY_IF(this->content);
368: free(this->encoding.ptr);
369: free(this);
370: }
371:
372: /**
373: * Create an empty PKCS#7 signed-data container.
374: */
375: static private_pkcs7_signed_data_t* create_empty()
376: {
377: private_pkcs7_signed_data_t *this;
378:
379: INIT(this,
380: .public = {
381: .container = {
382: .get_type = _get_type,
383: .create_signature_enumerator = _create_signature_enumerator,
384: .get_data = _get_data,
385: .get_encoding = _get_encoding,
386: .destroy = _destroy,
387: },
388: .get_attribute = _get_attribute,
389: .create_cert_enumerator = _create_cert_enumerator,
390: },
391: .creds = mem_cred_create(),
392: .signerinfos = linked_list_create(),
393: );
394:
395: return this;
396: }
397:
398: /**
399: * Parse PKCS#7 signed data
400: */
401: static bool parse(private_pkcs7_signed_data_t *this, chunk_t content)
402: {
403: asn1_parser_t *parser;
404: chunk_t object;
405: int objectID, version;
406: signerinfo_t *info = NULL;
407: bool success = FALSE;
408:
409: parser = asn1_parser_create(signedDataObjects, content);
410: parser->set_top_level(parser, 0);
411: while (parser->iterate(parser, &objectID, &object))
412: {
413: u_int level = parser->get_level(parser);
414:
415: switch (objectID)
416: {
417: case PKCS7_VERSION:
418: version = object.len ? (int)*object.ptr : 0;
419: DBG2(DBG_LIB, " v%d", version);
420: break;
421: case PKCS7_CONTENT_INFO:
422: this->content = lib->creds->create(lib->creds,
423: CRED_CONTAINER, CONTAINER_PKCS7,
424: BUILD_BLOB_ASN1_DER, object, BUILD_END);
425: break;
426: case PKCS7_CERT:
427: {
428: certificate_t *cert;
429:
430: DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate");
431: cert = lib->creds->create(lib->creds,
432: CRED_CERTIFICATE, CERT_X509,
433: BUILD_BLOB_ASN1_DER, object,
434: BUILD_END);
435: if (cert)
436: {
437: this->creds->add_cert(this->creds, FALSE, cert);
438: }
439: break;
440: }
441: case PKCS7_SIGNER_INFO:
442: INIT(info,
443: .digest_alg = OID_UNKNOWN,
444: .enc_alg = OID_UNKNOWN,
445: );
446: this->signerinfos->insert_last(this->signerinfos, info);
447: break;
448: case PKCS7_SIGNER_INFO_VERSION:
449: version = object.len ? (int)*object.ptr : 0;
450: DBG2(DBG_LIB, " v%d", version);
451: break;
452: case PKCS7_ISSUER:
453: info->issuer = identification_create_from_encoding(
454: ID_DER_ASN1_DN, object);
455: break;
456: case PKCS7_SERIAL_NUMBER:
457: info->serial = identification_create_from_encoding(
458: ID_KEY_ID, object);
459: break;
460: case PKCS7_AUTH_ATTRIBUTES:
461: *object.ptr = ASN1_SET;
462: info->attributes = pkcs7_attributes_create_from_chunk(
463: object, level+1);
464: *object.ptr = ASN1_CONTEXT_C_0;
465: break;
466: case PKCS7_DIGEST_ALGORITHM:
467: info->digest_alg = asn1_parse_algorithmIdentifier(object,
468: level, NULL);
469: break;
470: case PKCS7_DIGEST_ENC_ALGORITHM:
471: info->enc_alg = asn1_parse_algorithmIdentifier(object,
472: level, NULL);
473: break;
474: case PKCS7_ENCRYPTED_DIGEST:
475: info->encrypted_digest = chunk_clone(object);
476: break;
477: }
478: }
479: success = parser->success(parser);
480: parser->destroy(parser);
481:
482: return success;
483: }
484:
485: /**
486: * See header.
487: */
488: pkcs7_t *pkcs7_signed_data_load(chunk_t encoding, chunk_t content)
489: {
490: private_pkcs7_signed_data_t *this = create_empty();
491:
492: this->encoding = chunk_clone(encoding);
493: if (!parse(this, content))
494: {
495: destroy(this);
496: return NULL;
497: }
498: return &this->public;
499: }
500:
501: /**
502: * build a DER-encoded issuerAndSerialNumber object
503: */
504: static chunk_t build_issuerAndSerialNumber(certificate_t *cert)
505: {
506: identification_t *issuer = cert->get_issuer(cert);
507: chunk_t serial = chunk_empty;
508:
509: if (cert->get_type(cert) == CERT_X509)
510: {
511: x509_t *x509 = (x509_t*)cert;
512: serial = x509->get_serial(x509);
513: }
514:
515: return asn1_wrap(ASN1_SEQUENCE, "cm",
516: issuer->get_encoding(issuer),
517: asn1_integer("c", serial));
518: }
519:
520: /**
521: * Generate a new PKCS#7 signed-data container
522: */
523: static bool generate(private_pkcs7_signed_data_t *this, private_key_t *key,
524: certificate_t *cert, hash_algorithm_t alg,
525: pkcs7_attributes_t *pkcs9)
526: {
527: chunk_t authenticatedAttributes = chunk_empty;
528: chunk_t encryptedDigest = chunk_empty;
529: chunk_t data, signerInfo, encoding = chunk_empty;
530: chunk_t messageDigest, signingTime, attributes;
531: signature_scheme_t scheme;
532: hasher_t *hasher;
533: time_t now;
534: int digest_oid;
535:
536: digest_oid = hasher_algorithm_to_oid(alg);
537: scheme = signature_scheme_from_oid(digest_oid);
538:
539: if (!this->content->get_data(this->content, &data))
540: {
541: return FALSE;
542: }
543:
544: hasher = lib->crypto->create_hasher(lib->crypto, alg);
545: if (!hasher || !hasher->allocate_hash(hasher, data, &messageDigest))
546: {
547: DESTROY_IF(hasher);
548: DBG1(DBG_LIB, " hash algorithm %N not support",
549: hash_algorithm_names, alg);
550: free(data.ptr);
551: return FALSE;
552: }
553: hasher->destroy(hasher);
554: pkcs9->add_attribute(pkcs9,
555: OID_PKCS9_MESSAGE_DIGEST,
556: asn1_wrap(ASN1_OCTET_STRING, "m", messageDigest));
557:
558: /* take the current time as signingTime */
559: now = time(NULL);
560: signingTime = asn1_from_time(&now, ASN1_UTCTIME);
561: pkcs9->add_attribute(pkcs9, OID_PKCS9_SIGNING_TIME, signingTime);
562: pkcs9->add_attribute(pkcs9, OID_PKCS9_CONTENT_TYPE,
563: asn1_build_known_oid(OID_PKCS7_DATA));
564:
565: attributes = pkcs9->get_encoding(pkcs9);
566:
567: if (!key->sign(key, scheme, NULL, attributes, &encryptedDigest))
568: {
569: free(data.ptr);
570: return FALSE;
571: }
572: authenticatedAttributes = chunk_clone(attributes);
573: *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
574:
575: free(data.ptr);
576: if (encryptedDigest.ptr)
577: {
578: encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", encryptedDigest);
579: }
580: signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm",
581: ASN1_INTEGER_1,
582: build_issuerAndSerialNumber(cert),
583: asn1_algorithmIdentifier(digest_oid),
584: authenticatedAttributes,
585: asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
586: encryptedDigest);
587:
588: if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
589: {
590: free(signerInfo.ptr);
591: return FALSE;
592: }
593: if (!this->content->get_encoding(this->content, &data))
594: {
595: free(encoding.ptr);
596: free(signerInfo.ptr);
597: return FALSE;
598: }
599:
600: this->encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
601: asn1_build_known_oid(OID_PKCS7_SIGNED_DATA),
602: asn1_wrap(ASN1_CONTEXT_C_0, "m",
603: asn1_wrap(ASN1_SEQUENCE, "cmmmm",
604: ASN1_INTEGER_1,
605: asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_oid)),
606: data,
607: asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding),
608: asn1_wrap(ASN1_SET, "m", signerInfo))));
609:
610:
611: pkcs9->destroy(pkcs9);
612: /* TODO: create signerInfos entry */
613: return TRUE;
614: }
615:
616: /**
617: * See header.
618: */
619: pkcs7_t *pkcs7_signed_data_gen(container_type_t type, va_list args)
620: {
621: private_pkcs7_signed_data_t *this;
622: chunk_t blob = chunk_empty;
623: hash_algorithm_t alg = HASH_SHA1;
624: private_key_t *key = NULL;
625: certificate_t *cert = NULL;
626: pkcs7_attributes_t *pkcs9;
627: chunk_t value;
628: int oid;
629:
630: pkcs9 = pkcs7_attributes_create();
631:
632: while (TRUE)
633: {
634: switch (va_arg(args, builder_part_t))
635: {
636: case BUILD_SIGNING_KEY:
637: key = va_arg(args, private_key_t*);
638: continue;
639: case BUILD_SIGNING_CERT:
640: cert = va_arg(args, certificate_t*);
641: continue;
642: case BUILD_DIGEST_ALG:
643: alg = va_arg(args, int);
644: continue;
645: case BUILD_BLOB:
646: blob = va_arg(args, chunk_t);
647: continue;
648: case BUILD_PKCS7_ATTRIBUTE:
649: oid = va_arg(args, int);
650: value = va_arg(args, chunk_t);
651: pkcs9->add_attribute(pkcs9, oid, chunk_clone(value));
652: continue;
653: case BUILD_END:
654: break;
655: default:
656: pkcs9->destroy(pkcs9);
657: return NULL;
658: }
659: break;
660: }
661: if (blob.len && key && cert)
662: {
663: this = create_empty();
664:
665: this->creds->add_cert(this->creds, FALSE, cert->get_ref(cert));
666: this->content = lib->creds->create(lib->creds,
667: CRED_CONTAINER, CONTAINER_PKCS7_DATA,
668: BUILD_BLOB, blob, BUILD_END);
669:
670: if (this->content && generate(this, key, cert, alg, pkcs9))
671: {
672: return &this->public;
673: }
674: pkcs9->destroy(pkcs9);
675: destroy(this);
676: }
677: else
678: {
679: pkcs9->destroy(pkcs9);
680: }
681: return NULL;
682: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>