• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_CYASSL) || 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 
getASN1Element(curl_asn1Element * elem,const char * beg,const char * end)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  */
searchOID(const char * oid)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 
bool2str(const char * beg,const char * end)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  */
octet2str(const char * beg,const char * end)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 
bit2str(const char * beg,const char * end)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  */
int2str(const char * beg,const char * end)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
utf8asn1str(char ** to,int type,const char * from,const char * end)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   int charsize;
270   unsigned int wc;
271   char *buf;
272 
273   *to = NULL;
274   switch(type) {
275   case CURL_ASN1_BMP_STRING:
276     size = 2;
277     break;
278   case CURL_ASN1_UNIVERSAL_STRING:
279     size = 4;
280     break;
281   case CURL_ASN1_NUMERIC_STRING:
282   case CURL_ASN1_PRINTABLE_STRING:
283   case CURL_ASN1_TELETEX_STRING:
284   case CURL_ASN1_IA5_STRING:
285   case CURL_ASN1_VISIBLE_STRING:
286   case CURL_ASN1_UTF8_STRING:
287     break;
288   default:
289     return -1;  /* Conversion not supported. */
290   }
291 
292   if(inlength % size)
293     return -1;  /* Length inconsistent with character size. */
294   if(inlength / size > (SIZE_T_MAX - 1) / 4)
295     return -1;  /* Too big. */
296   buf = malloc(4 * (inlength / size) + 1);
297   if(!buf)
298     return -1;  /* Not enough memory. */
299 
300   if(type == CURL_ASN1_UTF8_STRING) {
301     /* Just copy. */
302     outlength = inlength;
303     if(outlength)
304       memcpy(buf, from, outlength);
305   }
306   else {
307     for(outlength = 0; from < end;) {
308       wc = 0;
309       switch(size) {
310       case 4:
311         wc = (wc << 8) | *(const unsigned char *) from++;
312         wc = (wc << 8) | *(const unsigned char *) from++;
313         /* FALLTHROUGH */
314       case 2:
315         wc = (wc << 8) | *(const unsigned char *) from++;
316         /* FALLTHROUGH */
317       default: /* case 1: */
318         wc = (wc << 8) | *(const unsigned char *) from++;
319       }
320       charsize = 1;
321       if(wc >= 0x00000080) {
322         if(wc >= 0x00000800) {
323           if(wc >= 0x00010000) {
324             if(wc >= 0x00200000) {
325               free(buf);
326               return -1;        /* Invalid char. size for target encoding. */
327             }
328             buf[outlength + 3] = (char) (0x80 | (wc & 0x3F));
329             wc = (wc >> 6) | 0x00010000;
330             charsize++;
331           }
332           buf[outlength + 2] = (char) (0x80 | (wc & 0x3F));
333           wc = (wc >> 6) | 0x00000800;
334           charsize++;
335         }
336         buf[outlength + 1] = (char) (0x80 | (wc & 0x3F));
337         wc = (wc >> 6) | 0x000000C0;
338         charsize++;
339       }
340       buf[outlength] = (char) wc;
341       outlength += charsize;
342     }
343   }
344   buf[outlength] = '\0';
345   *to = buf;
346   return outlength;
347 }
348 
349 /*
350  * Convert an ASN.1 String into its UTF-8 string representation.
351  * Return the dynamically allocated string, or NULL if an error occurs.
352  */
string2str(int type,const char * beg,const char * end)353 static const char *string2str(int type, const char *beg, const char *end)
354 {
355   char *buf;
356   if(utf8asn1str(&buf, type, beg, end) < 0)
357     return NULL;
358   return buf;
359 }
360 
361 /*
362  * Decimal ASCII encode unsigned integer `x' into the buflen sized buffer at
363  * buf.  Return the total number of encoded digits, even if larger than
364  * `buflen'.
365  */
encodeUint(char * buf,size_t buflen,unsigned int x)366 static size_t encodeUint(char *buf, size_t buflen, unsigned int x)
367 {
368   size_t i = 0;
369   unsigned int y = x / 10;
370 
371   if(y) {
372     i = encodeUint(buf, buflen, y);
373     x -= y * 10;
374   }
375   if(i < buflen)
376     buf[i] = (char) ('0' + x);
377   i++;
378   if(i < buflen)
379     buf[i] = '\0';      /* Store a terminator if possible. */
380   return i;
381 }
382 
383 /*
384  * Convert an ASN.1 OID into its dotted string representation.
385  * Store the result in th `n'-byte buffer at `buf'.
386  * Return the converted string length, or 0 on errors.
387  */
encodeOID(char * buf,size_t buflen,const char * beg,const char * end)388 static size_t encodeOID(char *buf, size_t buflen,
389                         const char *beg, const char *end)
390 {
391   size_t i;
392   unsigned int x;
393   unsigned int y;
394 
395   /* Process the first two numbers. */
396   y = *(const unsigned char *) beg++;
397   x = y / 40;
398   y -= x * 40;
399   i = encodeUint(buf, buflen, x);
400   if(i < buflen)
401     buf[i] = '.';
402   i++;
403   if(i >= buflen)
404     i += encodeUint(NULL, 0, y);
405   else
406     i += encodeUint(buf + i, buflen - i, y);
407 
408   /* Process the trailing numbers. */
409   while(beg < end) {
410     if(i < buflen)
411       buf[i] = '.';
412     i++;
413     x = 0;
414     do {
415       if(x & 0xFF000000)
416         return 0;
417       y = *(const unsigned char *) beg++;
418       x = (x << 7) | (y & 0x7F);
419     } while(y & 0x80);
420     if(i >= buflen)
421       i += encodeUint(NULL, 0, x);
422     else
423       i += encodeUint(buf + i, buflen - i, x);
424   }
425   if(i < buflen)
426     buf[i] = '\0';
427   return i;
428 }
429 
430 /*
431  * Convert an ASN.1 OID into its dotted or symbolic string representation.
432  * Return the dynamically allocated string, or NULL if an error occurs.
433  */
434 
OID2str(const char * beg,const char * end,bool symbolic)435 static const char *OID2str(const char *beg, const char *end, bool symbolic)
436 {
437   char *buf = NULL;
438   if(beg < end) {
439     size_t buflen = encodeOID(NULL, 0, beg, end);
440     if(buflen) {
441       buf = malloc(buflen + 1); /* one extra for the zero byte */
442       if(buf) {
443         encodeOID(buf, buflen, beg, end);
444         buf[buflen] = '\0';
445 
446         if(symbolic) {
447           const curl_OID *op = searchOID(buf);
448           if(op) {
449             free(buf);
450             buf = strdup(op->textoid);
451           }
452         }
453       }
454     }
455   }
456   return buf;
457 }
458 
GTime2str(const char * beg,const char * end)459 static const char *GTime2str(const char *beg, const char *end)
460 {
461   const char *tzp;
462   const char *fracp;
463   char sec1, sec2;
464   size_t fracl;
465   size_t tzl;
466   const char *sep = "";
467 
468   /* Convert an ASN.1 Generalized time to a printable string.
469      Return the dynamically allocated string, or NULL if an error occurs. */
470 
471   for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
472     ;
473 
474   /* Get seconds digits. */
475   sec1 = '0';
476   switch(fracp - beg - 12) {
477   case 0:
478     sec2 = '0';
479     break;
480   case 2:
481     sec1 = fracp[-2];
482     /* FALLTHROUGH */
483   case 1:
484     sec2 = fracp[-1];
485     break;
486   default:
487     return NULL;
488   }
489 
490   /* Scan for timezone, measure fractional seconds. */
491   tzp = fracp;
492   fracl = 0;
493   if(fracp < end && (*fracp == '.' || *fracp == ',')) {
494     fracp++;
495     do
496       tzp++;
497     while(tzp < end && *tzp >= '0' && *tzp <= '9');
498     /* Strip leading zeroes in fractional seconds. */
499     for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
500       ;
501   }
502 
503   /* Process timezone. */
504   if(tzp >= end)
505     ;           /* Nothing to do. */
506   else if(*tzp == 'Z') {
507     tzp = " GMT";
508     end = tzp + 4;
509   }
510   else {
511     sep = " ";
512     tzp++;
513   }
514 
515   tzl = end - tzp;
516   return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
517                        beg, beg + 4, beg + 6,
518                        beg + 8, beg + 10, sec1, sec2,
519                        fracl? ".": "", fracl, fracp,
520                        sep, tzl, tzp);
521 }
522 
523 /*
524  *  Convert an ASN.1 UTC time to a printable string.
525  * Return the dynamically allocated string, or NULL if an error occurs.
526  */
UTime2str(const char * beg,const char * end)527 static const char *UTime2str(const char *beg, const char *end)
528 {
529   const char *tzp;
530   size_t tzl;
531   const char *sec;
532 
533   for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
534     ;
535   /* Get the seconds. */
536   sec = beg + 10;
537   switch(tzp - sec) {
538   case 0:
539     sec = "00";
540   case 2:
541     break;
542   default:
543     return NULL;
544   }
545 
546   /* Process timezone. */
547   if(tzp >= end)
548     return NULL;
549   if(*tzp == 'Z') {
550     tzp = "GMT";
551     end = tzp + 3;
552   }
553   else
554     tzp++;
555 
556   tzl = end - tzp;
557   return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
558                        20 - (*beg >= '5'), beg, beg + 2, beg + 4,
559                        beg + 6, beg + 8, sec,
560                        tzl, tzp);
561 }
562 
563 /*
564  * Convert an ASN.1 element to a printable string.
565  * Return the dynamically allocated string, or NULL if an error occurs.
566  */
ASN1tostr(curl_asn1Element * elem,int type)567 static const char *ASN1tostr(curl_asn1Element *elem, int type)
568 {
569   if(elem->constructed)
570     return NULL; /* No conversion of structured elements. */
571 
572   if(!type)
573     type = elem->tag;   /* Type not forced: use element tag as type. */
574 
575   switch(type) {
576   case CURL_ASN1_BOOLEAN:
577     return bool2str(elem->beg, elem->end);
578   case CURL_ASN1_INTEGER:
579   case CURL_ASN1_ENUMERATED:
580     return int2str(elem->beg, elem->end);
581   case CURL_ASN1_BIT_STRING:
582     return bit2str(elem->beg, elem->end);
583   case CURL_ASN1_OCTET_STRING:
584     return octet2str(elem->beg, elem->end);
585   case CURL_ASN1_NULL:
586     return strdup("");
587   case CURL_ASN1_OBJECT_IDENTIFIER:
588     return OID2str(elem->beg, elem->end, TRUE);
589   case CURL_ASN1_UTC_TIME:
590     return UTime2str(elem->beg, elem->end);
591   case CURL_ASN1_GENERALIZED_TIME:
592     return GTime2str(elem->beg, elem->end);
593   case CURL_ASN1_UTF8_STRING:
594   case CURL_ASN1_NUMERIC_STRING:
595   case CURL_ASN1_PRINTABLE_STRING:
596   case CURL_ASN1_TELETEX_STRING:
597   case CURL_ASN1_IA5_STRING:
598   case CURL_ASN1_VISIBLE_STRING:
599   case CURL_ASN1_UNIVERSAL_STRING:
600   case CURL_ASN1_BMP_STRING:
601     return string2str(type, elem->beg, elem->end);
602   }
603 
604   return NULL;   /* Unsupported. */
605 }
606 
607 /*
608  * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at
609  * `buf'.  Return the total string length, even if larger than `buflen'.
610  */
encodeDN(char * buf,size_t buflen,curl_asn1Element * dn)611 static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn)
612 {
613   curl_asn1Element rdn;
614   curl_asn1Element atv;
615   curl_asn1Element oid;
616   curl_asn1Element value;
617   size_t l = 0;
618   const char *p1;
619   const char *p2;
620   const char *p3;
621   const char *str;
622 
623   for(p1 = dn->beg; p1 < dn->end;) {
624     p1 = getASN1Element(&rdn, p1, dn->end);
625     if(!p1)
626       return -1;
627     for(p2 = rdn.beg; p2 < rdn.end;) {
628       p2 = getASN1Element(&atv, p2, rdn.end);
629       if(!p2)
630         return -1;
631       p3 = getASN1Element(&oid, atv.beg, atv.end);
632       if(!p3)
633         return -1;
634       if(!getASN1Element(&value, p3, atv.end))
635         return -1;
636       str = ASN1tostr(&oid, 0);
637       if(!str)
638         return -1;
639 
640       /* Encode delimiter.
641          If attribute has a short uppercase name, delimiter is ", ". */
642       if(l) {
643         for(p3 = str; isupper(*p3); p3++)
644           ;
645         for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
646           if(l < buflen)
647             buf[l] = *p3;
648           l++;
649         }
650       }
651 
652       /* Encode attribute name. */
653       for(p3 = str; *p3; p3++) {
654         if(l < buflen)
655           buf[l] = *p3;
656         l++;
657       }
658       free((char *) str);
659 
660       /* Generate equal sign. */
661       if(l < buflen)
662         buf[l] = '=';
663       l++;
664 
665       /* Generate value. */
666       str = ASN1tostr(&value, 0);
667       if(!str)
668         return -1;
669       for(p3 = str; *p3; p3++) {
670         if(l < buflen)
671           buf[l] = *p3;
672         l++;
673       }
674       free((char *) str);
675     }
676   }
677 
678   return l;
679 }
680 
681 /*
682  * Convert an ASN.1 distinguished name into a printable string.
683  * Return the dynamically allocated string, or NULL if an error occurs.
684  */
DNtostr(curl_asn1Element * dn)685 static const char *DNtostr(curl_asn1Element *dn)
686 {
687   char *buf = NULL;
688   ssize_t buflen = encodeDN(NULL, 0, dn);
689 
690   if(buflen >= 0) {
691     buf = malloc(buflen + 1);
692     if(buf) {
693       encodeDN(buf, buflen + 1, dn);
694       buf[buflen] = '\0';
695     }
696   }
697   return buf;
698 }
699 
700 /*
701  * ASN.1 parse an X509 certificate into structure subfields.
702  * Syntax is assumed to have already been checked by the SSL backend.
703  * See RFC 5280.
704  */
Curl_parseX509(curl_X509certificate * cert,const char * beg,const char * end)705 int Curl_parseX509(curl_X509certificate *cert,
706                    const char *beg, const char *end)
707 {
708   curl_asn1Element elem;
709   curl_asn1Element tbsCertificate;
710   const char *ccp;
711   static const char defaultVersion = 0;  /* v1. */
712 
713   cert->certificate.header = NULL;
714   cert->certificate.beg = beg;
715   cert->certificate.end = end;
716 
717   /* Get the sequence content. */
718   if(!getASN1Element(&elem, beg, end))
719     return -1;  /* Invalid bounds/size. */
720   beg = elem.beg;
721   end = elem.end;
722 
723   /* Get tbsCertificate. */
724   beg = getASN1Element(&tbsCertificate, beg, end);
725   if(!beg)
726     return -1;
727   /* Skip the signatureAlgorithm. */
728   beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
729   if(!beg)
730     return -1;
731   /* Get the signatureValue. */
732   if(!getASN1Element(&cert->signature, beg, end))
733     return -1;
734 
735   /* Parse TBSCertificate. */
736   beg = tbsCertificate.beg;
737   end = tbsCertificate.end;
738   /* Get optional version, get serialNumber. */
739   cert->version.header = NULL;
740   cert->version.beg = &defaultVersion;
741   cert->version.end = &defaultVersion + sizeof(defaultVersion);
742   beg = getASN1Element(&elem, beg, end);
743   if(!beg)
744     return -1;
745   if(elem.tag == 0) {
746     if(!getASN1Element(&cert->version, elem.beg, elem.end))
747       return -1;
748     beg = getASN1Element(&elem, beg, end);
749     if(!beg)
750       return -1;
751   }
752   cert->serialNumber = elem;
753   /* Get signature algorithm. */
754   beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
755   /* Get issuer. */
756   beg = getASN1Element(&cert->issuer, beg, end);
757   if(!beg)
758     return -1;
759   /* Get notBefore and notAfter. */
760   beg = getASN1Element(&elem, beg, end);
761   if(!beg)
762     return -1;
763   ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end);
764   if(!ccp)
765     return -1;
766   if(!getASN1Element(&cert->notAfter, ccp, elem.end))
767     return -1;
768   /* Get subject. */
769   beg = getASN1Element(&cert->subject, beg, end);
770   if(!beg)
771     return -1;
772   /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
773   beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
774   if(!beg)
775     return -1;
776   ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm,
777                        cert->subjectPublicKeyInfo.beg,
778                        cert->subjectPublicKeyInfo.end);
779   if(!ccp)
780     return -1;
781   if(!getASN1Element(&cert->subjectPublicKey, ccp,
782                      cert->subjectPublicKeyInfo.end))
783     return -1;
784   /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
785   cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
786   cert->extensions.tag = elem.tag = 0;
787   cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
788   cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
789   cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
790   cert->extensions.header = NULL;
791   cert->extensions.beg = cert->extensions.end = "";
792   if(beg < end) {
793     beg = getASN1Element(&elem, beg, end);
794     if(!beg)
795       return -1;
796   }
797   if(elem.tag == 1) {
798     cert->issuerUniqueID = elem;
799     if(beg < end) {
800       beg = getASN1Element(&elem, beg, end);
801       if(!beg)
802         return -1;
803     }
804   }
805   if(elem.tag == 2) {
806     cert->subjectUniqueID = elem;
807     if(beg < end) {
808       beg = getASN1Element(&elem, beg, end);
809       if(!beg)
810         return -1;
811     }
812   }
813   if(elem.tag == 3)
814     if(!getASN1Element(&cert->extensions, elem.beg, elem.end))
815       return -1;
816   return 0;
817 }
818 
819 
820 /*
821  * Copy at most 64-characters, terminate with a newline and returns the
822  * effective number of stored characters.
823  */
copySubstring(char * to,const char * from)824 static size_t copySubstring(char *to, const char *from)
825 {
826   size_t i;
827   for(i = 0; i < 64; i++) {
828     to[i] = *from;
829     if(!*from++)
830       break;
831   }
832 
833   to[i++] = '\n';
834   return i;
835 }
836 
dumpAlgo(curl_asn1Element * param,const char * beg,const char * end)837 static const char *dumpAlgo(curl_asn1Element *param,
838                             const char *beg, const char *end)
839 {
840   curl_asn1Element oid;
841 
842   /* Get algorithm parameters and return algorithm name. */
843 
844   beg = getASN1Element(&oid, beg, end);
845   if(!beg)
846     return NULL;
847   param->header = NULL;
848   param->tag = 0;
849   param->beg = param->end = end;
850   if(beg < end)
851     if(!getASN1Element(param, beg, end))
852       return NULL;
853   return OID2str(oid.beg, oid.end, TRUE);
854 }
855 
do_pubkey_field(struct Curl_easy * data,int certnum,const char * label,curl_asn1Element * elem)856 static void do_pubkey_field(struct Curl_easy *data, int certnum,
857                             const char *label, curl_asn1Element *elem)
858 {
859   const char *output;
860 
861   /* Generate a certificate information record for the public key. */
862 
863   output = ASN1tostr(elem, 0);
864   if(output) {
865     if(data->set.ssl.certinfo)
866       Curl_ssl_push_certinfo(data, certnum, label, output);
867     if(!certnum)
868       infof(data, "   %s: %s\n", label, output);
869     free((char *) output);
870   }
871 }
872 
do_pubkey(struct Curl_easy * data,int certnum,const char * algo,curl_asn1Element * param,curl_asn1Element * pubkey)873 static void do_pubkey(struct Curl_easy *data, int certnum,
874                       const char *algo, curl_asn1Element *param,
875                       curl_asn1Element *pubkey)
876 {
877   curl_asn1Element elem;
878   curl_asn1Element pk;
879   const char *p;
880   const char *q;
881   unsigned long len;
882   unsigned int i;
883 
884   /* Generate all information records for the public key. */
885 
886   /* Get the public key (single element). */
887   if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
888     return;
889 
890   if(strcasecompare(algo, "rsaEncryption")) {
891     p = getASN1Element(&elem, pk.beg, pk.end);
892     if(!p)
893       return;
894 
895     /* Compute key length. */
896     for(q = elem.beg; !*q && q < elem.end; q++)
897       ;
898     len = (unsigned long)((elem.end - q) * 8);
899     if(len)
900       for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
901         len--;
902     if(len > 32)
903       elem.beg = q;     /* Strip leading zero bytes. */
904     if(!certnum)
905       infof(data, "   RSA Public Key (%lu bits)\n", len);
906     if(data->set.ssl.certinfo) {
907       q = curl_maprintf("%lu", len);
908       if(q) {
909         Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
910         free((char *) q);
911       }
912     }
913     /* Generate coefficients. */
914     do_pubkey_field(data, certnum, "rsa(n)", &elem);
915     if(!getASN1Element(&elem, p, pk.end))
916       return;
917     do_pubkey_field(data, certnum, "rsa(e)", &elem);
918   }
919   else if(strcasecompare(algo, "dsa")) {
920     p = getASN1Element(&elem, param->beg, param->end);
921     if(p) {
922       do_pubkey_field(data, certnum, "dsa(p)", &elem);
923       p = getASN1Element(&elem, p, param->end);
924       if(p) {
925         do_pubkey_field(data, certnum, "dsa(q)", &elem);
926         if(getASN1Element(&elem, p, param->end)) {
927           do_pubkey_field(data, certnum, "dsa(g)", &elem);
928           do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
929         }
930       }
931     }
932   }
933   else if(strcasecompare(algo, "dhpublicnumber")) {
934     p = getASN1Element(&elem, param->beg, param->end);
935     if(p) {
936       do_pubkey_field(data, certnum, "dh(p)", &elem);
937       if(getASN1Element(&elem, param->beg, param->end)) {
938         do_pubkey_field(data, certnum, "dh(g)", &elem);
939         do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
940       }
941     }
942   }
943 }
944 
Curl_extract_certinfo(struct connectdata * conn,int certnum,const char * beg,const char * end)945 CURLcode Curl_extract_certinfo(struct connectdata *conn,
946                                int certnum,
947                                const char *beg,
948                                const char *end)
949 {
950   curl_X509certificate cert;
951   struct Curl_easy *data = conn->data;
952   curl_asn1Element param;
953   const char *ccp;
954   char *cp1;
955   size_t cl1;
956   char *cp2;
957   CURLcode result;
958   unsigned long version;
959   size_t i;
960   size_t j;
961 
962   if(!data->set.ssl.certinfo)
963     if(certnum)
964       return CURLE_OK;
965 
966   /* Prepare the certificate information for curl_easy_getinfo(). */
967 
968   /* Extract the certificate ASN.1 elements. */
969   if(Curl_parseX509(&cert, beg, end))
970     return CURLE_PEER_FAILED_VERIFICATION;
971 
972   /* Subject. */
973   ccp = DNtostr(&cert.subject);
974   if(!ccp)
975     return CURLE_OUT_OF_MEMORY;
976   if(data->set.ssl.certinfo)
977     Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
978   if(!certnum)
979     infof(data, "%2d Subject: %s\n", certnum, ccp);
980   free((char *) ccp);
981 
982   /* Issuer. */
983   ccp = DNtostr(&cert.issuer);
984   if(!ccp)
985     return CURLE_OUT_OF_MEMORY;
986   if(data->set.ssl.certinfo)
987     Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
988   if(!certnum)
989     infof(data, "   Issuer: %s\n", ccp);
990   free((char *) ccp);
991 
992   /* Version (always fits in less than 32 bits). */
993   version = 0;
994   for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
995     version = (version << 8) | *(const unsigned char *) ccp;
996   if(data->set.ssl.certinfo) {
997     ccp = curl_maprintf("%lx", version);
998     if(!ccp)
999       return CURLE_OUT_OF_MEMORY;
1000     Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
1001     free((char *) ccp);
1002   }
1003   if(!certnum)
1004     infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
1005 
1006   /* Serial number. */
1007   ccp = ASN1tostr(&cert.serialNumber, 0);
1008   if(!ccp)
1009     return CURLE_OUT_OF_MEMORY;
1010   if(data->set.ssl.certinfo)
1011     Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
1012   if(!certnum)
1013     infof(data, "   Serial Number: %s\n", ccp);
1014   free((char *) ccp);
1015 
1016   /* Signature algorithm .*/
1017   ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
1018                  cert.signatureAlgorithm.end);
1019   if(!ccp)
1020     return CURLE_OUT_OF_MEMORY;
1021   if(data->set.ssl.certinfo)
1022     Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
1023   if(!certnum)
1024     infof(data, "   Signature Algorithm: %s\n", ccp);
1025   free((char *) ccp);
1026 
1027   /* Start Date. */
1028   ccp = ASN1tostr(&cert.notBefore, 0);
1029   if(!ccp)
1030     return CURLE_OUT_OF_MEMORY;
1031   if(data->set.ssl.certinfo)
1032     Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
1033   if(!certnum)
1034     infof(data, "   Start Date: %s\n", ccp);
1035   free((char *) ccp);
1036 
1037   /* Expire Date. */
1038   ccp = ASN1tostr(&cert.notAfter, 0);
1039   if(!ccp)
1040     return CURLE_OUT_OF_MEMORY;
1041   if(data->set.ssl.certinfo)
1042     Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
1043   if(!certnum)
1044     infof(data, "   Expire Date: %s\n", ccp);
1045   free((char *) ccp);
1046 
1047   /* Public Key Algorithm. */
1048   ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
1049                  cert.subjectPublicKeyAlgorithm.end);
1050   if(!ccp)
1051     return CURLE_OUT_OF_MEMORY;
1052   if(data->set.ssl.certinfo)
1053     Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
1054   if(!certnum)
1055     infof(data, "   Public Key Algorithm: %s\n", ccp);
1056   do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
1057   free((char *) ccp);
1058 
1059 /* TODO: extensions. */
1060 
1061   /* Signature. */
1062   ccp = ASN1tostr(&cert.signature, 0);
1063   if(!ccp)
1064     return CURLE_OUT_OF_MEMORY;
1065   if(data->set.ssl.certinfo)
1066     Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
1067   if(!certnum)
1068     infof(data, "   Signature: %s\n", ccp);
1069   free((char *) ccp);
1070 
1071   /* Generate PEM certificate. */
1072   result = Curl_base64_encode(data, cert.certificate.beg,
1073                               cert.certificate.end - cert.certificate.beg,
1074                               &cp1, &cl1);
1075   if(result)
1076     return result;
1077   /* Compute the number of characters in final certificate string. Format is:
1078      -----BEGIN CERTIFICATE-----\n
1079      <max 64 base64 characters>\n
1080      .
1081      .
1082      .
1083      -----END CERTIFICATE-----\n
1084    */
1085   i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
1086   cp2 = malloc(i + 1);
1087   if(!cp2) {
1088     free(cp1);
1089     return CURLE_OUT_OF_MEMORY;
1090   }
1091   /* Build the certificate string. */
1092   i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
1093   for(j = 0; j < cl1; j += 64)
1094     i += copySubstring(cp2 + i, cp1 + j);
1095   i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
1096   cp2[i] = '\0';
1097   free(cp1);
1098   if(data->set.ssl.certinfo)
1099     Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
1100   if(!certnum)
1101     infof(data, "%s\n", cp2);
1102   free(cp2);
1103   return CURLE_OK;
1104 }
1105 
1106 #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
1107 
1108 #if defined(USE_GSKIT)
1109 
checkOID(const char * beg,const char * end,const char * oid)1110 static const char *checkOID(const char *beg, const char *end,
1111                             const char *oid)
1112 {
1113   curl_asn1Element e;
1114   const char *ccp;
1115   const char *p;
1116   bool matched;
1117 
1118   /* Check if first ASN.1 element at `beg' is the given OID.
1119      Return a pointer in the source after the OID if found, else NULL. */
1120 
1121   ccp = getASN1Element(&e, beg, end);
1122   if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
1123     return NULL;
1124 
1125   p = OID2str(e.beg, e.end, FALSE);
1126   if(!p)
1127     return NULL;
1128 
1129   matched = !strcmp(p, oid);
1130   free((char *) p);
1131   return matched? ccp: NULL;
1132 }
1133 
Curl_verifyhost(struct connectdata * conn,const char * beg,const char * end)1134 CURLcode Curl_verifyhost(struct connectdata *conn,
1135                          const char *beg, const char *end)
1136 {
1137   struct Curl_easy *data = conn->data;
1138   curl_X509certificate cert;
1139   curl_asn1Element dn;
1140   curl_asn1Element elem;
1141   curl_asn1Element ext;
1142   curl_asn1Element name;
1143   const char *p;
1144   const char *q;
1145   char *dnsname;
1146   int matched = -1;
1147   size_t addrlen = (size_t) -1;
1148   ssize_t len;
1149   const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
1150                                                 conn->host.name;
1151   const char * const dispname = SSL_IS_PROXY()?
1152                                   conn->http_proxy.host.dispname:
1153                                   conn->host.dispname;
1154 #ifdef ENABLE_IPV6
1155   struct in6_addr addr;
1156 #else
1157   struct in_addr addr;
1158 #endif
1159 
1160   /* Verify that connection server matches info in X509 certificate at
1161      `beg'..`end'. */
1162 
1163   if(!SSL_CONN_CONFIG(verifyhost))
1164     return CURLE_OK;
1165 
1166   if(Curl_parseX509(&cert, beg, end))
1167     return CURLE_PEER_FAILED_VERIFICATION;
1168 
1169   /* Get the server IP address. */
1170 #ifdef ENABLE_IPV6
1171   if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
1172     addrlen = sizeof(struct in6_addr);
1173   else
1174 #endif
1175   if(Curl_inet_pton(AF_INET, hostname, &addr))
1176     addrlen = sizeof(struct in_addr);
1177 
1178   /* Process extensions. */
1179   for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
1180     p = getASN1Element(&ext, p, cert.extensions.end);
1181     if(!p)
1182       return CURLE_PEER_FAILED_VERIFICATION;
1183 
1184     /* Check if extension is a subjectAlternativeName. */
1185     ext.beg = checkOID(ext.beg, ext.end, sanOID);
1186     if(ext.beg) {
1187       ext.beg = getASN1Element(&elem, ext.beg, ext.end);
1188       if(!ext.beg)
1189         return CURLE_PEER_FAILED_VERIFICATION;
1190       /* Skip critical if present. */
1191       if(elem.tag == CURL_ASN1_BOOLEAN) {
1192         ext.beg = getASN1Element(&elem, ext.beg, ext.end);
1193         if(!ext.beg)
1194           return CURLE_PEER_FAILED_VERIFICATION;
1195       }
1196       /* Parse the octet string contents: is a single sequence. */
1197       if(!getASN1Element(&elem, elem.beg, elem.end))
1198         return CURLE_PEER_FAILED_VERIFICATION;
1199       /* Check all GeneralNames. */
1200       for(q = elem.beg; matched != 1 && q < elem.end;) {
1201         q = getASN1Element(&name, q, elem.end);
1202         if(!q)
1203           break;
1204         switch(name.tag) {
1205         case 2: /* DNS name. */
1206           len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
1207                             name.beg, name.end);
1208           if(len > 0 && (size_t)len == strlen(dnsname))
1209             matched = Curl_cert_hostcheck(dnsname, hostname);
1210           else
1211             matched = 0;
1212           free(dnsname);
1213           break;
1214 
1215         case 7: /* IP address. */
1216           matched = (size_t) (name.end - name.beg) == addrlen &&
1217                     !memcmp(&addr, name.beg, addrlen);
1218           break;
1219         }
1220       }
1221     }
1222   }
1223 
1224   switch(matched) {
1225   case 1:
1226     /* an alternative name matched the server hostname */
1227     infof(data, "\t subjectAltName: %s matched\n", dispname);
1228     return CURLE_OK;
1229   case 0:
1230     /* an alternative name field existed, but didn't match and then
1231        we MUST fail */
1232     infof(data, "\t subjectAltName does not match %s\n", dispname);
1233     return CURLE_PEER_FAILED_VERIFICATION;
1234   }
1235 
1236   /* Process subject. */
1237   name.header = NULL;
1238   name.beg = name.end = "";
1239   q = cert.subject.beg;
1240   /* we have to look to the last occurrence of a commonName in the
1241      distinguished one to get the most significant one. */
1242   while(q < cert.subject.end) {
1243     q = getASN1Element(&dn, q, cert.subject.end);
1244     if(!q)
1245       break;
1246     for(p = dn.beg; p < dn.end;) {
1247       p = getASN1Element(&elem, p, dn.end);
1248       if(!p)
1249         return CURLE_PEER_FAILED_VERIFICATION;
1250       /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
1251       elem.beg = checkOID(elem.beg, elem.end, cnOID);
1252       if(elem.beg)
1253         name = elem;    /* Latch CN. */
1254     }
1255   }
1256 
1257   /* Check the CN if found. */
1258   if(!getASN1Element(&elem, name.beg, name.end))
1259     failf(data, "SSL: unable to obtain common name from peer certificate");
1260   else {
1261     len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
1262     if(len < 0) {
1263       free(dnsname);
1264       return CURLE_OUT_OF_MEMORY;
1265     }
1266     if(strlen(dnsname) != (size_t) len)         /* Nul byte in string ? */
1267       failf(data, "SSL: illegal cert name field");
1268     else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
1269       infof(data, "\t common name: %s (matched)\n", dnsname);
1270       free(dnsname);
1271       return CURLE_OK;
1272     }
1273     else
1274       failf(data, "SSL: certificate subject name '%s' does not match "
1275             "target host name '%s'", dnsname, dispname);
1276     free(dnsname);
1277   }
1278 
1279   return CURLE_PEER_FAILED_VERIFICATION;
1280 }
1281 
1282 #endif /* USE_GSKIT */
1283