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(¶m, 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(¶m, 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, ¶m, &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>