Mercurial > projects > hoofbaby
comparison deps/Platinum/ThirdParty/Neptune/ThirdParty/axTLS/ssl/p12.c @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3425707ddbf6 |
---|---|
1 /* | |
2 * Copyright (c) 2007, Cameron Rich | |
3 * | |
4 * All rights reserved. | |
5 * | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions are met: | |
8 * | |
9 * * Redistributions of source code must retain the above copyright notice, | |
10 * this list of conditions and the following disclaimer. | |
11 * * Redistributions in binary form must reproduce the above copyright notice, | |
12 * this list of conditions and the following disclaimer in the documentation | |
13 * and/or other materials provided with the distribution. | |
14 * * Neither the name of the axTLS project nor the names of its contributors | |
15 * may be used to endorse or promote products derived from this software | |
16 * without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 /** | |
32 * Process PKCS#8/PKCS#12 keys. | |
33 * | |
34 * The decoding of a PKCS#12 key is fairly specific - this code was tested on a | |
35 * key generated with: | |
36 * | |
37 * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem | |
38 * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 | |
39 * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd | |
40 * | |
41 * or with a certificate chain: | |
42 * | |
43 * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem | |
44 * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe | |
45 * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd | |
46 * | |
47 * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The | |
48 * private/public keys/certs have to use RSA encryption. Both the integrity | |
49 * and privacy passwords are the same. | |
50 * | |
51 * The PKCS#8 files were generated with something like: | |
52 * | |
53 * PEM format: | |
54 * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1 | |
55 * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8 | |
56 * | |
57 * DER format: | |
58 * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER | |
59 * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8 | |
60 */ | |
61 | |
62 #include <stdlib.h> | |
63 #include <string.h> | |
64 #include <stdio.h> | |
65 | |
66 #include "ssl.h" | |
67 | |
68 /* all commented out if not used */ | |
69 #ifdef CONFIG_SSL_USE_PKCS12 | |
70 | |
71 #define BLOCK_SIZE 64 | |
72 #define PKCS12_KEY_ID 1 | |
73 #define PKCS12_IV_ID 2 | |
74 #define PKCS12_MAC_ID 3 | |
75 | |
76 static char *make_uni_pass(const char *password, int *uni_pass_len); | |
77 static int p8_decrypt(const char *uni_pass, int uni_pass_len, | |
78 const uint8_t *salt, int iter, | |
79 uint8_t *priv_key, int priv_key_len, int id); | |
80 static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key); | |
81 static int get_pbe_params(uint8_t *buf, int *offset, | |
82 const uint8_t **salt, int *iterations); | |
83 | |
84 /* | |
85 * Take a raw pkcs8 block and then decrypt it and turn it into a normal key. | |
86 */ | |
87 int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) | |
88 { | |
89 uint8_t *buf = ssl_obj->buf; | |
90 int len, offset = 0; | |
91 int iterations; | |
92 int ret = SSL_NOT_OK; | |
93 uint8_t *version = NULL; | |
94 const uint8_t *salt; | |
95 uint8_t *priv_key; | |
96 int uni_pass_len; | |
97 char *uni_pass = make_uni_pass(password, &uni_pass_len); | |
98 | |
99 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) | |
100 { | |
101 #ifdef CONFIG_SSL_FULL_MODE | |
102 printf("Error: Invalid p8 ASN.1 file\n"); | |
103 #endif | |
104 goto error; | |
105 } | |
106 | |
107 /* unencrypted key? */ | |
108 if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0) | |
109 { | |
110 ret = p8_add_key(ssl_ctx, buf); | |
111 goto error; | |
112 } | |
113 | |
114 if (get_pbe_params(buf, &offset, &salt, &iterations) < 0) | |
115 goto error; | |
116 | |
117 if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) | |
118 goto error; | |
119 | |
120 priv_key = &buf[offset]; | |
121 | |
122 p8_decrypt(uni_pass, uni_pass_len, salt, | |
123 iterations, priv_key, len, PKCS12_KEY_ID); | |
124 ret = p8_add_key(ssl_ctx, priv_key); | |
125 | |
126 error: | |
127 free(version); | |
128 free(uni_pass); | |
129 return ret; | |
130 } | |
131 | |
132 /* | |
133 * Take the unencrypted pkcs8 and turn it into a private key | |
134 */ | |
135 static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key) | |
136 { | |
137 uint8_t *buf = priv_key; | |
138 int len, offset = 0; | |
139 int ret = SSL_NOT_OK; | |
140 | |
141 /* Skip the preamble and go straight to the private key. | |
142 We only support rsaEncryption (1.2.840.113549.1.1.1) */ | |
143 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
144 asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || | |
145 asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
146 (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) | |
147 goto error; | |
148 | |
149 ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx); | |
150 | |
151 error: | |
152 return ret; | |
153 } | |
154 | |
155 /* | |
156 * Create the unicode password | |
157 */ | |
158 static char *make_uni_pass(const char *password, int *uni_pass_len) | |
159 { | |
160 int pass_len = 0, i; | |
161 char *uni_pass; | |
162 | |
163 if (password == NULL) | |
164 { | |
165 password = ""; | |
166 } | |
167 | |
168 uni_pass = (char *)malloc((strlen(password)+1)*2); | |
169 | |
170 /* modify the password into a unicode version */ | |
171 for (i = 0; i < (int)strlen(password); i++) | |
172 { | |
173 uni_pass[pass_len++] = 0; | |
174 uni_pass[pass_len++] = password[i]; | |
175 } | |
176 | |
177 uni_pass[pass_len++] = 0; /* null terminate */ | |
178 uni_pass[pass_len++] = 0; | |
179 *uni_pass_len = pass_len; | |
180 return uni_pass; | |
181 } | |
182 | |
183 /* | |
184 * Decrypt a pkcs8 block. | |
185 */ | |
186 static int p8_decrypt(const char *uni_pass, int uni_pass_len, | |
187 const uint8_t *salt, int iter, | |
188 uint8_t *priv_key, int priv_key_len, int id) | |
189 { | |
190 uint8_t p[BLOCK_SIZE*2]; | |
191 uint8_t d[BLOCK_SIZE]; | |
192 uint8_t Ai[SHA1_SIZE]; | |
193 SHA1_CTX sha_ctx; | |
194 RC4_CTX rc4_ctx; | |
195 int i; | |
196 | |
197 for (i = 0; i < BLOCK_SIZE; i++) | |
198 { | |
199 p[i] = salt[i % SALT_SIZE]; | |
200 p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len]; | |
201 d[i] = id; | |
202 } | |
203 | |
204 /* get the key - no IV since we are using RC4 */ | |
205 SHA1_Init(&sha_ctx); | |
206 SHA1_Update(&sha_ctx, d, sizeof(d)); | |
207 SHA1_Update(&sha_ctx, p, sizeof(p)); | |
208 SHA1_Final(Ai, &sha_ctx); | |
209 | |
210 for (i = 1; i < iter; i++) | |
211 { | |
212 SHA1_Init(&sha_ctx); | |
213 SHA1_Update(&sha_ctx, Ai, SHA1_SIZE); | |
214 SHA1_Final(Ai, &sha_ctx); | |
215 } | |
216 | |
217 /* do the decryption */ | |
218 if (id == PKCS12_KEY_ID) | |
219 { | |
220 RC4_setup(&rc4_ctx, Ai, 16); | |
221 RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len); | |
222 } | |
223 else /* MAC */ | |
224 memcpy(priv_key, Ai, SHA1_SIZE); | |
225 | |
226 return 0; | |
227 } | |
228 | |
229 /* | |
230 * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s) | |
231 * and keys. | |
232 */ | |
233 int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) | |
234 { | |
235 uint8_t *buf = ssl_obj->buf; | |
236 int all_ok = 0, len, iterations, auth_safes_start, | |
237 auth_safes_end, auth_safes_len, key_offset, offset = 0; | |
238 int all_certs = 0; | |
239 uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac; | |
240 uint8_t key[SHA1_SIZE]; | |
241 uint8_t mac[SHA1_SIZE]; | |
242 const uint8_t *salt; | |
243 int uni_pass_len, ret; | |
244 int error_code = SSL_ERROR_NOT_SUPPORTED; | |
245 char *uni_pass = make_uni_pass(password, &uni_pass_len); | |
246 static const uint8_t pkcs_data[] = /* pkc7 data */ | |
247 { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; | |
248 static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */ | |
249 { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 }; | |
250 static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */ | |
251 { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 }; | |
252 | |
253 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) | |
254 { | |
255 #ifdef CONFIG_SSL_FULL_MODE | |
256 printf("Error: Invalid p12 ASN.1 file\n"); | |
257 #endif | |
258 goto error; | |
259 } | |
260 | |
261 if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3) | |
262 { | |
263 error_code = SSL_ERROR_INVALID_VERSION; | |
264 goto error; | |
265 } | |
266 | |
267 /* remove all the boring pcks7 bits */ | |
268 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
269 (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || | |
270 len != sizeof(pkcs_data) || | |
271 memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) | |
272 goto error; | |
273 | |
274 offset += len; | |
275 | |
276 if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || | |
277 asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0) | |
278 goto error; | |
279 | |
280 /* work out the MAC start/end points (done on AuthSafes) */ | |
281 auth_safes_start = offset; | |
282 auth_safes_end = offset; | |
283 if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0) | |
284 goto error; | |
285 | |
286 auth_safes_len = auth_safes_end - auth_safes_start; | |
287 auth_safes = malloc(auth_safes_len); | |
288 | |
289 memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len); | |
290 | |
291 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
292 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
293 (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || | |
294 (len != sizeof(pkcs_encrypted) || | |
295 memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted)))) | |
296 goto error; | |
297 | |
298 offset += len; | |
299 | |
300 if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || | |
301 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
302 asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || | |
303 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
304 (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || | |
305 len != sizeof(pkcs_data) || | |
306 memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) | |
307 goto error; | |
308 | |
309 offset += len; | |
310 | |
311 /* work out the salt for the certificate */ | |
312 if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 || | |
313 (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0) | |
314 goto error; | |
315 | |
316 /* decrypt the certificate */ | |
317 cert = &buf[offset]; | |
318 if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, | |
319 len, PKCS12_KEY_ID)) < 0) | |
320 goto error; | |
321 | |
322 offset += len; | |
323 | |
324 /* load the certificate */ | |
325 key_offset = 0; | |
326 all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE); | |
327 | |
328 /* keep going until all certs are loaded */ | |
329 while (key_offset < all_certs) | |
330 { | |
331 int cert_offset = key_offset; | |
332 | |
333 if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 || | |
334 asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || | |
335 asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || | |
336 asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || | |
337 asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || | |
338 asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || | |
339 asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || | |
340 (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0) | |
341 goto error; | |
342 | |
343 if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0) | |
344 goto error; | |
345 | |
346 key_offset = cert_offset; | |
347 } | |
348 | |
349 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
350 (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || | |
351 len != sizeof(pkcs_data) || | |
352 memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) | |
353 goto error; | |
354 | |
355 offset += len; | |
356 | |
357 if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || | |
358 asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 || | |
359 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
360 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
361 (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || | |
362 (len != sizeof(pkcs8_key_bag)) || | |
363 memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag))) | |
364 goto error; | |
365 | |
366 offset += len; | |
367 | |
368 /* work out the salt for the private key */ | |
369 if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || | |
370 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
371 get_pbe_params(buf, &offset, &salt, &iterations) < 0 || | |
372 (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) | |
373 goto error; | |
374 | |
375 /* decrypt the private key */ | |
376 cert = &buf[offset]; | |
377 if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, | |
378 len, PKCS12_KEY_ID)) < 0) | |
379 goto error; | |
380 | |
381 offset += len; | |
382 | |
383 /* load the private key */ | |
384 if ((ret = p8_add_key(ssl_ctx, cert)) < 0) | |
385 goto error; | |
386 | |
387 /* miss out on friendly name, local key id etc */ | |
388 if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0) | |
389 goto error; | |
390 | |
391 /* work out the MAC */ | |
392 if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
393 asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
394 asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || | |
395 (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || | |
396 len != SHA1_SIZE) | |
397 goto error; | |
398 | |
399 orig_mac = &buf[offset]; | |
400 offset += len; | |
401 | |
402 /* get the salt */ | |
403 if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8) | |
404 goto error; | |
405 | |
406 salt = &buf[offset]; | |
407 | |
408 /* work out what the mac should be */ | |
409 if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, | |
410 key, SHA1_SIZE, PKCS12_MAC_ID)) < 0) | |
411 goto error; | |
412 | |
413 hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); | |
414 | |
415 if (memcmp(mac, orig_mac, SHA1_SIZE)) | |
416 { | |
417 error_code = SSL_ERROR_INVALID_HMAC; | |
418 goto error; | |
419 } | |
420 | |
421 all_ok = 1; | |
422 | |
423 error: | |
424 free(version); | |
425 free(uni_pass); | |
426 free(auth_safes); | |
427 return all_ok ? SSL_OK : error_code; | |
428 } | |
429 | |
430 /* | |
431 * Retrieve the salt/iteration details from a PBE block. | |
432 */ | |
433 static int get_pbe_params(uint8_t *buf, int *offset, | |
434 const uint8_t **salt, int *iterations) | |
435 { | |
436 static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */ | |
437 { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 }; | |
438 | |
439 int i, len; | |
440 uint8_t *iter = NULL; | |
441 int error_code = SSL_ERROR_NOT_SUPPORTED; | |
442 | |
443 /* Get the PBE type */ | |
444 if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || | |
445 (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) | |
446 goto error; | |
447 | |
448 /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) | |
449 which is the only algorithm we support */ | |
450 if (len != sizeof(pbeSH1RC4) || | |
451 memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4))) | |
452 { | |
453 #ifdef CONFIG_SSL_FULL_MODE | |
454 printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n"); | |
455 #endif | |
456 goto error; | |
457 } | |
458 | |
459 *offset += len; | |
460 | |
461 if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || | |
462 (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || | |
463 len != 8) | |
464 goto error; | |
465 | |
466 *salt = &buf[*offset]; | |
467 *offset += len; | |
468 | |
469 if ((len = asn1_get_int(buf, offset, &iter)) < 0) | |
470 goto error; | |
471 | |
472 *iterations = 0; | |
473 for (i = 0; i < len; i++) | |
474 { | |
475 (*iterations) <<= 8; | |
476 (*iterations) += iter[i]; | |
477 } | |
478 | |
479 free(iter); | |
480 error_code = SSL_OK; /* got here - we are ok */ | |
481 | |
482 error: | |
483 return error_code; | |
484 } | |
485 | |
486 #endif |