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 
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   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  */
string2str(int type,const char * beg,const char * end)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  */
encodeUint(char * buf,size_t buflen,unsigned int x)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  */
encodeOID(char * buf,size_t buflen,const char * beg,const char * end)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 
OID2str(const char * beg,const char * end,bool symbolic)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 
GTime2str(const char * beg,const char * end)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  */
UTime2str(const char * beg,const char * end)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  */
ASN1tostr(curl_asn1Element * elem,int type)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  */
encodeDN(char * buf,size_t buflen,curl_asn1Element * dn)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  */
DNtostr(curl_asn1Element * dn)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  */
Curl_parseX509(curl_X509certificate * cert,const char * beg,const char * end)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  */
copySubstring(char * to,const char * from)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 
dumpAlgo(curl_asn1Element * param,const char * beg,const char * end)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 
do_pubkey_field(struct Curl_easy * data,int certnum,const char * label,curl_asn1Element * elem)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 
do_pubkey(struct Curl_easy * data,int certnum,const char * algo,curl_asn1Element * param,curl_asn1Element * pubkey)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 
Curl_extract_certinfo(struct connectdata * conn,int certnum,const char * beg,const char * end)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(&param, 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(&param, 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, &param, &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 
checkOID(const char * beg,const char * end,const char * oid)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 
Curl_verifyhost(struct connectdata * conn,const char * beg,const char * end)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 */
1284