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