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   case 1:
    470     sec2 = fracp[-1];
    471     break;
    472   default:
    473     return (const char *) NULL;
    474   }
    475 
    476   /* Scan for timezone, measure fractional seconds. */
    477   tzp = fracp;
    478   fracl = 0;
    479   if(fracp < end && (*fracp == '.' || *fracp == ',')) {
    480     fracp++;
    481     do
    482       tzp++;
    483     while(tzp < end && *tzp >= '0' && *tzp <= '9');
    484     /* Strip leading zeroes in fractional seconds. */
    485     for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
    486       ;
    487   }
    488 
    489   /* Process timezone. */
    490   if(tzp >= end)
    491     ;           /* Nothing to do. */
    492   else if(*tzp == 'Z') {
    493     tzp = " GMT";
    494     end = tzp + 4;
    495   }
    496   else {
    497     sep = " ";
    498     tzp++;
    499   }
    500 
    501   tzl = end - tzp;
    502   return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
    503                        beg, beg + 4, beg + 6,
    504                        beg + 8, beg + 10, sec1, sec2,
    505                        fracl? ".": "", fracl, fracp,
    506                        sep, tzl, tzp);
    507 }
    508 
    509 static const char *UTime2str(const char *beg, const char *end)
    510 {
    511   const char *tzp;
    512   size_t tzl;
    513   const char *sec;
    514 
    515   /* Convert an ASN.1 UTC time to a printable string.
    516      Return the dynamically allocated string, or NULL if an error occurs. */
    517 
    518   for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
    519     ;
    520   /* Get the seconds. */
    521   sec = beg + 10;
    522   switch (tzp - sec) {
    523   case 0:
    524     sec = "00";
    525   case 2:
    526     break;
    527   default:
    528     return (const char *) NULL;
    529   }
    530 
    531   /* Process timezone. */
    532   if(tzp >= end)
    533     return (const char *) NULL;
    534   if(*tzp == 'Z') {
    535     tzp = "GMT";
    536     end = tzp + 3;
    537   }
    538   else
    539     tzp++;
    540 
    541   tzl = end - tzp;
    542   return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
    543                        20 - (*beg >= '5'), beg, beg + 2, beg + 4,
    544                        beg + 6, beg + 8, sec,
    545                        tzl, tzp);
    546 }
    547 
    548 const char *Curl_ASN1tostr(curl_asn1Element *elem, int type)
    549 {
    550   /* Convert an ASN.1 element to a printable string.
    551      Return the dynamically allocated string, or NULL if an error occurs. */
    552 
    553   if(elem->constructed)
    554     return (const char *) NULL; /* No conversion of structured elements. */
    555 
    556   if(!type)
    557     type = elem->tag;   /* Type not forced: use element tag as type. */
    558 
    559   switch (type) {
    560   case CURL_ASN1_BOOLEAN:
    561     return bool2str(elem->beg, elem->end);
    562   case CURL_ASN1_INTEGER:
    563   case CURL_ASN1_ENUMERATED:
    564     return int2str(elem->beg, elem->end);
    565   case CURL_ASN1_BIT_STRING:
    566     return bit2str(elem->beg, elem->end);
    567   case CURL_ASN1_OCTET_STRING:
    568     return octet2str(elem->beg, elem->end);
    569   case CURL_ASN1_NULL:
    570     return strdup("");
    571   case CURL_ASN1_OBJECT_IDENTIFIER:
    572     return OID2str(elem->beg, elem->end, TRUE);
    573   case CURL_ASN1_UTC_TIME:
    574     return UTime2str(elem->beg, elem->end);
    575   case CURL_ASN1_GENERALIZED_TIME:
    576     return GTime2str(elem->beg, elem->end);
    577   case CURL_ASN1_UTF8_STRING:
    578   case CURL_ASN1_NUMERIC_STRING:
    579   case CURL_ASN1_PRINTABLE_STRING:
    580   case CURL_ASN1_TELETEX_STRING:
    581   case CURL_ASN1_IA5_STRING:
    582   case CURL_ASN1_VISIBLE_STRING:
    583   case CURL_ASN1_UNIVERSAL_STRING:
    584   case CURL_ASN1_BMP_STRING:
    585     return string2str(type, elem->beg, elem->end);
    586   }
    587 
    588   return (const char *) NULL;   /* Unsupported. */
    589 }
    590 
    591 static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
    592 {
    593   curl_asn1Element rdn;
    594   curl_asn1Element atv;
    595   curl_asn1Element oid;
    596   curl_asn1Element value;
    597   size_t l = 0;
    598   const char *p1;
    599   const char *p2;
    600   const char *p3;
    601   const char *str;
    602 
    603   /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'.
    604      Return the total string length, even if larger than `n'. */
    605 
    606   for(p1 = dn->beg; p1 < dn->end;) {
    607     p1 = Curl_getASN1Element(&rdn, p1, dn->end);
    608     for(p2 = rdn.beg; p2 < rdn.end;) {
    609       p2 = Curl_getASN1Element(&atv, p2, rdn.end);
    610       p3 = Curl_getASN1Element(&oid, atv.beg, atv.end);
    611       Curl_getASN1Element(&value, p3, atv.end);
    612       str = Curl_ASN1tostr(&oid, 0);
    613       if(!str)
    614         return -1;
    615 
    616       /* Encode delimiter.
    617          If attribute has a short uppercase name, delimiter is ", ". */
    618       if(l) {
    619         for(p3 = str; isupper(*p3); p3++)
    620           ;
    621         for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
    622           if(l < n)
    623             buf[l] = *p3;
    624           l++;
    625         }
    626       }
    627 
    628       /* Encode attribute name. */
    629       for(p3 = str; *p3; p3++) {
    630         if(l < n)
    631           buf[l] = *p3;
    632         l++;
    633       }
    634       free((char *) str);
    635 
    636       /* Generate equal sign. */
    637       if(l < n)
    638         buf[l] = '=';
    639       l++;
    640 
    641       /* Generate value. */
    642       str = Curl_ASN1tostr(&value, 0);
    643       if(!str)
    644         return -1;
    645       for(p3 = str; *p3; p3++) {
    646         if(l < n)
    647           buf[l] = *p3;
    648         l++;
    649       }
    650       free((char *) str);
    651     }
    652   }
    653 
    654   return l;
    655 }
    656 
    657 const char *Curl_DNtostr(curl_asn1Element *dn)
    658 {
    659   char *buf = (char *) NULL;
    660   ssize_t n = encodeDN(buf, 0, dn);
    661 
    662   /* Convert an ASN.1 distinguished name into a printable string.
    663      Return the dynamically allocated string, or NULL if an error occurs. */
    664 
    665   if(n >= 0) {
    666     buf = malloc(n + 1);
    667     if(buf) {
    668       encodeDN(buf, n + 1, dn);
    669       buf[n] = '\0';
    670     }
    671   }
    672   return (const char *) buf;
    673 }
    674 
    675 /*
    676  * X509 parser.
    677  */
    678 
    679 int Curl_parseX509(curl_X509certificate *cert,
    680                    const char *beg, const char *end)
    681 {
    682   curl_asn1Element elem;
    683   curl_asn1Element tbsCertificate;
    684   const char *ccp;
    685   static const char defaultVersion = 0;  /* v1. */
    686 
    687   /* ASN.1 parse an X509 certificate into structure subfields.
    688      Syntax is assumed to have already been checked by the SSL backend.
    689      See RFC 5280. */
    690 
    691   cert->certificate.header = NULL;
    692   cert->certificate.beg = beg;
    693   cert->certificate.end = end;
    694 
    695   /* Get the sequence content. */
    696   if(!Curl_getASN1Element(&elem, beg, end))
    697     return -1;  /* Invalid bounds/size. */
    698   beg = elem.beg;
    699   end = elem.end;
    700 
    701   /* Get tbsCertificate. */
    702   beg = Curl_getASN1Element(&tbsCertificate, beg, end);
    703   /* Skip the signatureAlgorithm. */
    704   beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
    705   /* Get the signatureValue. */
    706   Curl_getASN1Element(&cert->signature, beg, end);
    707 
    708   /* Parse TBSCertificate. */
    709   beg = tbsCertificate.beg;
    710   end = tbsCertificate.end;
    711   /* Get optional version, get serialNumber. */
    712   cert->version.header = NULL;
    713   cert->version.beg = &defaultVersion;
    714   cert->version.end = &defaultVersion + sizeof defaultVersion;;
    715   beg = Curl_getASN1Element(&elem, beg, end);
    716   if(elem.tag == 0) {
    717     Curl_getASN1Element(&cert->version, elem.beg, elem.end);
    718     beg = Curl_getASN1Element(&elem, beg, end);
    719   }
    720   cert->serialNumber = elem;
    721   /* Get signature algorithm. */
    722   beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
    723   /* Get issuer. */
    724   beg = Curl_getASN1Element(&cert->issuer, beg, end);
    725   /* Get notBefore and notAfter. */
    726   beg = Curl_getASN1Element(&elem, beg, end);
    727   ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end);
    728   Curl_getASN1Element(&cert->notAfter, ccp, elem.end);
    729   /* Get subject. */
    730   beg = Curl_getASN1Element(&cert->subject, beg, end);
    731   /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
    732   beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
    733   ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm,
    734                             cert->subjectPublicKeyInfo.beg,
    735                             cert->subjectPublicKeyInfo.end);
    736   Curl_getASN1Element(&cert->subjectPublicKey, ccp,
    737                       cert->subjectPublicKeyInfo.end);
    738   /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
    739   cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
    740   cert->extensions.tag = elem.tag = 0;
    741   cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
    742   cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
    743   cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
    744   cert->extensions.header = NULL;
    745   cert->extensions.beg = cert->extensions.end = "";
    746   if(beg < end)
    747     beg = Curl_getASN1Element(&elem, beg, end);
    748   if(elem.tag == 1) {
    749     cert->issuerUniqueID = elem;
    750     if(beg < end)
    751       beg = Curl_getASN1Element(&elem, beg, end);
    752   }
    753   if(elem.tag == 2) {
    754     cert->subjectUniqueID = elem;
    755     if(beg < end)
    756       beg = Curl_getASN1Element(&elem, beg, end);
    757   }
    758   if(elem.tag == 3)
    759     Curl_getASN1Element(&cert->extensions, elem.beg, elem.end);
    760   return 0;
    761 }
    762 
    763 static size_t copySubstring(char *to, const char *from)
    764 {
    765   size_t i;
    766 
    767   /* Copy at most 64-characters, terminate with a newline and returns the
    768      effective number of stored characters. */
    769 
    770   for(i = 0; i < 64; i++) {
    771     to[i] = *from;
    772     if(!*from++)
    773       break;
    774   }
    775 
    776   to[i++] = '\n';
    777   return i;
    778 }
    779 
    780 static const char *dumpAlgo(curl_asn1Element *param,
    781                             const char *beg, const char *end)
    782 {
    783   curl_asn1Element oid;
    784 
    785   /* Get algorithm parameters and return algorithm name. */
    786 
    787   beg = Curl_getASN1Element(&oid, beg, end);
    788   param->header = NULL;
    789   param->tag = 0;
    790   param->beg = param->end = end;
    791   if(beg < end)
    792     Curl_getASN1Element(param, beg, end);
    793   return OID2str(oid.beg, oid.end, TRUE);
    794 }
    795 
    796 static void do_pubkey_field(struct Curl_easy *data, int certnum,
    797                             const char *label, curl_asn1Element *elem)
    798 {
    799   const char *output;
    800 
    801   /* Generate a certificate information record for the public key. */
    802 
    803   output = Curl_ASN1tostr(elem, 0);
    804   if(output) {
    805     if(data->set.ssl.certinfo)
    806       Curl_ssl_push_certinfo(data, certnum, label, output);
    807     if(!certnum)
    808       infof(data, "   %s: %s\n", label, output);
    809     free((char *) output);
    810   }
    811 }
    812 
    813 static void do_pubkey(struct Curl_easy *data, int certnum,
    814                       const char *algo, curl_asn1Element *param,
    815                       curl_asn1Element *pubkey)
    816 {
    817   curl_asn1Element elem;
    818   curl_asn1Element pk;
    819   const char *p;
    820   const char *q;
    821   unsigned long len;
    822   unsigned int i;
    823 
    824   /* Generate all information records for the public key. */
    825 
    826   /* Get the public key (single element). */
    827   Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end);
    828 
    829   if(strcasecompare(algo, "rsaEncryption")) {
    830     p = Curl_getASN1Element(&elem, pk.beg, pk.end);
    831     /* Compute key length. */
    832     for(q = elem.beg; !*q && q < elem.end; q++)
    833       ;
    834     len = (unsigned long)((elem.end - q) * 8);
    835     if(len)
    836       for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
    837         len--;
    838     if(len > 32)
    839       elem.beg = q;     /* Strip leading zero bytes. */
    840     if(!certnum)
    841       infof(data, "   RSA Public Key (%lu bits)\n", len);
    842     if(data->set.ssl.certinfo) {
    843       q = curl_maprintf("%lu", len);
    844       if(q) {
    845         Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
    846         free((char *) q);
    847       }
    848     }
    849     /* Generate coefficients. */
    850     do_pubkey_field(data, certnum, "rsa(n)", &elem);
    851     Curl_getASN1Element(&elem, p, pk.end);
    852     do_pubkey_field(data, certnum, "rsa(e)", &elem);
    853   }
    854   else if(strcasecompare(algo, "dsa")) {
    855     p = Curl_getASN1Element(&elem, param->beg, param->end);
    856     do_pubkey_field(data, certnum, "dsa(p)", &elem);
    857     p = Curl_getASN1Element(&elem, p, param->end);
    858     do_pubkey_field(data, certnum, "dsa(q)", &elem);
    859     Curl_getASN1Element(&elem, p, param->end);
    860     do_pubkey_field(data, certnum, "dsa(g)", &elem);
    861     do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
    862   }
    863   else if(strcasecompare(algo, "dhpublicnumber")) {
    864     p = Curl_getASN1Element(&elem, param->beg, param->end);
    865     do_pubkey_field(data, certnum, "dh(p)", &elem);
    866     Curl_getASN1Element(&elem, param->beg, param->end);
    867     do_pubkey_field(data, certnum, "dh(g)", &elem);
    868     do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
    869   }
    870 #if 0 /* Patent-encumbered. */
    871   else if(strcasecompare(algo, "ecPublicKey")) {
    872     /* Left TODO. */
    873   }
    874 #endif
    875 }
    876 
    877 CURLcode Curl_extract_certinfo(struct connectdata *conn,
    878                                int certnum,
    879                                const char *beg,
    880                                const char *end)
    881 {
    882   curl_X509certificate cert;
    883   struct Curl_easy *data = conn->data;
    884   curl_asn1Element param;
    885   const char *ccp;
    886   char *cp1;
    887   size_t cl1;
    888   char *cp2;
    889   CURLcode result;
    890   unsigned long version;
    891   size_t i;
    892   size_t j;
    893 
    894   if(!data->set.ssl.certinfo)
    895     if(certnum)
    896       return CURLE_OK;
    897 
    898   /* Prepare the certificate information for curl_easy_getinfo(). */
    899 
    900   /* Extract the certificate ASN.1 elements. */
    901   if(Curl_parseX509(&cert, beg, end))
    902     return CURLE_OUT_OF_MEMORY;
    903 
    904   /* Subject. */
    905   ccp = Curl_DNtostr(&cert.subject);
    906   if(!ccp)
    907     return CURLE_OUT_OF_MEMORY;
    908   if(data->set.ssl.certinfo)
    909     Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
    910   if(!certnum)
    911     infof(data, "%2d Subject: %s\n", certnum, ccp);
    912   free((char *) ccp);
    913 
    914   /* Issuer. */
    915   ccp = Curl_DNtostr(&cert.issuer);
    916   if(!ccp)
    917     return CURLE_OUT_OF_MEMORY;
    918   if(data->set.ssl.certinfo)
    919     Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
    920   if(!certnum)
    921     infof(data, "   Issuer: %s\n", ccp);
    922   free((char *) ccp);
    923 
    924   /* Version (always fits in less than 32 bits). */
    925   version = 0;
    926   for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
    927     version = (version << 8) | *(const unsigned char *) ccp;
    928   if(data->set.ssl.certinfo) {
    929     ccp = curl_maprintf("%lx", version);
    930     if(!ccp)
    931       return CURLE_OUT_OF_MEMORY;
    932     Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
    933     free((char *) ccp);
    934   }
    935   if(!certnum)
    936     infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
    937 
    938   /* Serial number. */
    939   ccp = Curl_ASN1tostr(&cert.serialNumber, 0);
    940   if(!ccp)
    941     return CURLE_OUT_OF_MEMORY;
    942   if(data->set.ssl.certinfo)
    943     Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
    944   if(!certnum)
    945     infof(data, "   Serial Number: %s\n", ccp);
    946   free((char *) ccp);
    947 
    948   /* Signature algorithm .*/
    949   ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
    950                  cert.signatureAlgorithm.end);
    951   if(!ccp)
    952     return CURLE_OUT_OF_MEMORY;
    953   if(data->set.ssl.certinfo)
    954     Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
    955   if(!certnum)
    956     infof(data, "   Signature Algorithm: %s\n", ccp);
    957   free((char *) ccp);
    958 
    959   /* Start Date. */
    960   ccp = Curl_ASN1tostr(&cert.notBefore, 0);
    961   if(!ccp)
    962     return CURLE_OUT_OF_MEMORY;
    963   if(data->set.ssl.certinfo)
    964     Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
    965   if(!certnum)
    966     infof(data, "   Start Date: %s\n", ccp);
    967   free((char *) ccp);
    968 
    969   /* Expire Date. */
    970   ccp = Curl_ASN1tostr(&cert.notAfter, 0);
    971   if(!ccp)
    972     return CURLE_OUT_OF_MEMORY;
    973   if(data->set.ssl.certinfo)
    974     Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
    975   if(!certnum)
    976     infof(data, "   Expire Date: %s\n", ccp);
    977   free((char *) ccp);
    978 
    979   /* Public Key Algorithm. */
    980   ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
    981                  cert.subjectPublicKeyAlgorithm.end);
    982   if(!ccp)
    983     return CURLE_OUT_OF_MEMORY;
    984   if(data->set.ssl.certinfo)
    985     Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
    986   if(!certnum)
    987     infof(data, "   Public Key Algorithm: %s\n", ccp);
    988   do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
    989   free((char *) ccp);
    990 
    991 /* TODO: extensions. */
    992 
    993   /* Signature. */
    994   ccp = Curl_ASN1tostr(&cert.signature, 0);
    995   if(!ccp)
    996     return CURLE_OUT_OF_MEMORY;
    997   if(data->set.ssl.certinfo)
    998     Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
    999   if(!certnum)
   1000     infof(data, "   Signature: %s\n", ccp);
   1001   free((char *) ccp);
   1002 
   1003   /* Generate PEM certificate. */
   1004   result = Curl_base64_encode(data, cert.certificate.beg,
   1005                               cert.certificate.end - cert.certificate.beg,
   1006                               &cp1, &cl1);
   1007   if(result)
   1008     return result;
   1009   /* Compute the number of characters in final certificate string. Format is:
   1010      -----BEGIN CERTIFICATE-----\n
   1011      <max 64 base64 characters>\n
   1012      .
   1013      .
   1014      .
   1015      -----END CERTIFICATE-----\n
   1016    */
   1017   i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
   1018   cp2 = malloc(i + 1);
   1019   if(!cp2) {
   1020     free(cp1);
   1021     return CURLE_OUT_OF_MEMORY;
   1022   }
   1023   /* Build the certificate string. */
   1024   i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
   1025   for(j = 0; j < cl1; j += 64)
   1026     i += copySubstring(cp2 + i, cp1 + j);
   1027   i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
   1028   cp2[i] = '\0';
   1029   free(cp1);
   1030   if(data->set.ssl.certinfo)
   1031     Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
   1032   if(!certnum)
   1033     infof(data, "%s\n", cp2);
   1034   free(cp2);
   1035   return CURLE_OK;
   1036 }
   1037 
   1038 #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
   1039 
   1040 #if defined(USE_GSKIT)
   1041 
   1042 static const char *checkOID(const char *beg, const char *end,
   1043                             const char *oid)
   1044 {
   1045   curl_asn1Element e;
   1046   const char *ccp;
   1047   const char *p;
   1048   bool matched;
   1049 
   1050   /* Check if first ASN.1 element at `beg' is the given OID.
   1051      Return a pointer in the source after the OID if found, else NULL. */
   1052 
   1053   ccp = Curl_getASN1Element(&e, beg, end);
   1054   if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
   1055     return (const char *) NULL;
   1056 
   1057   p = OID2str(e.beg, e.end, FALSE);
   1058   if(!p)
   1059     return (const char *) NULL;
   1060 
   1061   matched = !strcmp(p, oid);
   1062   free((char *) p);
   1063   return matched? ccp: (const char *) NULL;
   1064 }
   1065 
   1066 CURLcode Curl_verifyhost(struct connectdata *conn,
   1067                          const char *beg, const char *end)
   1068 {
   1069   struct Curl_easy *data = conn->data;
   1070   curl_X509certificate cert;
   1071   curl_asn1Element dn;
   1072   curl_asn1Element elem;
   1073   curl_asn1Element ext;
   1074   curl_asn1Element name;
   1075   const char *p;
   1076   const char *q;
   1077   char *dnsname;
   1078   int matched = -1;
   1079   size_t addrlen = (size_t) -1;
   1080   ssize_t len;
   1081   const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
   1082                                                 conn->host.name;
   1083   const char * const dispname = SSL_IS_PROXY()?
   1084                                   conn->http_proxy.host.dispname:
   1085                                   conn->host.dispname;
   1086 #ifdef ENABLE_IPV6
   1087   struct in6_addr addr;
   1088 #else
   1089   struct in_addr addr;
   1090 #endif
   1091 
   1092   /* Verify that connection server matches info in X509 certificate at
   1093      `beg'..`end'. */
   1094 
   1095   if(!SSL_CONN_CONFIG(verifyhost))
   1096     return CURLE_OK;
   1097 
   1098   if(Curl_parseX509(&cert, beg, end))
   1099     return CURLE_PEER_FAILED_VERIFICATION;
   1100 
   1101   /* Get the server IP address. */
   1102 #ifdef ENABLE_IPV6
   1103   if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
   1104     addrlen = sizeof(struct in6_addr);
   1105   else
   1106 #endif
   1107   if(Curl_inet_pton(AF_INET, hostname, &addr))
   1108     addrlen = sizeof(struct in_addr);
   1109 
   1110   /* Process extensions. */
   1111   for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
   1112     p = Curl_getASN1Element(&ext, p, cert.extensions.end);
   1113     /* Check if extension is a subjectAlternativeName. */
   1114     ext.beg = checkOID(ext.beg, ext.end, sanOID);
   1115     if(ext.beg) {
   1116       ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
   1117       /* Skip critical if present. */
   1118       if(elem.tag == CURL_ASN1_BOOLEAN)
   1119         ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
   1120       /* Parse the octet string contents: is a single sequence. */
   1121       Curl_getASN1Element(&elem, elem.beg, elem.end);
   1122       /* Check all GeneralNames. */
   1123       for(q = elem.beg; matched != 1 && q < elem.end;) {
   1124         q = Curl_getASN1Element(&name, q, elem.end);
   1125         switch (name.tag) {
   1126         case 2: /* DNS name. */
   1127           len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
   1128                             name.beg, name.end);
   1129           if(len > 0 && (size_t)len == strlen(dnsname))
   1130             matched = Curl_cert_hostcheck(dnsname, hostname);
   1131           else
   1132             matched = 0;
   1133           free(dnsname);
   1134           break;
   1135 
   1136         case 7: /* IP address. */
   1137           matched = (size_t) (name.end - q) == addrlen &&
   1138                     !memcmp(&addr, q, addrlen);
   1139           break;
   1140         }
   1141       }
   1142     }
   1143   }
   1144 
   1145   switch (matched) {
   1146   case 1:
   1147     /* an alternative name matched the server hostname */
   1148     infof(data, "\t subjectAltName: %s matched\n", dispname);
   1149     return CURLE_OK;
   1150   case 0:
   1151     /* an alternative name field existed, but didn't match and then
   1152        we MUST fail */
   1153     infof(data, "\t subjectAltName does not match %s\n", dispname);
   1154     return CURLE_PEER_FAILED_VERIFICATION;
   1155   }
   1156 
   1157   /* Process subject. */
   1158   name.header = NULL;
   1159   name.beg = name.end = "";
   1160   q = cert.subject.beg;
   1161   /* we have to look to the last occurrence of a commonName in the
   1162      distinguished one to get the most significant one. */
   1163   while(q < cert.subject.end) {
   1164     q = Curl_getASN1Element(&dn, q, cert.subject.end);
   1165     for(p = dn.beg; p < dn.end;) {
   1166       p = Curl_getASN1Element(&elem, p, dn.end);
   1167       /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
   1168       elem.beg = checkOID(elem.beg, elem.end, cnOID);
   1169       if(elem.beg)
   1170         name = elem;    /* Latch CN. */
   1171     }
   1172   }
   1173 
   1174   /* Check the CN if found. */
   1175   if(!Curl_getASN1Element(&elem, name.beg, name.end))
   1176     failf(data, "SSL: unable to obtain common name from peer certificate");
   1177   else {
   1178     len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
   1179     if(len < 0) {
   1180       free(dnsname);
   1181       return CURLE_OUT_OF_MEMORY;
   1182     }
   1183     if(strlen(dnsname) != (size_t) len)         /* Nul byte in string ? */
   1184       failf(data, "SSL: illegal cert name field");
   1185     else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
   1186       infof(data, "\t common name: %s (matched)\n", dnsname);
   1187       free(dnsname);
   1188       return CURLE_OK;
   1189     }
   1190     else
   1191       failf(data, "SSL: certificate subject name '%s' does not match "
   1192             "target host name '%s'", dnsname, dispname);
   1193     free(dnsname);
   1194   }
   1195 
   1196   return CURLE_PEER_FAILED_VERIFICATION;
   1197 }
   1198 
   1199 #endif /* USE_GSKIT */
   1200