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