Annotation of embedaddon/curl/lib/x509asn1.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>