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