Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012 Martin Willi
3: * Copyright (C) 2012 revosec AG
4: * Copyright (C) 2012 Tobias Brunner
5: * Copyright (C) 2002-2008 Andreas Steffen
6: * Copyright (C) 2005 Jan Hutter, Martin Willi
7: * HSR Hochschule fuer Technik Rapperswil
8: *
9: * This program is free software; you can redistribute it and/or modify it
10: * under the terms of the GNU General Public License as published by the
11: * Free Software Foundation; either version 2 of the License, or (at your
12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13: *
14: * This program is distributed in the hope that it will be useful, but
15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17: * for more details.
18: */
19:
20: #include "pkcs7_enveloped_data.h"
21:
22: #include <asn1/asn1.h>
23: #include <asn1/asn1_parser.h>
24: #include <asn1/oid.h>
25: #include <credentials/certificates/x509.h>
26: #include <utils/debug.h>
27:
28: typedef struct private_pkcs7_enveloped_data_t private_pkcs7_enveloped_data_t;
29:
30: /**
31: * Private data of a PKCS#7 signed-data container.
32: */
33: struct private_pkcs7_enveloped_data_t {
34:
35: /**
36: * Implements pkcs7_t.
37: */
38: pkcs7_t public;
39:
40: /**
41: * Decrypted content
42: */
43: chunk_t content;
44:
45: /**
46: * Encrypted and encoded PKCS#7 enveloped-data
47: */
48: chunk_t encoding;
49: };
50:
51: /**
52: * ASN.1 definition of the PKCS#7 envelopedData type
53: */
54: static const asn1Object_t envelopedDataObjects[] = {
55: { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
56: { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
57: { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */
58: { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */
59: { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */
60: { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
61: { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
62: { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */
63: { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */
64: { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */
65: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
66: { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
67: { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */
68: { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */
69: { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */
70: { 0, "exit", ASN1_EOC, ASN1_EXIT }
71: };
72: #define PKCS7_VERSION 1
73: #define PKCS7_RECIPIENT_INFO_VERSION 4
74: #define PKCS7_ISSUER 6
75: #define PKCS7_SERIAL_NUMBER 7
76: #define PKCS7_ENCRYPTION_ALG 8
77: #define PKCS7_ENCRYPTED_KEY 9
78: #define PKCS7_CONTENT_TYPE 12
79: #define PKCS7_CONTENT_ENC_ALGORITHM 13
80: #define PKCS7_ENCRYPTED_CONTENT 14
81:
82: /**
83: * Find a private key for issuerAndSerialNumber
84: */
85: static private_key_t *find_private(identification_t *issuer,
86: identification_t *serial)
87: {
88: enumerator_t *enumerator;
89: certificate_t *cert;
90: public_key_t *public;
91: private_key_t *private = NULL;
92: identification_t *id;
93: chunk_t fp;
94:
95: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
96: CERT_X509, KEY_RSA, serial, FALSE);
97: while (enumerator->enumerate(enumerator, &cert))
98: {
99: if (issuer->equals(issuer, cert->get_issuer(cert)))
100: {
101: public = cert->get_public_key(cert);
102: if (public)
103: {
104: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp))
105: {
106: id = identification_create_from_encoding(ID_KEY_ID, fp);
107: private = lib->credmgr->get_private(lib->credmgr,
108: KEY_ANY, id, NULL);
109: id->destroy(id);
110: }
111: public->destroy(public);
112: }
113: }
114: if (private)
115: {
116: break;
117: }
118: }
119: enumerator->destroy(enumerator);
120: return private;
121: }
122:
123: /**
124: * Decrypt content using a private key from "issuer"
125: */
126: static bool decrypt(private_key_t *private, chunk_t key, chunk_t iv, int oid,
127: chunk_t encrypted, chunk_t *plain)
128: {
129: encryption_algorithm_t alg;
130: chunk_t plain_key;
131: crypter_t *crypter;
132: size_t key_size;
133:
134: alg = encryption_algorithm_from_oid(oid, &key_size);
135: if (alg == ENCR_UNDEFINED)
136: {
137: DBG1(DBG_LIB, "unsupported content encryption algorithm");
138: return FALSE;
139: }
140: if (!private->decrypt(private, ENCRYPT_RSA_PKCS1, key, &plain_key))
141: {
142: DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa");
143: return FALSE;
144: }
145: crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
146: if (!crypter)
147: {
148: DBG1(DBG_LIB, "crypter %N-%d not available",
149: encryption_algorithm_names, alg, key_size);
150: free(plain_key.ptr);
151: return FALSE;
152: }
153: if (plain_key.len != crypter->get_key_size(crypter))
154: {
155: DBG1(DBG_LIB, "symmetric key length %d is wrong", plain_key.len);
156: free(plain_key.ptr);
157: crypter->destroy(crypter);
158: return FALSE;
159: }
160: if (iv.len != crypter->get_iv_size(crypter))
161: {
162: DBG1(DBG_LIB, "IV length %d is wrong", iv.len);
163: free(plain_key.ptr);
164: crypter->destroy(crypter);
165: return FALSE;
166: }
167: if (!crypter->set_key(crypter, plain_key) ||
168: !crypter->decrypt(crypter, encrypted, iv, plain))
169: {
170: free(plain_key.ptr);
171: crypter->destroy(crypter);
172: return FALSE;
173: }
174: DBG4(DBG_LIB, "decrypted content with padding: %B", plain);
175: free(plain_key.ptr);
176: crypter->destroy(crypter);
177: return TRUE;
178: }
179:
180: /**
181: * Remove the padding from plain data
182: */
183: static bool remove_padding(private_pkcs7_enveloped_data_t *this)
184: {
185: u_char *pos = this->content.ptr + this->content.len - 1;
186: u_char pattern = *pos;
187: size_t padding = pattern;
188:
189: if (padding > this->content.len)
190: {
191: DBG1(DBG_LIB, "padding greater than data length");
192: return FALSE;
193: }
194: this->content.len -= padding;
195:
196: while (padding-- > 0)
197: {
198: if (*pos-- != pattern)
199: {
200: DBG1(DBG_LIB, "wrong padding pattern");
201: return FALSE;
202: }
203: }
204: return TRUE;
205: }
206:
207: /**
208: * Parse and decrypt enveloped-data
209: */
210: static bool parse(private_pkcs7_enveloped_data_t *this, chunk_t content)
211: {
212: asn1_parser_t *parser;
213: chunk_t object;
214: int objectID, version, alg = OID_UNKNOWN;
215: bool success = FALSE;
216: identification_t *issuer = NULL, *serial = NULL;
217: private_key_t *private = NULL;
218: chunk_t iv = chunk_empty, key = chunk_empty, encrypted = chunk_empty;
219:
220: parser = asn1_parser_create(envelopedDataObjects, content);
221: parser->set_top_level(parser, 0);
222:
223: while (parser->iterate(parser, &objectID, &object))
224: {
225: u_int level = parser->get_level(parser);
226:
227: switch (objectID)
228: {
229: case PKCS7_VERSION:
230: version = object.len ? (int)*object.ptr : 0;
231: DBG2(DBG_LIB, " v%d", version);
232: if (version != 0)
233: {
234: DBG1(DBG_LIB, "envelopedData version is not 0");
235: goto end;
236: }
237: break;
238: case PKCS7_RECIPIENT_INFO_VERSION:
239: version = object.len ? (int)*object.ptr : 0;
240: DBG2(DBG_LIB, " v%d", version);
241: if (version != 0)
242: {
243: DBG1(DBG_LIB, "recipient info version is not 0");
244: goto end;
245: }
246: break;
247: case PKCS7_ISSUER:
248: if (!issuer)
249: {
250: issuer = identification_create_from_encoding(ID_DER_ASN1_DN,
251: object);
252: }
253: break;
254: case PKCS7_SERIAL_NUMBER:
255: if (!serial)
256: {
257: serial = identification_create_from_encoding(ID_KEY_ID,
258: object);
259: }
260: break;
261: case PKCS7_ENCRYPTION_ALG:
262: if (asn1_parse_algorithmIdentifier(object, level,
263: NULL) != OID_RSA_ENCRYPTION)
264: {
265: DBG1(DBG_LIB, "only rsa encryption supported");
266: goto end;
267: }
268: break;
269: case PKCS7_ENCRYPTED_KEY:
270: key = object;
271: break;
272: case PKCS7_CONTENT_TYPE:
273: if (asn1_known_oid(object) != OID_PKCS7_DATA)
274: {
275: DBG1(DBG_LIB, "encrypted content not of type pkcs7 data");
276: goto end;
277: }
278: break;
279: case PKCS7_CONTENT_ENC_ALGORITHM:
280: alg = asn1_parse_algorithmIdentifier(object, level, &iv);
281: if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING,
282: level + 1, "IV"))
283: {
284: DBG1(DBG_LIB, "IV could not be parsed");
285: goto end;
286: }
287: break;
288: case PKCS7_ENCRYPTED_CONTENT:
289: encrypted = object;
290: break;
291: }
292: }
293: success = parser->success(parser);
294:
295: end:
296: parser->destroy(parser);
297: if (!success)
298: {
299: goto failed;
300: }
301: success = FALSE;
302: if (!issuer)
303: {
304: goto failed;
305: }
306: private = find_private(issuer, serial);
307: if (!private)
308: {
309: DBG1(DBG_LIB, "no private key found to decrypt pkcs7");
310: goto failed;
311: }
312: if (!decrypt(private, key, iv, alg, encrypted, &this->content))
313: {
314: goto failed;
315: }
316: if (!remove_padding(this))
317: {
318: goto failed;
319: }
320:
321: success = TRUE;
322: failed:
323: DESTROY_IF(issuer);
324: DESTROY_IF(serial);
325: DESTROY_IF(private);
326: return success;
327: }
328:
329: METHOD(container_t, get_type, container_type_t,
330: private_pkcs7_enveloped_data_t *this)
331: {
332: return CONTAINER_PKCS7_ENVELOPED_DATA;
333: }
334:
335: METHOD(container_t, create_signature_enumerator, enumerator_t*,
336: private_pkcs7_enveloped_data_t *this)
337: {
338: return enumerator_create_empty();
339: }
340:
341: METHOD(container_t, get_data, bool,
342: private_pkcs7_enveloped_data_t *this, chunk_t *data)
343: {
344: if (this->content.len)
345: {
346: *data = chunk_clone(this->content);
347: return TRUE;
348: }
349: return FALSE;
350: }
351:
352: METHOD(container_t, get_encoding, bool,
353: private_pkcs7_enveloped_data_t *this, chunk_t *data)
354: {
355: *data = chunk_clone(this->encoding);
356: return TRUE;
357: }
358:
359: METHOD(container_t, destroy, void,
360: private_pkcs7_enveloped_data_t *this)
361: {
362: free(this->content.ptr);
363: free(this->encoding.ptr);
364: free(this);
365: }
366:
367: /**
368: * Generic constructor
369: */
370: static private_pkcs7_enveloped_data_t* create_empty()
371: {
372: private_pkcs7_enveloped_data_t *this;
373:
374: INIT(this,
375: .public = {
376: .container = {
377: .get_type = _get_type,
378: .create_signature_enumerator = _create_signature_enumerator,
379: .get_data = _get_data,
380: .get_encoding = _get_encoding,
381: .destroy = _destroy,
382: },
383: .create_cert_enumerator = (void*)enumerator_create_empty,
384: .get_attribute = (void*)return_false,
385: },
386: );
387:
388: return this;
389: }
390:
391: /**
392: * See header.
393: */
394: pkcs7_t *pkcs7_enveloped_data_load(chunk_t encoding, chunk_t content)
395: {
396: private_pkcs7_enveloped_data_t *this = create_empty();
397:
398: this->encoding = chunk_clone(encoding);
399: if (!parse(this, content))
400: {
401: destroy(this);
402: return NULL;
403: }
404:
405: return &this->public;
406: }
407:
408: /**
409: * Allocate data with an RNG
410: */
411: static bool get_random(rng_quality_t quality, size_t size, chunk_t *out)
412: {
413: rng_t *rng;
414:
415: rng = lib->crypto->create_rng(lib->crypto, quality);
416: if (!rng)
417: {
418: return FALSE;
419: }
420: if (!rng->allocate_bytes(rng, size, out))
421: {
422: rng->destroy(rng);
423: return FALSE;
424: }
425: rng->destroy(rng);
426: return TRUE;
427: }
428:
429: /**
430: * Encrypt symmetric key using a public key from a certificate
431: */
432: static bool encrypt_key(certificate_t *cert, chunk_t in, chunk_t *out)
433: {
434: public_key_t *key;
435:
436: key = cert->get_public_key(cert);
437: if (!key)
438: {
439: return FALSE;
440: }
441: if (!key->encrypt(key, ENCRYPT_RSA_PKCS1, in, out))
442: {
443: key->destroy(key);
444: return FALSE;
445: }
446: key->destroy(key);
447: return TRUE;
448: }
449:
450: /**
451: * build a DER-encoded issuerAndSerialNumber object
452: */
453: static chunk_t build_issuerAndSerialNumber(certificate_t *cert)
454: {
455: identification_t *issuer = cert->get_issuer(cert);
456: chunk_t serial = chunk_empty;
457:
458: if (cert->get_type(cert) == CERT_X509)
459: {
460: x509_t *x509 = (x509_t*)cert;
461: serial = x509->get_serial(x509);
462: }
463:
464: return asn1_wrap(ASN1_SEQUENCE, "cm",
465: issuer->get_encoding(issuer),
466: asn1_integer("c", serial));
467: }
468:
469: /**
470: * Generate a new PKCS#7 enveloped-data container
471: */
472: static bool generate(private_pkcs7_enveloped_data_t *this,
473: certificate_t *cert, encryption_algorithm_t alg, int key_size)
474: {
475: chunk_t contentEncryptionAlgorithm, encryptedContentInfo, recipientInfo;
476: chunk_t iv, symmetricKey, protectedKey, content;
477: crypter_t *crypter;
478: size_t bs, padding;
479: int alg_oid;
480:
481: alg_oid = encryption_algorithm_to_oid(alg, key_size);
482: if (alg_oid == OID_UNKNOWN)
483: {
484: DBG1(DBG_LIB, " encryption algorithm %N not supported",
485: encryption_algorithm_names, alg);
486: return FALSE;
487: }
488: crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
489: if (crypter == NULL)
490: {
491: DBG1(DBG_LIB, " could not create crypter for algorithm %N",
492: encryption_algorithm_names, alg);
493: return FALSE;
494: }
495:
496: if (!get_random(RNG_TRUE, crypter->get_key_size(crypter), &symmetricKey))
497: {
498: DBG1(DBG_LIB, " failed to allocate symmetric encryption key");
499: crypter->destroy(crypter);
500: return FALSE;
501: }
502: DBG4(DBG_LIB, " symmetric encryption key: %B", &symmetricKey);
503:
504: if (!get_random(RNG_WEAK, crypter->get_iv_size(crypter), &iv))
505: {
506: DBG1(DBG_LIB, " failed to allocate initialization vector");
507: crypter->destroy(crypter);
508: return FALSE;
509: }
510: DBG4(DBG_LIB, " initialization vector: %B", &iv);
511:
512: bs = crypter->get_block_size(crypter);
513: padding = bs - this->content.len % bs;
514: content = chunk_alloc(this->content.len + padding);
515: memcpy(content.ptr, this->content.ptr, this->content.len);
516: memset(content.ptr + this->content.len, padding, padding);
517: DBG3(DBG_LIB, " padded unencrypted data: %B", &content);
518:
519: /* symmetric inline encryption of content */
520: if (!crypter->set_key(crypter, symmetricKey) ||
521: !crypter->encrypt(crypter, content, iv, NULL))
522: {
523: crypter->destroy(crypter);
524: chunk_clear(&symmetricKey);
525: chunk_free(&iv);
526: return FALSE;
527: }
528: crypter->destroy(crypter);
529: DBG3(DBG_LIB, " encrypted data: %B", &content);
530:
531: if (!encrypt_key(cert, symmetricKey, &protectedKey))
532: {
533: DBG1(DBG_LIB, " encrypting symmetric key failed");
534: chunk_clear(&symmetricKey);
535: chunk_free(&iv);
536: chunk_free(&content);
537: return FALSE;
538: }
539: chunk_clear(&symmetricKey);
540:
541: contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm",
542: asn1_build_known_oid(alg_oid),
543: asn1_wrap(ASN1_OCTET_STRING, "m", iv));
544:
545: encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm",
546: asn1_build_known_oid(OID_PKCS7_DATA),
547: contentEncryptionAlgorithm,
548: asn1_wrap(ASN1_CONTEXT_S_0, "m", content));
549:
550: recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm",
551: ASN1_INTEGER_0,
552: build_issuerAndSerialNumber(cert),
553: asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
554: asn1_wrap(ASN1_OCTET_STRING, "m", protectedKey));
555:
556: this->encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
557: asn1_build_known_oid(OID_PKCS7_ENVELOPED_DATA),
558: asn1_wrap(ASN1_CONTEXT_C_0, "m",
559: asn1_wrap(ASN1_SEQUENCE, "cmm",
560: ASN1_INTEGER_0,
561: asn1_wrap(ASN1_SET, "m", recipientInfo),
562: encryptedContentInfo)));
563:
564: return TRUE;
565: }
566:
567: /**
568: * See header.
569: */
570: pkcs7_t *pkcs7_enveloped_data_gen(container_type_t type, va_list args)
571: {
572: private_pkcs7_enveloped_data_t *this;
573: chunk_t blob = chunk_empty;
574: encryption_algorithm_t alg = ENCR_AES_CBC;
575: certificate_t *cert = NULL;
576: int key_size = 128;
577:
578: while (TRUE)
579: {
580: switch (va_arg(args, builder_part_t))
581: {
582: case BUILD_CERT:
583: cert = va_arg(args, certificate_t*);
584: continue;
585: case BUILD_ENCRYPTION_ALG:
586: alg = va_arg(args, int);
587: continue;
588: case BUILD_KEY_SIZE:
589: key_size = va_arg(args, int);
590: continue;
591: case BUILD_BLOB:
592: blob = va_arg(args, chunk_t);
593: continue;
594: case BUILD_END:
595: break;
596: default:
597: return NULL;
598: }
599: break;
600: }
601: if (blob.len && cert)
602: {
603: this = create_empty();
604:
605: this->content = chunk_clone(blob);
606: if (generate(this, cert, alg, key_size))
607: {
608: return &this->public;
609: }
610: destroy(this);
611: }
612: return NULL;
613: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>