Mercurial > projects > hoofbaby
comparison deps/Platinum/ThirdParty/Neptune/ThirdParty/axTLS/ssl/asn1.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 * Some primitive asn methods for extraction ASN.1 data. | |
33 */ | |
34 | |
35 #include <stdio.h> | |
36 #include <stdlib.h> | |
37 #include <string.h> | |
38 #include <time.h> | |
39 #include "os_port.h" | |
40 #include "crypto.h" | |
41 #include "crypto_misc.h" | |
42 | |
43 #define SIG_OID_PREFIX_SIZE 8 | |
44 #define SIG_IIS6_OID_SIZE 5 | |
45 | |
46 /* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */ | |
47 static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = | |
48 { | |
49 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01 | |
50 }; | |
51 | |
52 static const uint8_t sig_iis6_oid[SIG_IIS6_OID_SIZE] = | |
53 { | |
54 0x2b, 0x0e, 0x03, 0x02, 0x1d | |
55 }; | |
56 | |
57 /* CN, O, OU */ | |
58 static const uint8_t g_dn_types[] = { 3, 10, 11 }; | |
59 | |
60 int get_asn1_length(const uint8_t *buf, int *offset) | |
61 { | |
62 int len, i; | |
63 | |
64 if (!(buf[*offset] & 0x80)) /* short form */ | |
65 { | |
66 len = buf[(*offset)++]; | |
67 } | |
68 else /* long form */ | |
69 { | |
70 int length_bytes = buf[(*offset)++]&0x7f; | |
71 len = 0; | |
72 for (i = 0; i < length_bytes; i++) | |
73 { | |
74 len <<= 8; | |
75 len += buf[(*offset)++]; | |
76 } | |
77 } | |
78 | |
79 return len; | |
80 } | |
81 | |
82 /** | |
83 * Skip the ASN1.1 object type and its length. Get ready to read the object's | |
84 * data. | |
85 */ | |
86 int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type) | |
87 { | |
88 if (buf[*offset] != obj_type) | |
89 return X509_NOT_OK; | |
90 (*offset)++; | |
91 return get_asn1_length(buf, offset); | |
92 } | |
93 | |
94 /** | |
95 * Skip over an ASN.1 object type completely. Get ready to read the next | |
96 * object. | |
97 */ | |
98 int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type) | |
99 { | |
100 int len; | |
101 | |
102 if (buf[*offset] != obj_type) | |
103 return X509_NOT_OK; | |
104 (*offset)++; | |
105 len = get_asn1_length(buf, offset); | |
106 *offset += len; | |
107 return 0; | |
108 } | |
109 | |
110 /** | |
111 * Read an integer value for ASN.1 data | |
112 * Note: This function allocates memory which must be freed by the user. | |
113 */ | |
114 int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object) | |
115 { | |
116 int len; | |
117 | |
118 if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) | |
119 goto end_int_array; | |
120 | |
121 if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ | |
122 { | |
123 len--; | |
124 (*offset)++; | |
125 } | |
126 | |
127 *object = (uint8_t *)malloc(len); | |
128 memcpy(*object, &buf[*offset], len); | |
129 *offset += len; | |
130 | |
131 end_int_array: | |
132 return len; | |
133 } | |
134 | |
135 /** | |
136 * Get all the RSA private key specifics from an ASN.1 encoded file | |
137 */ | |
138 int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) | |
139 { | |
140 int offset = 7; | |
141 uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL; | |
142 int mod_len, priv_len, pub_len; | |
143 #ifdef CONFIG_BIGINT_CRT | |
144 uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; | |
145 int p_len, q_len, dP_len, dQ_len, qInv_len; | |
146 #endif | |
147 | |
148 /* not in der format */ | |
149 if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ | |
150 { | |
151 #ifdef CONFIG_SSL_FULL_MODE | |
152 printf("Error: This is not a valid ASN.1 file\n"); | |
153 #endif | |
154 return X509_INVALID_PRIV_KEY; | |
155 } | |
156 | |
157 /* initialise the RNG */ | |
158 RNG_initialize(buf, len); | |
159 | |
160 mod_len = asn1_get_int(buf, &offset, &modulus); | |
161 pub_len = asn1_get_int(buf, &offset, &pub_exp); | |
162 priv_len = asn1_get_int(buf, &offset, &priv_exp); | |
163 | |
164 if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) | |
165 return X509_INVALID_PRIV_KEY; | |
166 | |
167 #ifdef CONFIG_BIGINT_CRT | |
168 p_len = asn1_get_int(buf, &offset, &p); | |
169 q_len = asn1_get_int(buf, &offset, &q); | |
170 dP_len = asn1_get_int(buf, &offset, &dP); | |
171 dQ_len = asn1_get_int(buf, &offset, &dQ); | |
172 qInv_len = asn1_get_int(buf, &offset, &qInv); | |
173 | |
174 if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) | |
175 return X509_INVALID_PRIV_KEY; | |
176 | |
177 RSA_priv_key_new(rsa_ctx, | |
178 modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, | |
179 p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); | |
180 | |
181 free(p); | |
182 free(q); | |
183 free(dP); | |
184 free(dQ); | |
185 free(qInv); | |
186 #else | |
187 RSA_priv_key_new(rsa_ctx, | |
188 modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len); | |
189 #endif | |
190 | |
191 free(modulus); | |
192 free(priv_exp); | |
193 free(pub_exp); | |
194 return X509_OK; | |
195 } | |
196 | |
197 /** | |
198 * Get the time of a certificate. Ignore hours/minutes/seconds. | |
199 */ | |
200 static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) | |
201 { | |
202 int ret = X509_NOT_OK, len, t_offset; | |
203 struct tm tm; | |
204 | |
205 if (buf[(*offset)++] != ASN1_UTC_TIME) | |
206 goto end_utc_time; | |
207 len = get_asn1_length(buf, offset); | |
208 t_offset = *offset; | |
209 | |
210 memset(&tm, 0, sizeof(struct tm)); | |
211 tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0'); | |
212 | |
213 if (tm.tm_year <= 50) /* 1951-2050 thing */ | |
214 { | |
215 tm.tm_year += 100; | |
216 } | |
217 | |
218 tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1; | |
219 tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0'); | |
220 *t = mktime(&tm); | |
221 *offset += len; | |
222 ret = X509_OK; | |
223 | |
224 end_utc_time: | |
225 return ret; | |
226 } | |
227 | |
228 /** | |
229 * Get the version type of a certificate (which we don't actually care about) | |
230 */ | |
231 int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) | |
232 { | |
233 int ret = X509_NOT_OK; | |
234 | |
235 (*offset) += 2; /* get past explicit tag */ | |
236 if (asn1_skip_obj(cert, offset, ASN1_INTEGER)) | |
237 goto end_version; | |
238 | |
239 ret = X509_OK; | |
240 end_version: | |
241 return ret; | |
242 } | |
243 | |
244 /** | |
245 * Retrieve the notbefore and notafter certificate times. | |
246 */ | |
247 int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) | |
248 { | |
249 return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || | |
250 asn1_get_utc_time(cert, offset, &x509_ctx->not_before) || | |
251 asn1_get_utc_time(cert, offset, &x509_ctx->not_after)); | |
252 } | |
253 | |
254 /** | |
255 * Get the components of a distinguished name | |
256 */ | |
257 static int asn1_get_oid_x520(const uint8_t *buf, int *offset) | |
258 { | |
259 int dn_type = 0; | |
260 int len; | |
261 | |
262 if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) | |
263 goto end_oid; | |
264 | |
265 /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name | |
266 components we are interested in. */ | |
267 if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04) | |
268 dn_type = buf[(*offset)++]; | |
269 else | |
270 { | |
271 *offset += len; /* skip over it */ | |
272 } | |
273 | |
274 end_oid: | |
275 return dn_type; | |
276 } | |
277 | |
278 /** | |
279 * Obtain an ASN.1 printable string type. | |
280 */ | |
281 static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str) | |
282 { | |
283 int len = X509_NOT_OK; | |
284 | |
285 /* some certs have this awful crud in them for some reason */ | |
286 if (buf[*offset] != ASN1_PRINTABLE_STR && | |
287 buf[*offset] != ASN1_TELETEX_STR && | |
288 buf[*offset] != ASN1_IA5_STR && | |
289 buf[*offset] != ASN1_UNICODE_STR) | |
290 goto end_pnt_str; | |
291 | |
292 (*offset)++; | |
293 len = get_asn1_length(buf, offset); | |
294 | |
295 if (buf[*offset - 1] == ASN1_UNICODE_STR) | |
296 { | |
297 int i; | |
298 *str = (char *)malloc(len/2+1); /* allow for null */ | |
299 | |
300 for (i = 0; i < len; i += 2) | |
301 (*str)[i/2] = buf[*offset + i + 1]; | |
302 | |
303 (*str)[len/2] = 0; /* null terminate */ | |
304 } | |
305 else | |
306 { | |
307 *str = (char *)malloc(len+1); /* allow for null */ | |
308 memcpy(*str, &buf[*offset], len); | |
309 (*str)[len] = 0; /* null terminate */ | |
310 } | |
311 | |
312 *offset += len; | |
313 | |
314 end_pnt_str: | |
315 return len; | |
316 } | |
317 | |
318 /** | |
319 * Get the subject name (or the issuer) of a certificate. | |
320 */ | |
321 int asn1_name(const uint8_t *cert, int *offset, char *dn[]) | |
322 { | |
323 int ret = X509_NOT_OK; | |
324 int dn_type; | |
325 char *tmp = NULL; | |
326 | |
327 if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) | |
328 goto end_name; | |
329 | |
330 while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) | |
331 { | |
332 int i, found = 0; | |
333 | |
334 if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || | |
335 (dn_type = asn1_get_oid_x520(cert, offset)) < 0) | |
336 goto end_name; | |
337 | |
338 if (asn1_get_printable_str(cert, offset, &tmp) < 0) | |
339 { | |
340 free(tmp); | |
341 goto end_name; | |
342 } | |
343 | |
344 /* find the distinguished named type */ | |
345 for (i = 0; i < X509_NUM_DN_TYPES; i++) | |
346 { | |
347 if (dn_type == g_dn_types[i]) | |
348 { | |
349 if (dn[i] == NULL) | |
350 { | |
351 dn[i] = tmp; | |
352 found = 1; | |
353 break; | |
354 } | |
355 } | |
356 } | |
357 | |
358 if (found == 0) /* not found so get rid of it */ | |
359 { | |
360 free(tmp); | |
361 } | |
362 } | |
363 | |
364 ret = X509_OK; | |
365 end_name: | |
366 return ret; | |
367 } | |
368 | |
369 /** | |
370 * Read the modulus and public exponent of a certificate. | |
371 */ | |
372 int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) | |
373 { | |
374 int ret = X509_NOT_OK, mod_len, pub_len; | |
375 uint8_t *modulus = NULL, *pub_exp = NULL; | |
376 | |
377 if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || | |
378 asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || | |
379 asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) | |
380 goto end_pub_key; | |
381 | |
382 (*offset)++; /* ignore the padding bit field */ | |
383 | |
384 if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) | |
385 goto end_pub_key; | |
386 | |
387 mod_len = asn1_get_int(cert, offset, &modulus); | |
388 pub_len = asn1_get_int(cert, offset, &pub_exp); | |
389 | |
390 RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); | |
391 | |
392 free(modulus); | |
393 free(pub_exp); | |
394 ret = X509_OK; | |
395 | |
396 end_pub_key: | |
397 return ret; | |
398 } | |
399 | |
400 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
401 /** | |
402 * Read the signature of the certificate. | |
403 */ | |
404 int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) | |
405 { | |
406 int ret = X509_NOT_OK; | |
407 | |
408 if (cert[(*offset)++] != ASN1_BIT_STRING) | |
409 goto end_sig; | |
410 | |
411 x509_ctx->sig_len = get_asn1_length(cert, offset)-1; | |
412 (*offset)++; /* ignore bit string padding bits */ | |
413 x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len); | |
414 memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len); | |
415 *offset += x509_ctx->sig_len; | |
416 ret = X509_OK; | |
417 | |
418 end_sig: | |
419 return ret; | |
420 } | |
421 | |
422 /* | |
423 * Compare 2 distinguished name components for equality | |
424 * @return 0 if a match | |
425 */ | |
426 static int asn1_compare_dn_comp(const char *dn1, const char *dn2) | |
427 { | |
428 int ret = 1; | |
429 | |
430 if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match; | |
431 | |
432 ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0; | |
433 | |
434 err_no_match: | |
435 return ret; | |
436 } | |
437 | |
438 /** | |
439 * Clean up all of the CA certificates. | |
440 */ | |
441 void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) | |
442 { | |
443 int i = 0; | |
444 | |
445 if (ca_cert_ctx == NULL) | |
446 return; | |
447 | |
448 while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) | |
449 { | |
450 x509_free(ca_cert_ctx->cert[i]); | |
451 ca_cert_ctx->cert[i++] = NULL; | |
452 } | |
453 | |
454 free(ca_cert_ctx); | |
455 } | |
456 | |
457 /* | |
458 * Compare 2 distinguished names for equality | |
459 * @return 0 if a match | |
460 */ | |
461 int asn1_compare_dn(char * const dn1[], char * const dn2[]) | |
462 { | |
463 int i; | |
464 | |
465 for (i = 0; i < X509_NUM_DN_TYPES; i++) | |
466 { | |
467 if (asn1_compare_dn_comp(dn1[i], dn2[i])) | |
468 return 1; | |
469 } | |
470 | |
471 return 0; /* all good */ | |
472 } | |
473 | |
474 #endif | |
475 | |
476 /** | |
477 * Read the signature type of the certificate. We only support RSA-MD5 and | |
478 * RSA-SHA1 signature types. | |
479 */ | |
480 int asn1_signature_type(const uint8_t *cert, | |
481 int *offset, X509_CTX *x509_ctx) | |
482 { | |
483 int ret = X509_NOT_OK, len; | |
484 | |
485 if (cert[(*offset)++] != ASN1_OID) | |
486 goto end_check_sig; | |
487 | |
488 len = get_asn1_length(cert, offset); | |
489 | |
490 if (len == 5 && memcmp(sig_iis6_oid, &cert[*offset], | |
491 SIG_IIS6_OID_SIZE) == 0) | |
492 { | |
493 x509_ctx->sig_type = SIG_TYPE_SHA1; | |
494 } | |
495 else | |
496 { | |
497 if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE)) | |
498 goto end_check_sig; /* unrecognised cert type */ | |
499 | |
500 x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE]; | |
501 } | |
502 | |
503 *offset += len; | |
504 asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */ | |
505 ret = X509_OK; | |
506 | |
507 end_check_sig: | |
508 return ret; | |
509 } | |
510 |