Annotation of embedaddon/curl/lib/x509asn1.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22:
23: #include "curl_setup.h"
24:
25: #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
26: defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
27:
28: #include <curl/curl.h>
29: #include "urldata.h"
30: #include "strcase.h"
31: #include "hostcheck.h"
32: #include "vtls/vtls.h"
33: #include "sendf.h"
34: #include "inet_pton.h"
35: #include "curl_base64.h"
36: #include "x509asn1.h"
37:
38: /* The last 3 #include files should be in this order */
39: #include "curl_printf.h"
40: #include "curl_memory.h"
41: #include "memdebug.h"
42:
43: /* ASN.1 OIDs. */
44: static const char cnOID[] = "2.5.4.3"; /* Common name. */
45: static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */
46:
47: static const curl_OID OIDtable[] = {
48: { "1.2.840.10040.4.1", "dsa" },
49: { "1.2.840.10040.4.3", "dsa-with-sha1" },
50: { "1.2.840.10045.2.1", "ecPublicKey" },
51: { "1.2.840.10045.3.0.1", "c2pnb163v1" },
52: { "1.2.840.10045.4.1", "ecdsa-with-SHA1" },
53: { "1.2.840.10046.2.1", "dhpublicnumber" },
54: { "1.2.840.113549.1.1.1", "rsaEncryption" },
55: { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" },
56: { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" },
57: { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" },
58: { "1.2.840.113549.1.1.10", "RSASSA-PSS" },
59: { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" },
60: { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" },
61: { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" },
62: { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" },
63: { "1.2.840.113549.2.2", "md2" },
64: { "1.2.840.113549.2.5", "md5" },
65: { "1.3.14.3.2.26", "sha1" },
66: { cnOID, "CN" },
67: { "2.5.4.4", "SN" },
68: { "2.5.4.5", "serialNumber" },
69: { "2.5.4.6", "C" },
70: { "2.5.4.7", "L" },
71: { "2.5.4.8", "ST" },
72: { "2.5.4.9", "streetAddress" },
73: { "2.5.4.10", "O" },
74: { "2.5.4.11", "OU" },
75: { "2.5.4.12", "title" },
76: { "2.5.4.13", "description" },
77: { "2.5.4.17", "postalCode" },
78: { "2.5.4.41", "name" },
79: { "2.5.4.42", "givenName" },
80: { "2.5.4.43", "initials" },
81: { "2.5.4.44", "generationQualifier" },
82: { "2.5.4.45", "X500UniqueIdentifier" },
83: { "2.5.4.46", "dnQualifier" },
84: { "2.5.4.65", "pseudonym" },
85: { "1.2.840.113549.1.9.1", "emailAddress" },
86: { "2.5.4.72", "role" },
87: { sanOID, "subjectAltName" },
88: { "2.5.29.18", "issuerAltName" },
89: { "2.5.29.19", "basicConstraints" },
90: { "2.16.840.1.101.3.4.2.4", "sha224" },
91: { "2.16.840.1.101.3.4.2.1", "sha256" },
92: { "2.16.840.1.101.3.4.2.2", "sha384" },
93: { "2.16.840.1.101.3.4.2.3", "sha512" },
94: { (const char *) NULL, (const char *) NULL }
95: };
96:
97: /*
98: * Lightweight ASN.1 parser.
99: * In particular, it does not check for syntactic/lexical errors.
100: * It is intended to support certificate information gathering for SSL backends
101: * that offer a mean to get certificates as a whole, but do not supply
102: * entry points to get particular certificate sub-fields.
103: * Please note there is no pretention here to rewrite a full SSL library.
104: */
105:
106: static const char *getASN1Element(curl_asn1Element *elem,
107: const char *beg, const char *end)
108: WARN_UNUSED_RESULT;
109:
110: static const char *getASN1Element(curl_asn1Element *elem,
111: const char *beg, const char *end)
112: {
113: unsigned char b;
114: unsigned long len;
115: curl_asn1Element lelem;
116:
117: /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
118: ending at `end'.
119: Returns a pointer in source string after the parsed element, or NULL
120: if an error occurs. */
121: if(!beg || !end || beg >= end || !*beg ||
122: (size_t)(end - beg) > CURL_ASN1_MAX)
123: return NULL;
124:
125: /* Process header byte. */
126: elem->header = beg;
127: b = (unsigned char) *beg++;
128: elem->constructed = (b & 0x20) != 0;
129: elem->class = (b >> 6) & 3;
130: b &= 0x1F;
131: if(b == 0x1F)
132: return NULL; /* Long tag values not supported here. */
133: elem->tag = b;
134:
135: /* Process length. */
136: if(beg >= end)
137: return NULL;
138: b = (unsigned char) *beg++;
139: if(!(b & 0x80))
140: len = b;
141: else if(!(b &= 0x7F)) {
142: /* Unspecified length. Since we have all the data, we can determine the
143: effective length by skipping element until an end element is found. */
144: if(!elem->constructed)
145: return NULL;
146: elem->beg = beg;
147: while(beg < end && *beg) {
148: beg = getASN1Element(&lelem, beg, end);
149: if(!beg)
150: return NULL;
151: }
152: if(beg >= end)
153: return NULL;
154: elem->end = beg;
155: return beg + 1;
156: }
157: else if((unsigned)b > (size_t)(end - beg))
158: return NULL; /* Does not fit in source. */
159: else {
160: /* Get long length. */
161: len = 0;
162: do {
163: if(len & 0xFF000000L)
164: return NULL; /* Lengths > 32 bits are not supported. */
165: len = (len << 8) | (unsigned char) *beg++;
166: } while(--b);
167: }
168: if(len > (size_t)(end - beg))
169: return NULL; /* Element data does not fit in source. */
170: elem->beg = beg;
171: elem->end = beg + len;
172: return elem->end;
173: }
174:
175: /*
176: * Search the null terminated OID or OID identifier in local table.
177: * Return the table entry pointer or NULL if not found.
178: */
179: static const curl_OID * searchOID(const char *oid)
180: {
181: const curl_OID *op;
182: for(op = OIDtable; op->numoid; op++)
183: if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
184: return op;
185:
186: return NULL;
187: }
188:
189: /*
190: * Convert an ASN.1 Boolean value into its string representation. Return the
191: * dynamically allocated string, or NULL if source is not an ASN.1 Boolean
192: * value.
193: */
194:
195: static const char *bool2str(const char *beg, const char *end)
196: {
197: if(end - beg != 1)
198: return NULL;
199: return strdup(*beg? "TRUE": "FALSE");
200: }
201:
202: /*
203: * Convert an ASN.1 octet string to a printable string.
204: * Return the dynamically allocated string, or NULL if an error occurs.
205: */
206: static const char *octet2str(const char *beg, const char *end)
207: {
208: size_t n = end - beg;
209: char *buf = NULL;
210:
211: if(n <= (SIZE_T_MAX - 1) / 3) {
212: buf = malloc(3 * n + 1);
213: if(buf)
214: for(n = 0; beg < end; n += 3)
215: msnprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
216: }
217: return buf;
218: }
219:
220: static const char *bit2str(const char *beg, const char *end)
221: {
222: /* Convert an ASN.1 bit string to a printable string.
223: Return the dynamically allocated string, or NULL if an error occurs. */
224:
225: if(++beg > end)
226: return NULL;
227: return octet2str(beg, end);
228: }
229:
230: /*
231: * Convert an ASN.1 integer value into its string representation.
232: * Return the dynamically allocated string, or NULL if source is not an
233: * ASN.1 integer value.
234: */
235: static const char *int2str(const char *beg, const char *end)
236: {
237: unsigned long val = 0;
238: size_t n = end - beg;
239:
240: if(!n)
241: return NULL;
242:
243: if(n > 4)
244: return octet2str(beg, end);
245:
246: /* Represent integers <= 32-bit as a single value. */
247: if(*beg & 0x80)
248: val = ~val;
249:
250: do
251: val = (val << 8) | *(const unsigned char *) beg++;
252: while(beg < end);
253: return curl_maprintf("%s%lx", val >= 10? "0x": "", val);
254: }
255:
256: /*
257: * Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
258: * destination buffer dynamically. The allocation size will normally be too
259: * large: this is to avoid buffer overflows.
260: * Terminate the string with a nul byte and return the converted
261: * string length.
262: */
263: static ssize_t
264: utf8asn1str(char **to, int type, const char *from, const char *end)
265: {
266: size_t inlength = end - from;
267: int size = 1;
268: size_t outlength;
269: char *buf;
270:
271: *to = NULL;
272: switch(type) {
273: case CURL_ASN1_BMP_STRING:
274: size = 2;
275: break;
276: case CURL_ASN1_UNIVERSAL_STRING:
277: size = 4;
278: break;
279: case CURL_ASN1_NUMERIC_STRING:
280: case CURL_ASN1_PRINTABLE_STRING:
281: case CURL_ASN1_TELETEX_STRING:
282: case CURL_ASN1_IA5_STRING:
283: case CURL_ASN1_VISIBLE_STRING:
284: case CURL_ASN1_UTF8_STRING:
285: break;
286: default:
287: return -1; /* Conversion not supported. */
288: }
289:
290: if(inlength % size)
291: return -1; /* Length inconsistent with character size. */
292: if(inlength / size > (SIZE_T_MAX - 1) / 4)
293: return -1; /* Too big. */
294: buf = malloc(4 * (inlength / size) + 1);
295: if(!buf)
296: return -1; /* Not enough memory. */
297:
298: if(type == CURL_ASN1_UTF8_STRING) {
299: /* Just copy. */
300: outlength = inlength;
301: if(outlength)
302: memcpy(buf, from, outlength);
303: }
304: else {
305: for(outlength = 0; from < end;) {
306: int charsize;
307: unsigned int wc;
308:
309: wc = 0;
310: switch(size) {
311: case 4:
312: wc = (wc << 8) | *(const unsigned char *) from++;
313: wc = (wc << 8) | *(const unsigned char *) from++;
314: /* FALLTHROUGH */
315: case 2:
316: wc = (wc << 8) | *(const unsigned char *) from++;
317: /* FALLTHROUGH */
318: default: /* case 1: */
319: wc = (wc << 8) | *(const unsigned char *) from++;
320: }
321: charsize = 1;
322: if(wc >= 0x00000080) {
323: if(wc >= 0x00000800) {
324: if(wc >= 0x00010000) {
325: if(wc >= 0x00200000) {
326: free(buf);
327: return -1; /* Invalid char. size for target encoding. */
328: }
329: buf[outlength + 3] = (char) (0x80 | (wc & 0x3F));
330: wc = (wc >> 6) | 0x00010000;
331: charsize++;
332: }
333: buf[outlength + 2] = (char) (0x80 | (wc & 0x3F));
334: wc = (wc >> 6) | 0x00000800;
335: charsize++;
336: }
337: buf[outlength + 1] = (char) (0x80 | (wc & 0x3F));
338: wc = (wc >> 6) | 0x000000C0;
339: charsize++;
340: }
341: buf[outlength] = (char) wc;
342: outlength += charsize;
343: }
344: }
345: buf[outlength] = '\0';
346: *to = buf;
347: return outlength;
348: }
349:
350: /*
351: * Convert an ASN.1 String into its UTF-8 string representation.
352: * Return the dynamically allocated string, or NULL if an error occurs.
353: */
354: static const char *string2str(int type, const char *beg, const char *end)
355: {
356: char *buf;
357: if(utf8asn1str(&buf, type, beg, end) < 0)
358: return NULL;
359: return buf;
360: }
361:
362: /*
363: * Decimal ASCII encode unsigned integer `x' into the buflen sized buffer at
364: * buf. Return the total number of encoded digits, even if larger than
365: * `buflen'.
366: */
367: static size_t encodeUint(char *buf, size_t buflen, unsigned int x)
368: {
369: size_t i = 0;
370: unsigned int y = x / 10;
371:
372: if(y) {
373: i = encodeUint(buf, buflen, y);
374: x -= y * 10;
375: }
376: if(i < buflen)
377: buf[i] = (char) ('0' + x);
378: i++;
379: if(i < buflen)
380: buf[i] = '\0'; /* Store a terminator if possible. */
381: return i;
382: }
383:
384: /*
385: * Convert an ASN.1 OID into its dotted string representation.
386: * Store the result in th `n'-byte buffer at `buf'.
387: * Return the converted string length, or 0 on errors.
388: */
389: static size_t encodeOID(char *buf, size_t buflen,
390: const char *beg, const char *end)
391: {
392: size_t i;
393: unsigned int x;
394: unsigned int y;
395:
396: /* Process the first two numbers. */
397: y = *(const unsigned char *) beg++;
398: x = y / 40;
399: y -= x * 40;
400: i = encodeUint(buf, buflen, x);
401: if(i < buflen)
402: buf[i] = '.';
403: i++;
404: if(i >= buflen)
405: i += encodeUint(NULL, 0, y);
406: else
407: i += encodeUint(buf + i, buflen - i, y);
408:
409: /* Process the trailing numbers. */
410: while(beg < end) {
411: if(i < buflen)
412: buf[i] = '.';
413: i++;
414: x = 0;
415: do {
416: if(x & 0xFF000000)
417: return 0;
418: y = *(const unsigned char *) beg++;
419: x = (x << 7) | (y & 0x7F);
420: } while(y & 0x80);
421: if(i >= buflen)
422: i += encodeUint(NULL, 0, x);
423: else
424: i += encodeUint(buf + i, buflen - i, x);
425: }
426: if(i < buflen)
427: buf[i] = '\0';
428: return i;
429: }
430:
431: /*
432: * Convert an ASN.1 OID into its dotted or symbolic string representation.
433: * Return the dynamically allocated string, or NULL if an error occurs.
434: */
435:
436: static const char *OID2str(const char *beg, const char *end, bool symbolic)
437: {
438: char *buf = NULL;
439: if(beg < end) {
440: size_t buflen = encodeOID(NULL, 0, beg, end);
441: if(buflen) {
442: buf = malloc(buflen + 1); /* one extra for the zero byte */
443: if(buf) {
444: encodeOID(buf, buflen, beg, end);
445: buf[buflen] = '\0';
446:
447: if(symbolic) {
448: const curl_OID *op = searchOID(buf);
449: if(op) {
450: free(buf);
451: buf = strdup(op->textoid);
452: }
453: }
454: }
455: }
456: }
457: return buf;
458: }
459:
460: static const char *GTime2str(const char *beg, const char *end)
461: {
462: const char *tzp;
463: const char *fracp;
464: char sec1, sec2;
465: size_t fracl;
466: size_t tzl;
467: const char *sep = "";
468:
469: /* Convert an ASN.1 Generalized time to a printable string.
470: Return the dynamically allocated string, or NULL if an error occurs. */
471:
472: for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
473: ;
474:
475: /* Get seconds digits. */
476: sec1 = '0';
477: switch(fracp - beg - 12) {
478: case 0:
479: sec2 = '0';
480: break;
481: case 2:
482: sec1 = fracp[-2];
483: /* FALLTHROUGH */
484: case 1:
485: sec2 = fracp[-1];
486: break;
487: default:
488: return NULL;
489: }
490:
491: /* Scan for timezone, measure fractional seconds. */
492: tzp = fracp;
493: fracl = 0;
494: if(fracp < end && (*fracp == '.' || *fracp == ',')) {
495: fracp++;
496: do
497: tzp++;
498: while(tzp < end && *tzp >= '0' && *tzp <= '9');
499: /* Strip leading zeroes in fractional seconds. */
500: for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
501: ;
502: }
503:
504: /* Process timezone. */
505: if(tzp >= end)
506: ; /* Nothing to do. */
507: else if(*tzp == 'Z') {
508: tzp = " GMT";
509: end = tzp + 4;
510: }
511: else {
512: sep = " ";
513: tzp++;
514: }
515:
516: tzl = end - tzp;
517: return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
518: beg, beg + 4, beg + 6,
519: beg + 8, beg + 10, sec1, sec2,
520: fracl? ".": "", fracl, fracp,
521: sep, tzl, tzp);
522: }
523:
524: /*
525: * Convert an ASN.1 UTC time to a printable string.
526: * Return the dynamically allocated string, or NULL if an error occurs.
527: */
528: static const char *UTime2str(const char *beg, const char *end)
529: {
530: const char *tzp;
531: size_t tzl;
532: const char *sec;
533:
534: for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
535: ;
536: /* Get the seconds. */
537: sec = beg + 10;
538: switch(tzp - sec) {
539: case 0:
540: sec = "00";
541: case 2:
542: break;
543: default:
544: return NULL;
545: }
546:
547: /* Process timezone. */
548: if(tzp >= end)
549: return NULL;
550: if(*tzp == 'Z') {
551: tzp = "GMT";
552: end = tzp + 3;
553: }
554: else
555: tzp++;
556:
557: tzl = end - tzp;
558: return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
559: 20 - (*beg >= '5'), beg, beg + 2, beg + 4,
560: beg + 6, beg + 8, sec,
561: tzl, tzp);
562: }
563:
564: /*
565: * Convert an ASN.1 element to a printable string.
566: * Return the dynamically allocated string, or NULL if an error occurs.
567: */
568: static const char *ASN1tostr(curl_asn1Element *elem, int type)
569: {
570: if(elem->constructed)
571: return NULL; /* No conversion of structured elements. */
572:
573: if(!type)
574: type = elem->tag; /* Type not forced: use element tag as type. */
575:
576: switch(type) {
577: case CURL_ASN1_BOOLEAN:
578: return bool2str(elem->beg, elem->end);
579: case CURL_ASN1_INTEGER:
580: case CURL_ASN1_ENUMERATED:
581: return int2str(elem->beg, elem->end);
582: case CURL_ASN1_BIT_STRING:
583: return bit2str(elem->beg, elem->end);
584: case CURL_ASN1_OCTET_STRING:
585: return octet2str(elem->beg, elem->end);
586: case CURL_ASN1_NULL:
587: return strdup("");
588: case CURL_ASN1_OBJECT_IDENTIFIER:
589: return OID2str(elem->beg, elem->end, TRUE);
590: case CURL_ASN1_UTC_TIME:
591: return UTime2str(elem->beg, elem->end);
592: case CURL_ASN1_GENERALIZED_TIME:
593: return GTime2str(elem->beg, elem->end);
594: case CURL_ASN1_UTF8_STRING:
595: case CURL_ASN1_NUMERIC_STRING:
596: case CURL_ASN1_PRINTABLE_STRING:
597: case CURL_ASN1_TELETEX_STRING:
598: case CURL_ASN1_IA5_STRING:
599: case CURL_ASN1_VISIBLE_STRING:
600: case CURL_ASN1_UNIVERSAL_STRING:
601: case CURL_ASN1_BMP_STRING:
602: return string2str(type, elem->beg, elem->end);
603: }
604:
605: return NULL; /* Unsupported. */
606: }
607:
608: /*
609: * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at
610: * `buf'. Return the total string length, even if larger than `buflen'.
611: */
612: static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn)
613: {
614: curl_asn1Element rdn;
615: curl_asn1Element atv;
616: curl_asn1Element oid;
617: curl_asn1Element value;
618: size_t l = 0;
619: const char *p1;
620: const char *p2;
621: const char *p3;
622: const char *str;
623:
624: for(p1 = dn->beg; p1 < dn->end;) {
625: p1 = getASN1Element(&rdn, p1, dn->end);
626: if(!p1)
627: return -1;
628: for(p2 = rdn.beg; p2 < rdn.end;) {
629: p2 = getASN1Element(&atv, p2, rdn.end);
630: if(!p2)
631: return -1;
632: p3 = getASN1Element(&oid, atv.beg, atv.end);
633: if(!p3)
634: return -1;
635: if(!getASN1Element(&value, p3, atv.end))
636: return -1;
637: str = ASN1tostr(&oid, 0);
638: if(!str)
639: return -1;
640:
641: /* Encode delimiter.
642: If attribute has a short uppercase name, delimiter is ", ". */
643: if(l) {
644: for(p3 = str; isupper(*p3); p3++)
645: ;
646: for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
647: if(l < buflen)
648: buf[l] = *p3;
649: l++;
650: }
651: }
652:
653: /* Encode attribute name. */
654: for(p3 = str; *p3; p3++) {
655: if(l < buflen)
656: buf[l] = *p3;
657: l++;
658: }
659: free((char *) str);
660:
661: /* Generate equal sign. */
662: if(l < buflen)
663: buf[l] = '=';
664: l++;
665:
666: /* Generate value. */
667: str = ASN1tostr(&value, 0);
668: if(!str)
669: return -1;
670: for(p3 = str; *p3; p3++) {
671: if(l < buflen)
672: buf[l] = *p3;
673: l++;
674: }
675: free((char *) str);
676: }
677: }
678:
679: return l;
680: }
681:
682: /*
683: * Convert an ASN.1 distinguished name into a printable string.
684: * Return the dynamically allocated string, or NULL if an error occurs.
685: */
686: static const char *DNtostr(curl_asn1Element *dn)
687: {
688: char *buf = NULL;
689: ssize_t buflen = encodeDN(NULL, 0, dn);
690:
691: if(buflen >= 0) {
692: buf = malloc(buflen + 1);
693: if(buf) {
694: encodeDN(buf, buflen + 1, dn);
695: buf[buflen] = '\0';
696: }
697: }
698: return buf;
699: }
700:
701: /*
702: * ASN.1 parse an X509 certificate into structure subfields.
703: * Syntax is assumed to have already been checked by the SSL backend.
704: * See RFC 5280.
705: */
706: int Curl_parseX509(curl_X509certificate *cert,
707: const char *beg, const char *end)
708: {
709: curl_asn1Element elem;
710: curl_asn1Element tbsCertificate;
711: const char *ccp;
712: static const char defaultVersion = 0; /* v1. */
713:
714: cert->certificate.header = NULL;
715: cert->certificate.beg = beg;
716: cert->certificate.end = end;
717:
718: /* Get the sequence content. */
719: if(!getASN1Element(&elem, beg, end))
720: return -1; /* Invalid bounds/size. */
721: beg = elem.beg;
722: end = elem.end;
723:
724: /* Get tbsCertificate. */
725: beg = getASN1Element(&tbsCertificate, beg, end);
726: if(!beg)
727: return -1;
728: /* Skip the signatureAlgorithm. */
729: beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
730: if(!beg)
731: return -1;
732: /* Get the signatureValue. */
733: if(!getASN1Element(&cert->signature, beg, end))
734: return -1;
735:
736: /* Parse TBSCertificate. */
737: beg = tbsCertificate.beg;
738: end = tbsCertificate.end;
739: /* Get optional version, get serialNumber. */
740: cert->version.header = NULL;
741: cert->version.beg = &defaultVersion;
742: cert->version.end = &defaultVersion + sizeof(defaultVersion);
743: beg = getASN1Element(&elem, beg, end);
744: if(!beg)
745: return -1;
746: if(elem.tag == 0) {
747: if(!getASN1Element(&cert->version, elem.beg, elem.end))
748: return -1;
749: beg = getASN1Element(&elem, beg, end);
750: if(!beg)
751: return -1;
752: }
753: cert->serialNumber = elem;
754: /* Get signature algorithm. */
755: beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
756: /* Get issuer. */
757: beg = getASN1Element(&cert->issuer, beg, end);
758: if(!beg)
759: return -1;
760: /* Get notBefore and notAfter. */
761: beg = getASN1Element(&elem, beg, end);
762: if(!beg)
763: return -1;
764: ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end);
765: if(!ccp)
766: return -1;
767: if(!getASN1Element(&cert->notAfter, ccp, elem.end))
768: return -1;
769: /* Get subject. */
770: beg = getASN1Element(&cert->subject, beg, end);
771: if(!beg)
772: return -1;
773: /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
774: beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
775: if(!beg)
776: return -1;
777: ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm,
778: cert->subjectPublicKeyInfo.beg,
779: cert->subjectPublicKeyInfo.end);
780: if(!ccp)
781: return -1;
782: if(!getASN1Element(&cert->subjectPublicKey, ccp,
783: cert->subjectPublicKeyInfo.end))
784: return -1;
785: /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
786: cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
787: cert->extensions.tag = elem.tag = 0;
788: cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
789: cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
790: cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
791: cert->extensions.header = NULL;
792: cert->extensions.beg = cert->extensions.end = "";
793: if(beg < end) {
794: beg = getASN1Element(&elem, beg, end);
795: if(!beg)
796: return -1;
797: }
798: if(elem.tag == 1) {
799: cert->issuerUniqueID = elem;
800: if(beg < end) {
801: beg = getASN1Element(&elem, beg, end);
802: if(!beg)
803: return -1;
804: }
805: }
806: if(elem.tag == 2) {
807: cert->subjectUniqueID = elem;
808: if(beg < end) {
809: beg = getASN1Element(&elem, beg, end);
810: if(!beg)
811: return -1;
812: }
813: }
814: if(elem.tag == 3)
815: if(!getASN1Element(&cert->extensions, elem.beg, elem.end))
816: return -1;
817: return 0;
818: }
819:
820:
821: /*
822: * Copy at most 64-characters, terminate with a newline and returns the
823: * effective number of stored characters.
824: */
825: static size_t copySubstring(char *to, const char *from)
826: {
827: size_t i;
828: for(i = 0; i < 64; i++) {
829: to[i] = *from;
830: if(!*from++)
831: break;
832: }
833:
834: to[i++] = '\n';
835: return i;
836: }
837:
838: static const char *dumpAlgo(curl_asn1Element *param,
839: const char *beg, const char *end)
840: {
841: curl_asn1Element oid;
842:
843: /* Get algorithm parameters and return algorithm name. */
844:
845: beg = getASN1Element(&oid, beg, end);
846: if(!beg)
847: return NULL;
848: param->header = NULL;
849: param->tag = 0;
850: param->beg = param->end = end;
851: if(beg < end)
852: if(!getASN1Element(param, beg, end))
853: return NULL;
854: return OID2str(oid.beg, oid.end, TRUE);
855: }
856:
857: static void do_pubkey_field(struct Curl_easy *data, int certnum,
858: const char *label, curl_asn1Element *elem)
859: {
860: const char *output;
861:
862: /* Generate a certificate information record for the public key. */
863:
864: output = ASN1tostr(elem, 0);
865: if(output) {
866: if(data->set.ssl.certinfo)
867: Curl_ssl_push_certinfo(data, certnum, label, output);
868: if(!certnum)
869: infof(data, " %s: %s\n", label, output);
870: free((char *) output);
871: }
872: }
873:
874: static void do_pubkey(struct Curl_easy *data, int certnum,
875: const char *algo, curl_asn1Element *param,
876: curl_asn1Element *pubkey)
877: {
878: curl_asn1Element elem;
879: curl_asn1Element pk;
880: const char *p;
881:
882: /* Generate all information records for the public key. */
883:
884: /* Get the public key (single element). */
885: if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
886: return;
887:
888: if(strcasecompare(algo, "rsaEncryption")) {
889: const char *q;
890: unsigned long len;
891:
892: p = getASN1Element(&elem, pk.beg, pk.end);
893: if(!p)
894: return;
895:
896: /* Compute key length. */
897: for(q = elem.beg; !*q && q < elem.end; q++)
898: ;
899: len = (unsigned long)((elem.end - q) * 8);
900: if(len) {
901: unsigned int i;
902: for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
903: len--;
904: }
905: if(len > 32)
906: elem.beg = q; /* Strip leading zero bytes. */
907: if(!certnum)
908: infof(data, " RSA Public Key (%lu bits)\n", len);
909: if(data->set.ssl.certinfo) {
910: q = curl_maprintf("%lu", len);
911: if(q) {
912: Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
913: free((char *) q);
914: }
915: }
916: /* Generate coefficients. */
917: do_pubkey_field(data, certnum, "rsa(n)", &elem);
918: if(!getASN1Element(&elem, p, pk.end))
919: return;
920: do_pubkey_field(data, certnum, "rsa(e)", &elem);
921: }
922: else if(strcasecompare(algo, "dsa")) {
923: p = getASN1Element(&elem, param->beg, param->end);
924: if(p) {
925: do_pubkey_field(data, certnum, "dsa(p)", &elem);
926: p = getASN1Element(&elem, p, param->end);
927: if(p) {
928: do_pubkey_field(data, certnum, "dsa(q)", &elem);
929: if(getASN1Element(&elem, p, param->end)) {
930: do_pubkey_field(data, certnum, "dsa(g)", &elem);
931: do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
932: }
933: }
934: }
935: }
936: else if(strcasecompare(algo, "dhpublicnumber")) {
937: p = getASN1Element(&elem, param->beg, param->end);
938: if(p) {
939: do_pubkey_field(data, certnum, "dh(p)", &elem);
940: if(getASN1Element(&elem, param->beg, param->end)) {
941: do_pubkey_field(data, certnum, "dh(g)", &elem);
942: do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
943: }
944: }
945: }
946: }
947:
948: CURLcode Curl_extract_certinfo(struct connectdata *conn,
949: int certnum,
950: const char *beg,
951: const char *end)
952: {
953: curl_X509certificate cert;
954: struct Curl_easy *data = conn->data;
955: curl_asn1Element param;
956: const char *ccp;
957: char *cp1;
958: size_t cl1;
959: char *cp2;
960: CURLcode result;
961: unsigned long version;
962: size_t i;
963: size_t j;
964:
965: if(!data->set.ssl.certinfo)
966: if(certnum)
967: return CURLE_OK;
968:
969: /* Prepare the certificate information for curl_easy_getinfo(). */
970:
971: /* Extract the certificate ASN.1 elements. */
972: if(Curl_parseX509(&cert, beg, end))
973: return CURLE_PEER_FAILED_VERIFICATION;
974:
975: /* Subject. */
976: ccp = DNtostr(&cert.subject);
977: if(!ccp)
978: return CURLE_OUT_OF_MEMORY;
979: if(data->set.ssl.certinfo)
980: Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
981: if(!certnum)
982: infof(data, "%2d Subject: %s\n", certnum, ccp);
983: free((char *) ccp);
984:
985: /* Issuer. */
986: ccp = DNtostr(&cert.issuer);
987: if(!ccp)
988: return CURLE_OUT_OF_MEMORY;
989: if(data->set.ssl.certinfo)
990: Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
991: if(!certnum)
992: infof(data, " Issuer: %s\n", ccp);
993: free((char *) ccp);
994:
995: /* Version (always fits in less than 32 bits). */
996: version = 0;
997: for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
998: version = (version << 8) | *(const unsigned char *) ccp;
999: if(data->set.ssl.certinfo) {
1000: ccp = curl_maprintf("%lx", version);
1001: if(!ccp)
1002: return CURLE_OUT_OF_MEMORY;
1003: Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
1004: free((char *) ccp);
1005: }
1006: if(!certnum)
1007: infof(data, " Version: %lu (0x%lx)\n", version + 1, version);
1008:
1009: /* Serial number. */
1010: ccp = ASN1tostr(&cert.serialNumber, 0);
1011: if(!ccp)
1012: return CURLE_OUT_OF_MEMORY;
1013: if(data->set.ssl.certinfo)
1014: Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
1015: if(!certnum)
1016: infof(data, " Serial Number: %s\n", ccp);
1017: free((char *) ccp);
1018:
1019: /* Signature algorithm .*/
1020: ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg,
1021: cert.signatureAlgorithm.end);
1022: if(!ccp)
1023: return CURLE_OUT_OF_MEMORY;
1024: if(data->set.ssl.certinfo)
1025: Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
1026: if(!certnum)
1027: infof(data, " Signature Algorithm: %s\n", ccp);
1028: free((char *) ccp);
1029:
1030: /* Start Date. */
1031: ccp = ASN1tostr(&cert.notBefore, 0);
1032: if(!ccp)
1033: return CURLE_OUT_OF_MEMORY;
1034: if(data->set.ssl.certinfo)
1035: Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
1036: if(!certnum)
1037: infof(data, " Start Date: %s\n", ccp);
1038: free((char *) ccp);
1039:
1040: /* Expire Date. */
1041: ccp = ASN1tostr(&cert.notAfter, 0);
1042: if(!ccp)
1043: return CURLE_OUT_OF_MEMORY;
1044: if(data->set.ssl.certinfo)
1045: Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
1046: if(!certnum)
1047: infof(data, " Expire Date: %s\n", ccp);
1048: free((char *) ccp);
1049:
1050: /* Public Key Algorithm. */
1051: ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg,
1052: cert.subjectPublicKeyAlgorithm.end);
1053: if(!ccp)
1054: return CURLE_OUT_OF_MEMORY;
1055: if(data->set.ssl.certinfo)
1056: Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
1057: if(!certnum)
1058: infof(data, " Public Key Algorithm: %s\n", ccp);
1059: do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey);
1060: free((char *) ccp);
1061:
1062: /* Signature. */
1063: ccp = ASN1tostr(&cert.signature, 0);
1064: if(!ccp)
1065: return CURLE_OUT_OF_MEMORY;
1066: if(data->set.ssl.certinfo)
1067: Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
1068: if(!certnum)
1069: infof(data, " Signature: %s\n", ccp);
1070: free((char *) ccp);
1071:
1072: /* Generate PEM certificate. */
1073: result = Curl_base64_encode(data, cert.certificate.beg,
1074: cert.certificate.end - cert.certificate.beg,
1075: &cp1, &cl1);
1076: if(result)
1077: return result;
1078: /* Compute the number of characters in final certificate string. Format is:
1079: -----BEGIN CERTIFICATE-----\n
1080: <max 64 base64 characters>\n
1081: .
1082: .
1083: .
1084: -----END CERTIFICATE-----\n
1085: */
1086: i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
1087: cp2 = malloc(i + 1);
1088: if(!cp2) {
1089: free(cp1);
1090: return CURLE_OUT_OF_MEMORY;
1091: }
1092: /* Build the certificate string. */
1093: i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
1094: for(j = 0; j < cl1; j += 64)
1095: i += copySubstring(cp2 + i, cp1 + j);
1096: i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
1097: cp2[i] = '\0';
1098: free(cp1);
1099: if(data->set.ssl.certinfo)
1100: Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
1101: if(!certnum)
1102: infof(data, "%s\n", cp2);
1103: free(cp2);
1104: return CURLE_OK;
1105: }
1106:
1107: #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */
1108:
1109: #if defined(USE_GSKIT)
1110:
1111: static const char *checkOID(const char *beg, const char *end,
1112: const char *oid)
1113: {
1114: curl_asn1Element e;
1115: const char *ccp;
1116: const char *p;
1117: bool matched;
1118:
1119: /* Check if first ASN.1 element at `beg' is the given OID.
1120: Return a pointer in the source after the OID if found, else NULL. */
1121:
1122: ccp = getASN1Element(&e, beg, end);
1123: if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
1124: return NULL;
1125:
1126: p = OID2str(e.beg, e.end, FALSE);
1127: if(!p)
1128: return NULL;
1129:
1130: matched = !strcmp(p, oid);
1131: free((char *) p);
1132: return matched? ccp: NULL;
1133: }
1134:
1135: CURLcode Curl_verifyhost(struct connectdata *conn,
1136: const char *beg, const char *end)
1137: {
1138: struct Curl_easy *data = conn->data;
1139: curl_X509certificate cert;
1140: curl_asn1Element dn;
1141: curl_asn1Element elem;
1142: curl_asn1Element ext;
1143: curl_asn1Element name;
1144: const char *p;
1145: const char *q;
1146: char *dnsname;
1147: int matched = -1;
1148: size_t addrlen = (size_t) -1;
1149: ssize_t len;
1150: const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
1151: conn->host.name;
1152: const char * const dispname = SSL_IS_PROXY()?
1153: conn->http_proxy.host.dispname:
1154: conn->host.dispname;
1155: #ifdef ENABLE_IPV6
1156: struct in6_addr addr;
1157: #else
1158: struct in_addr addr;
1159: #endif
1160:
1161: /* Verify that connection server matches info in X509 certificate at
1162: `beg'..`end'. */
1163:
1164: if(!SSL_CONN_CONFIG(verifyhost))
1165: return CURLE_OK;
1166:
1167: if(Curl_parseX509(&cert, beg, end))
1168: return CURLE_PEER_FAILED_VERIFICATION;
1169:
1170: /* Get the server IP address. */
1171: #ifdef ENABLE_IPV6
1172: if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
1173: addrlen = sizeof(struct in6_addr);
1174: else
1175: #endif
1176: if(Curl_inet_pton(AF_INET, hostname, &addr))
1177: addrlen = sizeof(struct in_addr);
1178:
1179: /* Process extensions. */
1180: for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
1181: p = getASN1Element(&ext, p, cert.extensions.end);
1182: if(!p)
1183: return CURLE_PEER_FAILED_VERIFICATION;
1184:
1185: /* Check if extension is a subjectAlternativeName. */
1186: ext.beg = checkOID(ext.beg, ext.end, sanOID);
1187: if(ext.beg) {
1188: ext.beg = getASN1Element(&elem, ext.beg, ext.end);
1189: if(!ext.beg)
1190: return CURLE_PEER_FAILED_VERIFICATION;
1191: /* Skip critical if present. */
1192: if(elem.tag == CURL_ASN1_BOOLEAN) {
1193: ext.beg = getASN1Element(&elem, ext.beg, ext.end);
1194: if(!ext.beg)
1195: return CURLE_PEER_FAILED_VERIFICATION;
1196: }
1197: /* Parse the octet string contents: is a single sequence. */
1198: if(!getASN1Element(&elem, elem.beg, elem.end))
1199: return CURLE_PEER_FAILED_VERIFICATION;
1200: /* Check all GeneralNames. */
1201: for(q = elem.beg; matched != 1 && q < elem.end;) {
1202: q = getASN1Element(&name, q, elem.end);
1203: if(!q)
1204: break;
1205: switch(name.tag) {
1206: case 2: /* DNS name. */
1207: len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
1208: name.beg, name.end);
1209: if(len > 0 && (size_t)len == strlen(dnsname))
1210: matched = Curl_cert_hostcheck(dnsname, hostname);
1211: else
1212: matched = 0;
1213: free(dnsname);
1214: break;
1215:
1216: case 7: /* IP address. */
1217: matched = (size_t) (name.end - name.beg) == addrlen &&
1218: !memcmp(&addr, name.beg, addrlen);
1219: break;
1220: }
1221: }
1222: }
1223: }
1224:
1225: switch(matched) {
1226: case 1:
1227: /* an alternative name matched the server hostname */
1228: infof(data, "\t subjectAltName: %s matched\n", dispname);
1229: return CURLE_OK;
1230: case 0:
1231: /* an alternative name field existed, but didn't match and then
1232: we MUST fail */
1233: infof(data, "\t subjectAltName does not match %s\n", dispname);
1234: return CURLE_PEER_FAILED_VERIFICATION;
1235: }
1236:
1237: /* Process subject. */
1238: name.header = NULL;
1239: name.beg = name.end = "";
1240: q = cert.subject.beg;
1241: /* we have to look to the last occurrence of a commonName in the
1242: distinguished one to get the most significant one. */
1243: while(q < cert.subject.end) {
1244: q = getASN1Element(&dn, q, cert.subject.end);
1245: if(!q)
1246: break;
1247: for(p = dn.beg; p < dn.end;) {
1248: p = getASN1Element(&elem, p, dn.end);
1249: if(!p)
1250: return CURLE_PEER_FAILED_VERIFICATION;
1251: /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
1252: elem.beg = checkOID(elem.beg, elem.end, cnOID);
1253: if(elem.beg)
1254: name = elem; /* Latch CN. */
1255: }
1256: }
1257:
1258: /* Check the CN if found. */
1259: if(!getASN1Element(&elem, name.beg, name.end))
1260: failf(data, "SSL: unable to obtain common name from peer certificate");
1261: else {
1262: len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
1263: if(len < 0) {
1264: free(dnsname);
1265: return CURLE_OUT_OF_MEMORY;
1266: }
1267: if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
1268: failf(data, "SSL: illegal cert name field");
1269: else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
1270: infof(data, "\t common name: %s (matched)\n", dnsname);
1271: free(dnsname);
1272: return CURLE_OK;
1273: }
1274: else
1275: failf(data, "SSL: certificate subject name '%s' does not match "
1276: "target host name '%s'", dnsname, dispname);
1277: free(dnsname);
1278: }
1279:
1280: return CURLE_PEER_FAILED_VERIFICATION;
1281: }
1282:
1283: #endif /* USE_GSKIT */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>