x509asn1.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
00026     defined(USE_CYASSL) || defined(USE_SCHANNEL)
00027 
00028 #include <curl/curl.h>
00029 #include "urldata.h"
00030 #include "strcase.h"
00031 #include "hostcheck.h"
00032 #include "vtls/vtls.h"
00033 #include "sendf.h"
00034 #include "inet_pton.h"
00035 #include "curl_base64.h"
00036 #include "x509asn1.h"
00037 
00038 /* The last 3 #include files should be in this order */
00039 #include "curl_printf.h"
00040 #include "curl_memory.h"
00041 #include "memdebug.h"
00042 
00043 /* For overflow checks. */
00044 #define CURL_SIZE_T_MAX         ((size_t)-1)
00045 
00046 
00047 /* ASN.1 OIDs. */
00048 static const char       cnOID[] = "2.5.4.3";    /* Common name. */
00049 static const char       sanOID[] = "2.5.29.17"; /* Subject alternative name. */
00050 
00051 static const curl_OID   OIDtable[] = {
00052   { "1.2.840.10040.4.1",        "dsa" },
00053   { "1.2.840.10040.4.3",        "dsa-with-sha1" },
00054   { "1.2.840.10045.2.1",        "ecPublicKey" },
00055   { "1.2.840.10045.3.0.1",      "c2pnb163v1" },
00056   { "1.2.840.10045.4.1",        "ecdsa-with-SHA1" },
00057   { "1.2.840.10046.2.1",        "dhpublicnumber" },
00058   { "1.2.840.113549.1.1.1",     "rsaEncryption" },
00059   { "1.2.840.113549.1.1.2",     "md2WithRSAEncryption" },
00060   { "1.2.840.113549.1.1.4",     "md5WithRSAEncryption" },
00061   { "1.2.840.113549.1.1.5",     "sha1WithRSAEncryption" },
00062   { "1.2.840.113549.1.1.10",    "RSASSA-PSS" },
00063   { "1.2.840.113549.1.1.14",    "sha224WithRSAEncryption" },
00064   { "1.2.840.113549.1.1.11",    "sha256WithRSAEncryption" },
00065   { "1.2.840.113549.1.1.12",    "sha384WithRSAEncryption" },
00066   { "1.2.840.113549.1.1.13",    "sha512WithRSAEncryption" },
00067   { "1.2.840.113549.2.2",       "md2" },
00068   { "1.2.840.113549.2.5",       "md5" },
00069   { "1.3.14.3.2.26",            "sha1" },
00070   { cnOID,                      "CN" },
00071   { "2.5.4.4",                  "SN" },
00072   { "2.5.4.5",                  "serialNumber" },
00073   { "2.5.4.6",                  "C" },
00074   { "2.5.4.7",                  "L" },
00075   { "2.5.4.8",                  "ST" },
00076   { "2.5.4.9",                  "streetAddress" },
00077   { "2.5.4.10",                 "O" },
00078   { "2.5.4.11",                 "OU" },
00079   { "2.5.4.12",                 "title" },
00080   { "2.5.4.13",                 "description" },
00081   { "2.5.4.17",                 "postalCode" },
00082   { "2.5.4.41",                 "name" },
00083   { "2.5.4.42",                 "givenName" },
00084   { "2.5.4.43",                 "initials" },
00085   { "2.5.4.44",                 "generationQualifier" },
00086   { "2.5.4.45",                 "X500UniqueIdentifier" },
00087   { "2.5.4.46",                 "dnQualifier" },
00088   { "2.5.4.65",                 "pseudonym" },
00089   { "1.2.840.113549.1.9.1",     "emailAddress" },
00090   { "2.5.4.72",                 "role" },
00091   { sanOID,                     "subjectAltName" },
00092   { "2.5.29.18",                "issuerAltName" },
00093   { "2.5.29.19",                "basicConstraints" },
00094   { "2.16.840.1.101.3.4.2.4",   "sha224" },
00095   { "2.16.840.1.101.3.4.2.1",   "sha256" },
00096   { "2.16.840.1.101.3.4.2.2",   "sha384" },
00097   { "2.16.840.1.101.3.4.2.3",   "sha512" },
00098   { (const char *) NULL,        (const char *) NULL }
00099 };
00100 
00101 /*
00102  * Lightweight ASN.1 parser.
00103  * In particular, it does not check for syntactic/lexical errors.
00104  * It is intended to support certificate information gathering for SSL backends
00105  * that offer a mean to get certificates as a whole, but do not supply
00106  * entry points to get particular certificate sub-fields.
00107  * Please note there is no pretention here to rewrite a full SSL library.
00108  */
00109 
00110 
00111 const char *Curl_getASN1Element(curl_asn1Element *elem,
00112                                 const char *beg, const char *end)
00113 {
00114   unsigned char b;
00115   unsigned long len;
00116   curl_asn1Element lelem;
00117 
00118   /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
00119      ending at `end'.
00120      Returns a pointer in source string after the parsed element, or NULL
00121      if an error occurs. */
00122   if(!beg || !end || beg >= end || !*beg ||
00123      (size_t)(end - beg) > CURL_ASN1_MAX)
00124     return (const char *) NULL;
00125 
00126   /* Process header byte. */
00127   elem->header = beg;
00128   b = (unsigned char) *beg++;
00129   elem->constructed = (b & 0x20) != 0;
00130   elem->class = (b >> 6) & 3;
00131   b &= 0x1F;
00132   if(b == 0x1F)
00133     return (const char *) NULL; /* Long tag values not supported here. */
00134   elem->tag = b;
00135 
00136   /* Process length. */
00137   if(beg >= end)
00138     return (const char *) NULL;
00139   b = (unsigned char) *beg++;
00140   if(!(b & 0x80))
00141     len = b;
00142   else if(!(b &= 0x7F)) {
00143     /* Unspecified length. Since we have all the data, we can determine the
00144        effective length by skipping element until an end element is found. */
00145     if(!elem->constructed)
00146       return (const char *) NULL;
00147     elem->beg = beg;
00148     while(beg < end && *beg) {
00149       beg = Curl_getASN1Element(&lelem, beg, end);
00150       if(!beg)
00151         return (const char *) NULL;
00152     }
00153     if(beg >= end)
00154       return (const char *) NULL;
00155     elem->end = beg;
00156     return beg + 1;
00157   }
00158   else if((unsigned)b > (size_t)(end - beg))
00159     return (const char *) NULL; /* Does not fit in source. */
00160   else {
00161     /* Get long length. */
00162     len = 0;
00163     do {
00164       if(len & 0xFF000000L)
00165         return (const char *) NULL;  /* Lengths > 32 bits are not supported. */
00166       len = (len << 8) | (unsigned char) *beg++;
00167     } while(--b);
00168   }
00169   if(len > (size_t)(end - beg))
00170     return (const char *) NULL;  /* Element data does not fit in source. */
00171   elem->beg = beg;
00172   elem->end = beg + len;
00173   return elem->end;
00174 }
00175 
00176 static const curl_OID * searchOID(const char *oid)
00177 {
00178   const curl_OID *op;
00179 
00180   /* Search the null terminated OID or OID identifier in local table.
00181      Return the table entry pointer or NULL if not found. */
00182 
00183   for(op = OIDtable; op->numoid; op++)
00184     if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
00185       return op;
00186 
00187   return (const curl_OID *) NULL;
00188 }
00189 
00190 static const char *bool2str(const char *beg, const char *end)
00191 {
00192   /* Convert an ASN.1 Boolean value into its string representation.
00193      Return the dynamically allocated string, or NULL if source is not an
00194      ASN.1 Boolean value. */
00195 
00196   if(end - beg != 1)
00197     return (const char *) NULL;
00198   return strdup(*beg? "TRUE": "FALSE");
00199 }
00200 
00201 static const char *octet2str(const char *beg, const char *end)
00202 {
00203   size_t n = end - beg;
00204   char *buf = NULL;
00205 
00206   /* Convert an ASN.1 octet string to a printable string.
00207      Return the dynamically allocated string, or NULL if an error occurs. */
00208 
00209   if(n <= (CURL_SIZE_T_MAX - 1) / 3) {
00210     buf = malloc(3 * n + 1);
00211     if(buf)
00212       for(n = 0; beg < end; n += 3)
00213         snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
00214   }
00215   return buf;
00216 }
00217 
00218 static const char *bit2str(const char *beg, const char *end)
00219 {
00220   /* Convert an ASN.1 bit string to a printable string.
00221      Return the dynamically allocated string, or NULL if an error occurs. */
00222 
00223   if(++beg > end)
00224     return (const char *) NULL;
00225   return octet2str(beg, end);
00226 }
00227 
00228 static const char *int2str(const char *beg, const char *end)
00229 {
00230   long val = 0;
00231   size_t n = end - beg;
00232 
00233   /* Convert an ASN.1 integer value into its string representation.
00234      Return the dynamically allocated string, or NULL if source is not an
00235      ASN.1 integer value. */
00236 
00237   if(!n)
00238     return (const char *) NULL;
00239 
00240   if(n > 4)
00241     return octet2str(beg, end);
00242 
00243   /* Represent integers <= 32-bit as a single value. */
00244   if(*beg & 0x80)
00245     val = ~val;
00246 
00247   do
00248     val = (val << 8) | *(const unsigned char *) beg++;
00249   while(beg < end);
00250   return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val);
00251 }
00252 
00253 static ssize_t
00254 utf8asn1str(char **to, int type, const char *from, const char *end)
00255 {
00256   size_t inlength = end - from;
00257   int size = 1;
00258   size_t outlength;
00259   int charsize;
00260   unsigned int wc;
00261   char *buf;
00262 
00263   /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
00264      destination buffer dynamically. The allocation size will normally be too
00265      large: this is to avoid buffer overflows.
00266      Terminate the string with a nul byte and return the converted
00267      string length. */
00268 
00269   *to = (char *) NULL;
00270   switch(type) {
00271   case CURL_ASN1_BMP_STRING:
00272     size = 2;
00273     break;
00274   case CURL_ASN1_UNIVERSAL_STRING:
00275     size = 4;
00276     break;
00277   case CURL_ASN1_NUMERIC_STRING:
00278   case CURL_ASN1_PRINTABLE_STRING:
00279   case CURL_ASN1_TELETEX_STRING:
00280   case CURL_ASN1_IA5_STRING:
00281   case CURL_ASN1_VISIBLE_STRING:
00282   case CURL_ASN1_UTF8_STRING:
00283     break;
00284   default:
00285     return -1;  /* Conversion not supported. */
00286   }
00287 
00288   if(inlength % size)
00289     return -1;  /* Length inconsistent with character size. */
00290   if(inlength / size > (CURL_SIZE_T_MAX - 1) / 4)
00291     return -1;  /* Too big. */
00292   buf = malloc(4 * (inlength / size) + 1);
00293   if(!buf)
00294     return -1;  /* Not enough memory. */
00295 
00296   if(type == CURL_ASN1_UTF8_STRING) {
00297     /* Just copy. */
00298     outlength = inlength;
00299     if(outlength)
00300       memcpy(buf, from, outlength);
00301   }
00302   else {
00303     for(outlength = 0; from < end;) {
00304       wc = 0;
00305       switch(size) {
00306       case 4:
00307         wc = (wc << 8) | *(const unsigned char *) from++;
00308         wc = (wc << 8) | *(const unsigned char *) from++;
00309         /* fallthrough */
00310       case 2:
00311         wc = (wc << 8) | *(const unsigned char *) from++;
00312         /* fallthrough */
00313       default: /* case 1: */
00314         wc = (wc << 8) | *(const unsigned char *) from++;
00315       }
00316       charsize = 1;
00317       if(wc >= 0x00000080) {
00318         if(wc >= 0x00000800) {
00319           if(wc >= 0x00010000) {
00320             if(wc >= 0x00200000) {
00321               free(buf);
00322               return -1;        /* Invalid char. size for target encoding. */
00323             }
00324             buf[outlength + 3] = (char) (0x80 | (wc & 0x3F));
00325             wc = (wc >> 6) | 0x00010000;
00326             charsize++;
00327           }
00328           buf[outlength + 2] = (char) (0x80 | (wc & 0x3F));
00329           wc = (wc >> 6) | 0x00000800;
00330           charsize++;
00331         }
00332         buf[outlength + 1] = (char) (0x80 | (wc & 0x3F));
00333         wc = (wc >> 6) | 0x000000C0;
00334         charsize++;
00335       }
00336       buf[outlength] = (char) wc;
00337       outlength += charsize;
00338     }
00339   }
00340   buf[outlength] = '\0';
00341   *to = buf;
00342   return outlength;
00343 }
00344 
00345 static const char *string2str(int type, const char *beg, const char *end)
00346 {
00347   char *buf;
00348 
00349   /* Convert an ASN.1 String into its UTF-8 string representation.
00350      Return the dynamically allocated string, or NULL if an error occurs. */
00351 
00352   if(utf8asn1str(&buf, type, beg, end) < 0)
00353     return (const char *) NULL;
00354   return buf;
00355 }
00356 
00357 static int encodeUint(char *buf, int n, unsigned int x)
00358 {
00359   int i = 0;
00360   unsigned int y = x / 10;
00361 
00362   /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'.
00363      Return the total number of encoded digits, even if larger than `n'. */
00364 
00365   if(y) {
00366     i += encodeUint(buf, n, y);
00367     x -= y * 10;
00368   }
00369   if(i < n)
00370     buf[i] = (char) ('0' + x);
00371   i++;
00372   if(i < n)
00373     buf[i] = '\0';      /* Store a terminator if possible. */
00374   return i;
00375 }
00376 
00377 static int encodeOID(char *buf, int n, const char *beg, const char *end)
00378 {
00379   int i = 0;
00380   unsigned int x;
00381   unsigned int y;
00382 
00383   /* Convert an ASN.1 OID into its dotted string representation.
00384      Store the result in th `n'-byte buffer at `buf'.
00385      Return the converted string length, or -1 if an error occurs. */
00386 
00387   /* Process the first two numbers. */
00388   y = *(const unsigned char *) beg++;
00389   x = y / 40;
00390   y -= x * 40;
00391   i += encodeUint(buf + i, n - i, x);
00392   if(i < n)
00393     buf[i] = '.';
00394   i++;
00395   i += encodeUint(buf + i, n - i, y);
00396 
00397   /* Process the trailing numbers. */
00398   while(beg < end) {
00399     if(i < n)
00400       buf[i] = '.';
00401     i++;
00402     x = 0;
00403     do {
00404       if(x & 0xFF000000)
00405         return -1;
00406       y = *(const unsigned char *) beg++;
00407       x = (x << 7) | (y & 0x7F);
00408     } while(y & 0x80);
00409     i += encodeUint(buf + i, n - i, x);
00410   }
00411   if(i < n)
00412     buf[i] = '\0';
00413   return i;
00414 }
00415 
00416 static const char *OID2str(const char *beg, const char *end, bool symbolic)
00417 {
00418   char *buf = (char *) NULL;
00419   const curl_OID * op;
00420   int n;
00421 
00422   /* Convert an ASN.1 OID into its dotted or symbolic string representation.
00423      Return the dynamically allocated string, or NULL if an error occurs. */
00424 
00425   if(beg < end) {
00426     n = encodeOID((char *) NULL, -1, beg, end);
00427     if(n >= 0) {
00428       buf = malloc(n + 1);
00429       if(buf) {
00430         encodeOID(buf, n, beg, end);
00431         buf[n] = '\0';
00432 
00433         if(symbolic) {
00434           op = searchOID(buf);
00435           if(op) {
00436             free(buf);
00437             buf = strdup(op->textoid);
00438           }
00439         }
00440       }
00441     }
00442   }
00443   return buf;
00444 }
00445 
00446 static const char *GTime2str(const char *beg, const char *end)
00447 {
00448   const char *tzp;
00449   const char *fracp;
00450   char sec1, sec2;
00451   size_t fracl;
00452   size_t tzl;
00453   const char *sep = "";
00454 
00455   /* Convert an ASN.1 Generalized time to a printable string.
00456      Return the dynamically allocated string, or NULL if an error occurs. */
00457 
00458   for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
00459     ;
00460 
00461   /* Get seconds digits. */
00462   sec1 = '0';
00463   switch(fracp - beg - 12) {
00464   case 0:
00465     sec2 = '0';
00466     break;
00467   case 2:
00468     sec1 = fracp[-2];
00469   case 1:
00470     sec2 = fracp[-1];
00471     break;
00472   default:
00473     return (const char *) NULL;
00474   }
00475 
00476   /* Scan for timezone, measure fractional seconds. */
00477   tzp = fracp;
00478   fracl = 0;
00479   if(fracp < end && (*fracp == '.' || *fracp == ',')) {
00480     fracp++;
00481     do
00482       tzp++;
00483     while(tzp < end && *tzp >= '0' && *tzp <= '9');
00484     /* Strip leading zeroes in fractional seconds. */
00485     for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
00486       ;
00487   }
00488 
00489   /* Process timezone. */
00490   if(tzp >= end)
00491     ;           /* Nothing to do. */
00492   else if(*tzp == 'Z') {
00493     tzp = " GMT";
00494     end = tzp + 4;
00495   }
00496   else {
00497     sep = " ";
00498     tzp++;
00499   }
00500 
00501   tzl = end - tzp;
00502   return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
00503                        beg, beg + 4, beg + 6,
00504                        beg + 8, beg + 10, sec1, sec2,
00505                        fracl? ".": "", fracl, fracp,
00506                        sep, tzl, tzp);
00507 }
00508 
00509 static const char *UTime2str(const char *beg, const char *end)
00510 {
00511   const char *tzp;
00512   size_t tzl;
00513   const char *sec;
00514 
00515   /* Convert an ASN.1 UTC time to a printable string.
00516      Return the dynamically allocated string, or NULL if an error occurs. */
00517 
00518   for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
00519     ;
00520   /* Get the seconds. */
00521   sec = beg + 10;
00522   switch(tzp - sec) {
00523   case 0:
00524     sec = "00";
00525   case 2:
00526     break;
00527   default:
00528     return (const char *) NULL;
00529   }
00530 
00531   /* Process timezone. */
00532   if(tzp >= end)
00533     return (const char *) NULL;
00534   if(*tzp == 'Z') {
00535     tzp = "GMT";
00536     end = tzp + 3;
00537   }
00538   else
00539     tzp++;
00540 
00541   tzl = end - tzp;
00542   return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
00543                        20 - (*beg >= '5'), beg, beg + 2, beg + 4,
00544                        beg + 6, beg + 8, sec,
00545                        tzl, tzp);
00546 }
00547 
00548 const char *Curl_ASN1tostr(curl_asn1Element *elem, int type)
00549 {
00550   /* Convert an ASN.1 element to a printable string.
00551      Return the dynamically allocated string, or NULL if an error occurs. */
00552 
00553   if(elem->constructed)
00554     return (const char *) NULL; /* No conversion of structured elements. */
00555 
00556   if(!type)
00557     type = elem->tag;   /* Type not forced: use element tag as type. */
00558 
00559   switch(type) {
00560   case CURL_ASN1_BOOLEAN:
00561     return bool2str(elem->beg, elem->end);
00562   case CURL_ASN1_INTEGER:
00563   case CURL_ASN1_ENUMERATED:
00564     return int2str(elem->beg, elem->end);
00565   case CURL_ASN1_BIT_STRING:
00566     return bit2str(elem->beg, elem->end);
00567   case CURL_ASN1_OCTET_STRING:
00568     return octet2str(elem->beg, elem->end);
00569   case CURL_ASN1_NULL:
00570     return strdup("");
00571   case CURL_ASN1_OBJECT_IDENTIFIER:
00572     return OID2str(elem->beg, elem->end, TRUE);
00573   case CURL_ASN1_UTC_TIME:
00574     return UTime2str(elem->beg, elem->end);
00575   case CURL_ASN1_GENERALIZED_TIME:
00576     return GTime2str(elem->beg, elem->end);
00577   case CURL_ASN1_UTF8_STRING:
00578   case CURL_ASN1_NUMERIC_STRING:
00579   case CURL_ASN1_PRINTABLE_STRING:
00580   case CURL_ASN1_TELETEX_STRING:
00581   case CURL_ASN1_IA5_STRING:
00582   case CURL_ASN1_VISIBLE_STRING:
00583   case CURL_ASN1_UNIVERSAL_STRING:
00584   case CURL_ASN1_BMP_STRING:
00585     return string2str(type, elem->beg, elem->end);
00586   }
00587 
00588   return (const char *) NULL;   /* Unsupported. */
00589 }
00590 
00591 static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
00592 {
00593   curl_asn1Element rdn;
00594   curl_asn1Element atv;
00595   curl_asn1Element oid;
00596   curl_asn1Element value;
00597   size_t l = 0;
00598   const char *p1;
00599   const char *p2;
00600   const char *p3;
00601   const char *str;
00602 
00603   /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'.
00604      Return the total string length, even if larger than `n'. */
00605 
00606   for(p1 = dn->beg; p1 < dn->end;) {
00607     p1 = Curl_getASN1Element(&rdn, p1, dn->end);
00608     for(p2 = rdn.beg; p2 < rdn.end;) {
00609       p2 = Curl_getASN1Element(&atv, p2, rdn.end);
00610       p3 = Curl_getASN1Element(&oid, atv.beg, atv.end);
00611       Curl_getASN1Element(&value, p3, atv.end);
00612       str = Curl_ASN1tostr(&oid, 0);
00613       if(!str)
00614         return -1;
00615 
00616       /* Encode delimiter.
00617          If attribute has a short uppercase name, delimiter is ", ". */
00618       if(l) {
00619         for(p3 = str; isupper(*p3); p3++)
00620           ;
00621         for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
00622           if(l < n)
00623             buf[l] = *p3;
00624           l++;
00625         }
00626       }
00627 
00628       /* Encode attribute name. */
00629       for(p3 = str; *p3; p3++) {
00630         if(l < n)
00631           buf[l] = *p3;
00632         l++;
00633       }
00634       free((char *) str);
00635 
00636       /* Generate equal sign. */
00637       if(l < n)
00638         buf[l] = '=';
00639       l++;
00640 
00641       /* Generate value. */
00642       str = Curl_ASN1tostr(&value, 0);
00643       if(!str)
00644         return -1;
00645       for(p3 = str; *p3; p3++) {
00646         if(l < n)
00647           buf[l] = *p3;
00648         l++;
00649       }
00650       free((char *) str);
00651     }
00652   }
00653 
00654   return l;
00655 }
00656 
00657 const char *Curl_DNtostr(curl_asn1Element *dn)
00658 {
00659   char *buf = (char *) NULL;
00660   ssize_t n = encodeDN(buf, 0, dn);
00661 
00662   /* Convert an ASN.1 distinguished name into a printable string.
00663      Return the dynamically allocated string, or NULL if an error occurs. */
00664 
00665   if(n >= 0) {
00666     buf = malloc(n + 1);
00667     if(buf) {
00668       encodeDN(buf, n + 1, dn);
00669       buf[n] = '\0';
00670     }
00671   }
00672   return (const char *) buf;
00673 }
00674 
00675 /*
00676  * X509 parser.
00677  */
00678 
00679 int Curl_parseX509(curl_X509certificate *cert,
00680                    const char *beg, const char *end)
00681 {
00682   curl_asn1Element elem;
00683   curl_asn1Element tbsCertificate;
00684   const char *ccp;
00685   static const char defaultVersion = 0;  /* v1. */
00686 
00687   /* ASN.1 parse an X509 certificate into structure subfields.
00688      Syntax is assumed to have already been checked by the SSL backend.
00689      See RFC 5280. */
00690 
00691   cert->certificate.header = NULL;
00692   cert->certificate.beg = beg;
00693   cert->certificate.end = end;
00694 
00695   /* Get the sequence content. */
00696   if(!Curl_getASN1Element(&elem, beg, end))
00697     return -1;  /* Invalid bounds/size. */
00698   beg = elem.beg;
00699   end = elem.end;
00700 
00701   /* Get tbsCertificate. */
00702   beg = Curl_getASN1Element(&tbsCertificate, beg, end);
00703   /* Skip the signatureAlgorithm. */
00704   beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
00705   /* Get the signatureValue. */
00706   Curl_getASN1Element(&cert->signature, beg, end);
00707 
00708   /* Parse TBSCertificate. */
00709   beg = tbsCertificate.beg;
00710   end = tbsCertificate.end;
00711   /* Get optional version, get serialNumber. */
00712   cert->version.header = NULL;
00713   cert->version.beg = &defaultVersion;
00714   cert->version.end = &defaultVersion + sizeof defaultVersion;;
00715   beg = Curl_getASN1Element(&elem, beg, end);
00716   if(elem.tag == 0) {
00717     Curl_getASN1Element(&cert->version, elem.beg, elem.end);
00718     beg = Curl_getASN1Element(&elem, beg, end);
00719   }
00720   cert->serialNumber = elem;
00721   /* Get signature algorithm. */
00722   beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
00723   /* Get issuer. */
00724   beg = Curl_getASN1Element(&cert->issuer, beg, end);
00725   /* Get notBefore and notAfter. */
00726   beg = Curl_getASN1Element(&elem, beg, end);
00727   ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end);
00728   Curl_getASN1Element(&cert->notAfter, ccp, elem.end);
00729   /* Get subject. */
00730   beg = Curl_getASN1Element(&cert->subject, beg, end);
00731   /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
00732   beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
00733   ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm,
00734                             cert->subjectPublicKeyInfo.beg,
00735                             cert->subjectPublicKeyInfo.end);
00736   Curl_getASN1Element(&cert->subjectPublicKey, ccp,
00737                       cert->subjectPublicKeyInfo.end);
00738   /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
00739   cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
00740   cert->extensions.tag = elem.tag = 0;
00741   cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
00742   cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
00743   cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
00744   cert->extensions.header = NULL;
00745   cert->extensions.beg = cert->extensions.end = "";
00746   if(beg < end)
00747     beg = Curl_getASN1Element(&elem, beg, end);
00748   if(elem.tag == 1) {
00749     cert->issuerUniqueID = elem;
00750     if(beg < end)
00751       beg = Curl_getASN1Element(&elem, beg, end);
00752   }
00753   if(elem.tag == 2) {
00754     cert->subjectUniqueID = elem;
00755     if(beg < end)
00756       beg = Curl_getASN1Element(&elem, beg, end);
00757   }
00758   if(elem.tag == 3)
00759     Curl_getASN1Element(&cert->extensions, elem.beg, elem.end);
00760   return 0;
00761 }
00762 
00763 static size_t copySubstring(char *to, const char *from)
00764 {
00765   size_t i;
00766 
00767   /* Copy at most 64-characters, terminate with a newline and returns the
00768      effective number of stored characters. */
00769 
00770   for(i = 0; i < 64; i++) {
00771     to[i] = *from;
00772     if(!*from++)
00773       break;
00774   }
00775 
00776   to[i++] = '\n';
00777   return i;
00778 }
00779 
00780 static const char *dumpAlgo(curl_asn1Element *param,
00781                             const char *beg, const char *end)
00782 {
00783   curl_asn1Element oid;
00784 
00785   /* Get algorithm parameters and return algorithm name. */
00786 
00787   beg = Curl_getASN1Element(&oid, beg, end);
00788   param->header = NULL;
00789   param->tag = 0;
00790   param->beg = param->end = end;
00791   if(beg < end)
00792     Curl_getASN1Element(param, beg, end);
00793   return OID2str(oid.beg, oid.end, TRUE);
00794 }
00795 
00796 static void do_pubkey_field(struct Curl_easy *data, int certnum,
00797                             const char *label, curl_asn1Element *elem)
00798 {
00799   const char *output;
00800 
00801   /* Generate a certificate information record for the public key. */
00802 
00803   output = Curl_ASN1tostr(elem, 0);
00804   if(output) {
00805     if(data->set.ssl.certinfo)
00806       Curl_ssl_push_certinfo(data, certnum, label, output);
00807     if(!certnum)
00808       infof(data, "   %s: %s\n", label, output);
00809     free((char *) output);
00810   }
00811 }
00812 
00813 static void do_pubkey(struct Curl_easy *data, int certnum,
00814                       const char *algo, curl_asn1Element *param,
00815                       curl_asn1Element *pubkey)
00816 {
00817   curl_asn1Element elem;
00818   curl_asn1Element pk;
00819   const char *p;
00820   const char *q;
00821   unsigned long len;
00822   unsigned int i;
00823 
00824   /* Generate all information records for the public key. */
00825 
00826   /* Get the public key (single element). */
00827   Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end);
00828 
00829   if(strcasecompare(algo, "rsaEncryption")) {
00830     p = Curl_getASN1Element(&elem, pk.beg, pk.end);
00831     /* Compute key length. */
00832     for(q = elem.beg; !*q && q < elem.end; q++)
00833       ;
00834     len = (unsigned long)((elem.end - q) * 8);
00835     if(len)
00836       for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
00837         len--;
00838     if(len > 32)
00839       elem.beg = q;     /* Strip leading zero bytes. */
00840     if(!certnum)
00841       infof(data, "   RSA Public Key (%lu bits)\n", len);
00842     if(data->set.ssl.certinfo) {
00843       q = curl_maprintf("%lu", len);
00844       if(q) {
00845         Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
00846         free((char *) q);
00847       }
00848     }
00849     /* Generate coefficients. */
00850     do_pubkey_field(data, certnum, "rsa(n)", &elem);
00851     Curl_getASN1Element(&elem, p, pk.end);
00852     do_pubkey_field(data, certnum, "rsa(e)", &elem);
00853   }
00854   else if(strcasecompare(algo, "dsa")) {
00855     p = Curl_getASN1Element(&elem, param->beg, param->end);
00856     do_pubkey_field(data, certnum, "dsa(p)", &elem);
00857     p = Curl_getASN1Element(&elem, p, param->end);
00858     do_pubkey_field(data, certnum, "dsa(q)", &elem);
00859     Curl_getASN1Element(&elem, p, param->end);
00860     do_pubkey_field(data, certnum, "dsa(g)", &elem);
00861     do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
00862   }
00863   else if(strcasecompare(algo, "dhpublicnumber")) {
00864     p = Curl_getASN1Element(&elem, param->beg, param->end);
00865     do_pubkey_field(data, certnum, "dh(p)", &elem);
00866     Curl_getASN1Element(&elem, param->beg, param->end);
00867     do_pubkey_field(data, certnum, "dh(g)", &elem);
00868     do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
00869   }
00870 #if 0 /* Patent-encumbered. */
00871   else if(strcasecompare(algo, "ecPublicKey")) {
00872     /* Left TODO. */
00873   }
00874 #endif
00875 }
00876 
00877 CURLcode Curl_extract_certinfo(struct connectdata *conn,
00878                                int certnum,
00879                                const char *beg,
00880                                const char *end)
00881 {
00882   curl_X509certificate cert;
00883   struct Curl_easy *data = conn->data;
00884   curl_asn1Element param;
00885   const char *ccp;
00886   char *cp1;
00887   size_t cl1;
00888   char *cp2;
00889   CURLcode result;
00890   unsigned long version;
00891   size_t i;
00892   size_t j;
00893 
00894   if(!data->set.ssl.certinfo)
00895     if(certnum)
00896       return CURLE_OK;
00897 
00898   /* Prepare the certificate information for curl_easy_getinfo(). */
00899 
00900   /* Extract the certificate ASN.1 elements. */
00901   if(Curl_parseX509(&cert, beg, end))
00902     return CURLE_OUT_OF_MEMORY;
00903 
00904   /* Subject. */
00905   ccp = Curl_DNtostr(&cert.subject);
00906   if(!ccp)
00907     return CURLE_OUT_OF_MEMORY;
00908   if(data->set.ssl.certinfo)
00909     Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
00910   if(!certnum)
00911     infof(data, "%2d Subject: %s\n", certnum, ccp);
00912   free((char *) ccp);
00913 
00914   /* Issuer. */
00915   ccp = Curl_DNtostr(&cert.issuer);
00916   if(!ccp)
00917     return CURLE_OUT_OF_MEMORY;
00918   if(data->set.ssl.certinfo)
00919     Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
00920   if(!certnum)
00921     infof(data, "   Issuer: %s\n", ccp);
00922   free((char *) ccp);
00923 
00924   /* Version (always fits in less than 32 bits). */
00925   version = 0;
00926   for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
00927     version = (version << 8) | *(const unsigned char *) ccp;
00928   if(data->set.ssl.certinfo) {
00929     ccp = curl_maprintf("%lx", version);
00930     if(!ccp)
00931       return CURLE_OUT_OF_MEMORY;
00932     Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
00933     free((char *) ccp);
00934   }
00935   if(!certnum)
00936     infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
00937 
00938   /* Serial number. */
00939   ccp = Curl_ASN1tostr(&cert.serialNumber, 0);
00940   if(!ccp)
00941     return CURLE_OUT_OF_MEMORY;
00942   if(data->set.ssl.certinfo)
00943     Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
00944   if(!certnum)
00945     infof(data, "   Serial Number: %s\n", ccp);
00946   free((char *) ccp);
00947 
00948   /* Signature algorithm .*/
00949   ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
00950                  cert.signatureAlgorithm.end);
00951   if(!ccp)
00952     return CURLE_OUT_OF_MEMORY;
00953   if(data->set.ssl.certinfo)
00954     Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
00955   if(!certnum)
00956     infof(data, "   Signature Algorithm: %s\n", ccp);
00957   free((char *) ccp);
00958 
00959   /* Start Date. */
00960   ccp = Curl_ASN1tostr(&cert.notBefore, 0);
00961   if(!ccp)
00962     return CURLE_OUT_OF_MEMORY;
00963   if(data->set.ssl.certinfo)
00964     Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
00965   if(!certnum)
00966     infof(data, "   Start Date: %s\n", ccp);
00967   free((char *) ccp);
00968 
00969   /* Expire Date. */
00970   ccp = Curl_ASN1tostr(&cert.notAfter, 0);
00971   if(!ccp)
00972     return CURLE_OUT_OF_MEMORY;
00973   if(data->set.ssl.certinfo)
00974     Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
00975   if(!certnum)
00976     infof(data, "   Expire Date: %s\n", ccp);
00977   free((char *) ccp);
00978 
00979   /* Public Key Algorithm. */
00980   ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
00981                  cert.subjectPublicKeyAlgorithm.end);
00982   if(!ccp)
00983     return CURLE_OUT_OF_MEMORY;
00984   if(data->set.ssl.certinfo)
00985     Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
00986   if(!certnum)
00987     infof(data, "   Public Key Algorithm: %s\n", ccp);
00988   do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
00989   free((char *) ccp);
00990 
00991 /* TODO: extensions. */
00992 
00993   /* Signature. */
00994   ccp = Curl_ASN1tostr(&cert.signature, 0);
00995   if(!ccp)
00996     return CURLE_OUT_OF_MEMORY;
00997   if(data->set.ssl.certinfo)
00998     Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
00999   if(!certnum)
01000     infof(data, "   Signature: %s\n", ccp);
01001   free((char *) ccp);
01002 
01003   /* Generate PEM certificate. */
01004   result = Curl_base64_encode(data, cert.certificate.beg,
01005                               cert.certificate.end - cert.certificate.beg,
01006                               &cp1, &cl1);
01007   if(result)
01008     return result;
01009   /* Compute the number of characters in final certificate string. Format is:
01010      -----BEGIN CERTIFICATE-----\n
01011      <max 64 base64 characters>\n
01012      .
01013      .
01014      .
01015      -----END CERTIFICATE-----\n
01016    */
01017   i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
01018   cp2 = malloc(i + 1);
01019   if(!cp2) {
01020     free(cp1);
01021     return CURLE_OUT_OF_MEMORY;
01022   }
01023   /* Build the certificate string. */
01024   i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
01025   for(j = 0; j < cl1; j += 64)
01026     i += copySubstring(cp2 + i, cp1 + j);
01027   i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
01028   cp2[i] = '\0';
01029   free(cp1);
01030   if(data->set.ssl.certinfo)
01031     Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
01032   if(!certnum)
01033     infof(data, "%s\n", cp2);
01034   free(cp2);
01035   return CURLE_OK;
01036 }
01037 
01038 #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
01039 
01040 #if defined(USE_GSKIT)
01041 
01042 static const char *checkOID(const char *beg, const char *end,
01043                             const char *oid)
01044 {
01045   curl_asn1Element e;
01046   const char *ccp;
01047   const char *p;
01048   bool matched;
01049 
01050   /* Check if first ASN.1 element at `beg' is the given OID.
01051      Return a pointer in the source after the OID if found, else NULL. */
01052 
01053   ccp = Curl_getASN1Element(&e, beg, end);
01054   if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
01055     return (const char *) NULL;
01056 
01057   p = OID2str(e.beg, e.end, FALSE);
01058   if(!p)
01059     return (const char *) NULL;
01060 
01061   matched = !strcmp(p, oid);
01062   free((char *) p);
01063   return matched? ccp: (const char *) NULL;
01064 }
01065 
01066 CURLcode Curl_verifyhost(struct connectdata *conn,
01067                          const char *beg, const char *end)
01068 {
01069   struct Curl_easy *data = conn->data;
01070   curl_X509certificate cert;
01071   curl_asn1Element dn;
01072   curl_asn1Element elem;
01073   curl_asn1Element ext;
01074   curl_asn1Element name;
01075   const char *p;
01076   const char *q;
01077   char *dnsname;
01078   int matched = -1;
01079   size_t addrlen = (size_t) -1;
01080   ssize_t len;
01081   const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
01082                                                 conn->host.name;
01083   const char * const dispname = SSL_IS_PROXY()?
01084                                   conn->http_proxy.host.dispname:
01085                                   conn->host.dispname;
01086 #ifdef ENABLE_IPV6
01087   struct in6_addr addr;
01088 #else
01089   struct in_addr addr;
01090 #endif
01091 
01092   /* Verify that connection server matches info in X509 certificate at
01093      `beg'..`end'. */
01094 
01095   if(!SSL_CONN_CONFIG(verifyhost))
01096     return CURLE_OK;
01097 
01098   if(Curl_parseX509(&cert, beg, end))
01099     return CURLE_PEER_FAILED_VERIFICATION;
01100 
01101   /* Get the server IP address. */
01102 #ifdef ENABLE_IPV6
01103   if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
01104     addrlen = sizeof(struct in6_addr);
01105   else
01106 #endif
01107   if(Curl_inet_pton(AF_INET, hostname, &addr))
01108     addrlen = sizeof(struct in_addr);
01109 
01110   /* Process extensions. */
01111   for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
01112     p = Curl_getASN1Element(&ext, p, cert.extensions.end);
01113     /* Check if extension is a subjectAlternativeName. */
01114     ext.beg = checkOID(ext.beg, ext.end, sanOID);
01115     if(ext.beg) {
01116       ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
01117       /* Skip critical if present. */
01118       if(elem.tag == CURL_ASN1_BOOLEAN)
01119         ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
01120       /* Parse the octet string contents: is a single sequence. */
01121       Curl_getASN1Element(&elem, elem.beg, elem.end);
01122       /* Check all GeneralNames. */
01123       for(q = elem.beg; matched != 1 && q < elem.end;) {
01124         q = Curl_getASN1Element(&name, q, elem.end);
01125         switch(name.tag) {
01126         case 2: /* DNS name. */
01127           len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
01128                             name.beg, name.end);
01129           if(len > 0 && (size_t)len == strlen(dnsname))
01130             matched = Curl_cert_hostcheck(dnsname, hostname);
01131           else
01132             matched = 0;
01133           free(dnsname);
01134           break;
01135 
01136         case 7: /* IP address. */
01137           matched = (size_t) (name.end - q) == addrlen &&
01138                     !memcmp(&addr, q, addrlen);
01139           break;
01140         }
01141       }
01142     }
01143   }
01144 
01145   switch(matched) {
01146   case 1:
01147     /* an alternative name matched the server hostname */
01148     infof(data, "\t subjectAltName: %s matched\n", dispname);
01149     return CURLE_OK;
01150   case 0:
01151     /* an alternative name field existed, but didn't match and then
01152        we MUST fail */
01153     infof(data, "\t subjectAltName does not match %s\n", dispname);
01154     return CURLE_PEER_FAILED_VERIFICATION;
01155   }
01156 
01157   /* Process subject. */
01158   name.header = NULL;
01159   name.beg = name.end = "";
01160   q = cert.subject.beg;
01161   /* we have to look to the last occurrence of a commonName in the
01162      distinguished one to get the most significant one. */
01163   while(q < cert.subject.end) {
01164     q = Curl_getASN1Element(&dn, q, cert.subject.end);
01165     for(p = dn.beg; p < dn.end;) {
01166       p = Curl_getASN1Element(&elem, p, dn.end);
01167       /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
01168       elem.beg = checkOID(elem.beg, elem.end, cnOID);
01169       if(elem.beg)
01170         name = elem;    /* Latch CN. */
01171     }
01172   }
01173 
01174   /* Check the CN if found. */
01175   if(!Curl_getASN1Element(&elem, name.beg, name.end))
01176     failf(data, "SSL: unable to obtain common name from peer certificate");
01177   else {
01178     len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
01179     if(len < 0) {
01180       free(dnsname);
01181       return CURLE_OUT_OF_MEMORY;
01182     }
01183     if(strlen(dnsname) != (size_t) len)         /* Nul byte in string ? */
01184       failf(data, "SSL: illegal cert name field");
01185     else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
01186       infof(data, "\t common name: %s (matched)\n", dnsname);
01187       free(dnsname);
01188       return CURLE_OK;
01189     }
01190     else
01191       failf(data, "SSL: certificate subject name '%s' does not match "
01192             "target host name '%s'", dnsname, dispname);
01193     free(dnsname);
01194   }
01195 
01196   return CURLE_PEER_FAILED_VERIFICATION;
01197 }
01198 
01199 #endif /* USE_GSKIT */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:07