Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_pkcs12.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
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: #define _GNU_SOURCE /* for asprintf() */
17: #include <stdio.h>
18: #include <openssl/pkcs12.h>
19:
20: #include "openssl_pkcs12.h"
21: #include "openssl_util.h"
22:
23: #include <library.h>
24: #include <credentials/sets/mem_cred.h>
25:
26: typedef struct private_pkcs12_t private_pkcs12_t;
27:
28: /**
29: * Private data of a pkcs12_t object.
30: */
31: struct private_pkcs12_t {
32:
33: /**
34: * Public pkcs12_t interface.
35: */
36: pkcs12_t public;
37:
38: /**
39: * OpenSSL PKCS#12 structure
40: */
41: PKCS12 *p12;
42:
43: /**
44: * Credentials contained in container
45: */
46: mem_cred_t *creds;
47: };
48:
49: /**
50: * Decode certificate and add it to our credential set
51: */
52: static bool add_cert(private_pkcs12_t *this, X509 *x509)
53: {
54: certificate_t *cert = NULL;
55: chunk_t encoding;
56:
57: if (!x509)
58: { /* no certificate is ok */
59: return TRUE;
60: }
61: encoding = openssl_i2chunk(X509, x509);
62: if (encoding.ptr)
63: {
64: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
65: BUILD_BLOB_ASN1_DER, encoding,
66: BUILD_END);
67: if (cert)
68: {
69: this->creds->add_cert(this->creds, FALSE, cert);
70: }
71: }
72: chunk_free(&encoding);
73: X509_free(x509);
74: return cert != NULL;
75: }
76:
77: /**
78: * Add CA certificates to our credential set
79: */
80: static bool add_cas(private_pkcs12_t *this, STACK_OF(X509) *cas)
81: {
82: bool success = TRUE;
83: int i;
84:
85: if (!cas)
86: { /* no CAs is ok */
87: return TRUE;
88: }
89: for (i = 0; i < sk_X509_num(cas); i++)
90: {
91: if (!add_cert(this, sk_X509_value(cas, i)))
92: { /* continue to free all X509 objects */
93: success = FALSE;
94: }
95: }
96: sk_X509_free(cas);
97: return success;
98: }
99:
100: /**
101: * Decode private key and add it to our credential set
102: */
103: static bool add_key(private_pkcs12_t *this, EVP_PKEY *private)
104: {
105: private_key_t *key = NULL;
106: chunk_t encoding;
107: key_type_t type;
108:
109: if (!private)
110: { /* no private key is ok */
111: return TRUE;
112: }
113: switch (EVP_PKEY_base_id(private))
114: {
115: case EVP_PKEY_RSA:
116: type = KEY_RSA;
117: break;
118: case EVP_PKEY_EC:
119: type = KEY_ECDSA;
120: break;
121: default:
122: EVP_PKEY_free(private);
123: return FALSE;
124: }
125: encoding = openssl_i2chunk(PrivateKey, private);
126: if (encoding.ptr)
127: {
128: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
129: BUILD_BLOB_ASN1_DER, encoding,
130: BUILD_END);
131: if (key)
132: {
133: this->creds->add_key(this->creds, key);
134: }
135: }
136: chunk_clear(&encoding);
137: EVP_PKEY_free(private);
138: return key != NULL;
139: }
140:
141: /**
142: * Decrypt PKCS#12 file and unpack credentials
143: */
144: static bool decrypt_and_unpack(private_pkcs12_t *this)
145: {
146: enumerator_t *enumerator;
147: shared_key_t *shared;
148: STACK_OF(X509) *cas = NULL;
149: EVP_PKEY *private;
150: X509 *cert;
151: chunk_t key;
152: char *password;
153: bool success = FALSE;
154:
155: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
156: SHARED_PRIVATE_KEY_PASS, NULL, NULL);
157: while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
158: {
159: key = shared->get_key(shared);
160: if (!key.ptr || asprintf(&password, "%.*s", (int)key.len, key.ptr) < 0)
161: {
162: password = NULL;
163: }
164: if (PKCS12_parse(this->p12, password, &private, &cert, &cas))
165: {
166: success = add_key(this, private);
167: success &= add_cert(this, cert);
168: success &= add_cas(this, cas);
169: free(password);
170: break;
171: }
172: free(password);
173: }
174: enumerator->destroy(enumerator);
175: return success;
176: }
177:
178: METHOD(container_t, get_type, container_type_t,
179: private_pkcs12_t *this)
180: {
181: return CONTAINER_PKCS12;
182: }
183:
184: METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*,
185: private_pkcs12_t *this)
186: {
187: return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY,
188: KEY_ANY, NULL, FALSE);
189: }
190:
191: METHOD(pkcs12_t, create_key_enumerator, enumerator_t*,
192: private_pkcs12_t *this)
193: {
194: return this->creds->set.create_private_enumerator(&this->creds->set,
195: KEY_ANY, NULL);
196: }
197:
198: METHOD(container_t, destroy, void,
199: private_pkcs12_t *this)
200: {
201: if (this->p12)
202: {
203: PKCS12_free(this->p12);
204: }
205: this->creds->destroy(this->creds);
206: free(this);
207: }
208:
209: /**
210: * Parse a PKCS#12 container
211: */
212: static pkcs12_t *parse(chunk_t blob)
213: {
214: private_pkcs12_t *this;
215: BIO *bio;
216:
217: INIT(this,
218: .public = {
219: .container = {
220: .get_type = _get_type,
221: .create_signature_enumerator = (void*)enumerator_create_empty,
222: .get_data = (void*)return_false,
223: .get_encoding = (void*)return_false,
224: .destroy = _destroy,
225: },
226: .create_cert_enumerator = _create_cert_enumerator,
227: .create_key_enumerator = _create_key_enumerator,
228: },
229: .creds = mem_cred_create(),
230: );
231:
232: bio = BIO_new_mem_buf(blob.ptr, blob.len);
233: this->p12 = d2i_PKCS12_bio(bio, NULL);
234: BIO_free(bio);
235:
236: if (!this->p12 || !decrypt_and_unpack(this))
237: {
238: destroy(this);
239: return NULL;
240: }
241: return &this->public;
242: }
243:
244: /*
245: * Defined in header
246: */
247: pkcs12_t *openssl_pkcs12_load(container_type_t type, va_list args)
248: {
249: chunk_t blob = chunk_empty;
250:
251: while (TRUE)
252: {
253: switch (va_arg(args, builder_part_t))
254: {
255: case BUILD_BLOB_ASN1_DER:
256: blob = va_arg(args, chunk_t);
257: continue;
258: case BUILD_END:
259: break;
260: default:
261: return NULL;
262: }
263: break;
264: }
265: return blob.len ? parse(blob) : NULL;
266: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>