Mercurial > projects > hoofbaby
comparison deps/Platinum/ThirdParty/Neptune/ThirdParty/axTLS/ssl/x509.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 * @file x509.c | |
33 * | |
34 * Certificate processing. | |
35 */ | |
36 | |
37 #include <stdio.h> | |
38 #include <stdlib.h> | |
39 #include <string.h> | |
40 #include <time.h> | |
41 #include "os_port.h" | |
42 #include "crypto_misc.h" | |
43 | |
44 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
45 /** | |
46 * Retrieve the signature from a certificate. | |
47 */ | |
48 static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len) | |
49 { | |
50 int offset = 0; | |
51 const uint8_t *ptr = NULL; | |
52 | |
53 if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || | |
54 asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) | |
55 goto end_get_sig; | |
56 | |
57 if (asn1_sig[offset++] != ASN1_OCTET_STRING) | |
58 goto end_get_sig; | |
59 *len = get_asn1_length(asn1_sig, &offset); | |
60 ptr = &asn1_sig[offset]; /* all ok */ | |
61 | |
62 end_get_sig: | |
63 return ptr; | |
64 } | |
65 | |
66 #endif | |
67 | |
68 /** | |
69 * Construct a new x509 object. | |
70 * @return 0 if ok. < 0 if there was a problem. | |
71 */ | |
72 int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) | |
73 { | |
74 int begin_tbs, end_tbs; | |
75 int ret = X509_NOT_OK, offset = 0, cert_size = 0; | |
76 X509_CTX *x509_ctx; | |
77 BI_CTX *bi_ctx; | |
78 | |
79 *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); | |
80 x509_ctx = *ctx; | |
81 | |
82 /* get the certificate size */ | |
83 asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); | |
84 | |
85 if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) | |
86 goto end_cert; | |
87 | |
88 begin_tbs = offset; /* start of the tbs */ | |
89 end_tbs = begin_tbs; /* work out the end of the tbs */ | |
90 asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); | |
91 | |
92 if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) | |
93 goto end_cert; | |
94 | |
95 if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */ | |
96 { | |
97 if (asn1_version(cert, &offset, x509_ctx)) | |
98 goto end_cert; | |
99 } | |
100 | |
101 if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ | |
102 asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) | |
103 goto end_cert; | |
104 | |
105 /* make sure the signature is ok */ | |
106 if (asn1_signature_type(cert, &offset, x509_ctx)) | |
107 { | |
108 ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; | |
109 goto end_cert; | |
110 } | |
111 | |
112 if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || | |
113 asn1_validity(cert, &offset, x509_ctx) || | |
114 asn1_name(cert, &offset, x509_ctx->cert_dn) || | |
115 asn1_public_key(cert, &offset, x509_ctx)) | |
116 goto end_cert; | |
117 | |
118 bi_ctx = x509_ctx->rsa_ctx->bi_ctx; | |
119 | |
120 #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ | |
121 /* use the appropriate signature algorithm (SHA1/MD5/MD2) */ | |
122 if (x509_ctx->sig_type == SIG_TYPE_MD5) | |
123 { | |
124 MD5_CTX md5_ctx; | |
125 uint8_t md5_dgst[MD5_SIZE]; | |
126 MD5_Init(&md5_ctx); | |
127 MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); | |
128 MD5_Final(md5_dgst, &md5_ctx); | |
129 x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); | |
130 } | |
131 else if (x509_ctx->sig_type == SIG_TYPE_SHA1) | |
132 { | |
133 SHA1_CTX sha_ctx; | |
134 uint8_t sha_dgst[SHA1_SIZE]; | |
135 SHA1_Init(&sha_ctx); | |
136 SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); | |
137 SHA1_Final(sha_dgst, &sha_ctx); | |
138 x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); | |
139 } | |
140 else if (x509_ctx->sig_type == SIG_TYPE_MD2) | |
141 { | |
142 MD2_CTX md2_ctx; | |
143 uint8_t md2_dgst[MD2_SIZE]; | |
144 MD2_Init(&md2_ctx); | |
145 MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs); | |
146 MD2_Final(md2_dgst, &md2_ctx); | |
147 x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE); | |
148 } | |
149 | |
150 offset = end_tbs; /* skip the v3 data */ | |
151 if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || | |
152 asn1_signature(cert, &offset, x509_ctx)) | |
153 goto end_cert; | |
154 #endif | |
155 | |
156 /* GBG: compute the fingerprints */ | |
157 { | |
158 MD5_CTX md5_ctx; | |
159 MD5_Init(&md5_ctx); | |
160 MD5_Update(&md5_ctx, cert, cert_size); | |
161 MD5_Final(x509_ctx->fingerprint.md5, &md5_ctx); | |
162 } | |
163 { | |
164 SHA1_CTX sha1_ctx; | |
165 SHA1_Init(&sha1_ctx); | |
166 SHA1_Update(&sha1_ctx, cert, cert_size); | |
167 SHA1_Final(x509_ctx->fingerprint.sha1, &sha1_ctx); | |
168 } | |
169 /* /GBG: compute the fingerprints */ | |
170 | |
171 if (len) | |
172 { | |
173 *len = cert_size; | |
174 } | |
175 | |
176 ret = X509_OK; | |
177 end_cert: | |
178 | |
179 #ifdef CONFIG_SSL_FULL_MODE | |
180 if (ret) | |
181 { | |
182 printf("Error: Invalid X509 ASN.1 file\n"); | |
183 } | |
184 #endif | |
185 | |
186 return ret; | |
187 } | |
188 | |
189 /** | |
190 * Free an X.509 object's resources. | |
191 */ | |
192 void x509_free(X509_CTX *x509_ctx) | |
193 { | |
194 X509_CTX *next; | |
195 int i; | |
196 | |
197 if (x509_ctx == NULL) /* if already null, then don't bother */ | |
198 return; | |
199 | |
200 for (i = 0; i < X509_NUM_DN_TYPES; i++) | |
201 { | |
202 free(x509_ctx->ca_cert_dn[i]); | |
203 free(x509_ctx->cert_dn[i]); | |
204 } | |
205 | |
206 free(x509_ctx->signature); | |
207 | |
208 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
209 if (x509_ctx->digest) | |
210 { | |
211 bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); | |
212 } | |
213 #endif | |
214 | |
215 RSA_free(x509_ctx->rsa_ctx); | |
216 | |
217 next = x509_ctx->next; | |
218 free(x509_ctx); | |
219 x509_free(next); /* clear the chain */ | |
220 } | |
221 | |
222 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
223 /** | |
224 * Take a signature and decrypt it. | |
225 */ | |
226 static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, | |
227 bigint *modulus, bigint *pub_exp) | |
228 { | |
229 int i, size; | |
230 bigint *decrypted_bi, *dat_bi; | |
231 bigint *bir = NULL; | |
232 uint8_t *block = (uint8_t *)alloca(sig_len); | |
233 | |
234 /* decrypt */ | |
235 dat_bi = bi_import(ctx, sig, sig_len); | |
236 ctx->mod_offset = BIGINT_M_OFFSET; | |
237 | |
238 /* convert to a normal block */ | |
239 decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); | |
240 | |
241 bi_export(ctx, decrypted_bi, block, sig_len); | |
242 ctx->mod_offset = BIGINT_M_OFFSET; | |
243 | |
244 i = 10; /* start at the first possible non-padded byte */ | |
245 while (block[i++] && i < sig_len); | |
246 size = sig_len - i; | |
247 | |
248 /* get only the bit we want */ | |
249 if (size > 0) | |
250 { | |
251 int len; | |
252 const uint8_t *sig_ptr = get_signature(&block[i], &len); | |
253 | |
254 if (sig_ptr) | |
255 { | |
256 bir = bi_import(ctx, sig_ptr, len); | |
257 } | |
258 } | |
259 | |
260 /* save a few bytes of memory */ | |
261 bi_clear_cache(ctx); | |
262 return bir; | |
263 } | |
264 | |
265 /** | |
266 * Do some basic checks on the certificate chain. | |
267 * | |
268 * Certificate verification consists of a number of checks: | |
269 * - A root certificate exists in the certificate store. | |
270 * - The date of the certificate is after the start date. | |
271 * - The date of the certificate is before the finish date. | |
272 * - The certificate chain is valid. | |
273 * - That the certificate(s) are not self-signed. | |
274 * - The signature of the certificate is valid. | |
275 */ | |
276 int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) | |
277 { | |
278 int ret = X509_OK, i = 0; | |
279 bigint *cert_sig; | |
280 X509_CTX *next_cert = NULL; | |
281 BI_CTX *ctx; | |
282 bigint *mod = NULL, *expn = NULL; | |
283 struct timeval tv; | |
284 int match_ca_cert = 0; | |
285 uint8_t is_self_signed = 0; | |
286 | |
287 if (cert == NULL || ca_cert_ctx == NULL) | |
288 { | |
289 ret = X509_VFY_ERROR_NO_TRUSTED_CERT; | |
290 goto end_verify; | |
291 } | |
292 | |
293 /* last cert in the chain - look for a trusted cert */ | |
294 if (cert->next == NULL && ca_cert_ctx) | |
295 { | |
296 while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) | |
297 { | |
298 if (asn1_compare_dn(cert->ca_cert_dn, | |
299 ca_cert_ctx->cert[i]->cert_dn) == 0) | |
300 { | |
301 match_ca_cert = 1; | |
302 next_cert = ca_cert_ctx->cert[i]; | |
303 break; | |
304 } | |
305 | |
306 i++; | |
307 } | |
308 | |
309 /* trusted cert not found */ | |
310 if (match_ca_cert == 0) | |
311 { | |
312 ret = X509_VFY_ERROR_NO_TRUSTED_CERT; | |
313 goto end_verify; | |
314 } | |
315 } | |
316 else | |
317 { | |
318 next_cert = cert->next; | |
319 } | |
320 | |
321 gettimeofday(&tv, NULL); | |
322 | |
323 /* check the not before date */ | |
324 if (tv.tv_sec < cert->not_before) | |
325 { | |
326 ret = X509_VFY_ERROR_NOT_YET_VALID; | |
327 goto end_verify; | |
328 } | |
329 | |
330 /* check the not after date */ | |
331 if (tv.tv_sec > cert->not_after) | |
332 { | |
333 ret = X509_VFY_ERROR_EXPIRED; | |
334 goto end_verify; | |
335 } | |
336 | |
337 ctx = cert->rsa_ctx->bi_ctx; | |
338 | |
339 /* check for self-signing */ | |
340 if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) | |
341 { | |
342 is_self_signed = 1; | |
343 mod = cert->rsa_ctx->m; | |
344 expn = cert->rsa_ctx->e; | |
345 } | |
346 else if (next_cert != NULL) | |
347 { | |
348 mod = next_cert->rsa_ctx->m; | |
349 expn = next_cert->rsa_ctx->e; | |
350 | |
351 /* check the chain integrity */ | |
352 if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) | |
353 { | |
354 ret = X509_VFY_ERROR_INVALID_CHAIN; | |
355 goto end_verify; | |
356 } | |
357 } | |
358 | |
359 /* check the signature */ | |
360 if (mod != NULL) | |
361 { | |
362 cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, | |
363 bi_clone(ctx, mod), bi_clone(ctx, expn)); | |
364 | |
365 if (cert_sig && cert->digest) | |
366 { | |
367 if (bi_compare(cert_sig, cert->digest)) | |
368 { | |
369 ret = X509_VFY_ERROR_BAD_SIGNATURE; | |
370 } | |
371 | |
372 bi_free(ctx, cert_sig); | |
373 | |
374 if (ret) | |
375 goto end_verify; | |
376 } | |
377 else | |
378 { | |
379 ret = X509_VFY_ERROR_BAD_SIGNATURE; | |
380 goto end_verify; | |
381 } | |
382 } | |
383 | |
384 if (is_self_signed) | |
385 { | |
386 ret = X509_VFY_ERROR_SELF_SIGNED; | |
387 goto end_verify; | |
388 } | |
389 | |
390 /* go down the certificate chain using recursion. */ | |
391 if (ret == 0 && cert->next) | |
392 { | |
393 ret = x509_verify(ca_cert_ctx, next_cert); | |
394 } | |
395 | |
396 end_verify: | |
397 return ret; | |
398 } | |
399 #endif | |
400 | |
401 #if defined (CONFIG_SSL_FULL_MODE) | |
402 /** | |
403 * Used for diagnostics. | |
404 */ | |
405 static const char *not_part_of_cert = "<Not Part Of Certificate>"; | |
406 void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) | |
407 { | |
408 if (cert == NULL) | |
409 return; | |
410 | |
411 printf("=== CERTIFICATE ISSUED TO ===\n"); | |
412 printf("Common Name (CN):\t\t"); | |
413 printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ? | |
414 cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); | |
415 | |
416 printf("Organization (O):\t\t"); | |
417 printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ? | |
418 cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); | |
419 | |
420 printf("Organizational Unit (OU):\t"); | |
421 printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ? | |
422 cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); | |
423 | |
424 printf("=== CERTIFICATE ISSUED BY ===\n"); | |
425 printf("Common Name (CN):\t\t"); | |
426 printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ? | |
427 cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); | |
428 | |
429 printf("Organization (O):\t\t"); | |
430 printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ? | |
431 cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); | |
432 | |
433 printf("Organizational Unit (OU):\t"); | |
434 printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ? | |
435 cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); | |
436 | |
437 printf("Not Before:\t\t\t%s", ctime(&cert->not_before)); | |
438 printf("Not After:\t\t\t%s", ctime(&cert->not_after)); | |
439 printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8); | |
440 printf("Sig Type:\t\t\t"); | |
441 switch (cert->sig_type) | |
442 { | |
443 case SIG_TYPE_MD5: | |
444 printf("MD5\n"); | |
445 break; | |
446 case SIG_TYPE_SHA1: | |
447 printf("SHA1\n"); | |
448 break; | |
449 case SIG_TYPE_MD2: | |
450 printf("MD2\n"); | |
451 break; | |
452 default: | |
453 printf("Unrecognized: %d\n", cert->sig_type); | |
454 break; | |
455 } | |
456 | |
457 if (ca_cert_ctx) | |
458 { | |
459 printf("Verify:\t\t\t%s\n", | |
460 x509_display_error(x509_verify(ca_cert_ctx, cert))); | |
461 } | |
462 | |
463 #if 0 | |
464 print_blob("Signature", cert->signature, cert->sig_len); | |
465 bi_print("Modulus", cert->rsa_ctx->m); | |
466 bi_print("Pub Exp", cert->rsa_ctx->e); | |
467 #endif | |
468 | |
469 if (ca_cert_ctx) | |
470 { | |
471 x509_print(cert->next, ca_cert_ctx); | |
472 } | |
473 | |
474 TTY_FLUSH(); | |
475 } | |
476 | |
477 const char * x509_display_error(int error) | |
478 { | |
479 switch (error) | |
480 { | |
481 case X509_NOT_OK: | |
482 return "X509 not ok"; | |
483 | |
484 case X509_VFY_ERROR_NO_TRUSTED_CERT: | |
485 return "No trusted cert is available"; | |
486 | |
487 case X509_VFY_ERROR_BAD_SIGNATURE: | |
488 return "Bad signature"; | |
489 | |
490 case X509_VFY_ERROR_NOT_YET_VALID: | |
491 return "Cert is not yet valid"; | |
492 | |
493 case X509_VFY_ERROR_EXPIRED: | |
494 return "Cert has expired"; | |
495 | |
496 case X509_VFY_ERROR_SELF_SIGNED: | |
497 return "Cert is self-signed"; | |
498 | |
499 case X509_VFY_ERROR_INVALID_CHAIN: | |
500 return "Chain is invalid (check order of certs)"; | |
501 | |
502 case X509_VFY_ERROR_UNSUPPORTED_DIGEST: | |
503 return "Unsupported digest"; | |
504 | |
505 case X509_INVALID_PRIV_KEY: | |
506 return "Invalid private key"; | |
507 | |
508 default: | |
509 return "Unknown"; | |
510 } | |
511 } | |
512 #endif /* CONFIG_SSL_FULL_MODE */ | |
513 |