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