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