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