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 /* FALLTHROUGH */ 470 case 1: 471 sec2 = fracp[-1]; 472 break; 473 default: 474 return (const char *) NULL; 475 } 476 477 /* Scan for timezone, measure fractional seconds. */ 478 tzp = fracp; 479 fracl = 0; 480 if(fracp < end && (*fracp == '.' || *fracp == ',')) { 481 fracp++; 482 do 483 tzp++; 484 while(tzp < end && *tzp >= '0' && *tzp <= '9'); 485 /* Strip leading zeroes in fractional seconds. */ 486 for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--) 487 ; 488 } 489 490 /* Process timezone. */ 491 if(tzp >= end) 492 ; /* Nothing to do. */ 493 else if(*tzp == 'Z') { 494 tzp = " GMT"; 495 end = tzp + 4; 496 } 497 else { 498 sep = " "; 499 tzp++; 500 } 501 502 tzl = end - tzp; 503 return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", 504 beg, beg + 4, beg + 6, 505 beg + 8, beg + 10, sec1, sec2, 506 fracl? ".": "", fracl, fracp, 507 sep, tzl, tzp); 508 } 509 510 static const char *UTime2str(const char *beg, const char *end) 511 { 512 const char *tzp; 513 size_t tzl; 514 const char *sec; 515 516 /* Convert an ASN.1 UTC time to a printable string. 517 Return the dynamically allocated string, or NULL if an error occurs. */ 518 519 for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++) 520 ; 521 /* Get the seconds. */ 522 sec = beg + 10; 523 switch(tzp - sec) { 524 case 0: 525 sec = "00"; 526 case 2: 527 break; 528 default: 529 return (const char *) NULL; 530 } 531 532 /* Process timezone. */ 533 if(tzp >= end) 534 return (const char *) NULL; 535 if(*tzp == 'Z') { 536 tzp = "GMT"; 537 end = tzp + 3; 538 } 539 else 540 tzp++; 541 542 tzl = end - tzp; 543 return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", 544 20 - (*beg >= '5'), beg, beg + 2, beg + 4, 545 beg + 6, beg + 8, sec, 546 tzl, tzp); 547 } 548 549 const char *Curl_ASN1tostr(curl_asn1Element *elem, int type) 550 { 551 /* Convert an ASN.1 element to a printable string. 552 Return the dynamically allocated string, or NULL if an error occurs. */ 553 554 if(elem->constructed) 555 return (const char *) NULL; /* No conversion of structured elements. */ 556 557 if(!type) 558 type = elem->tag; /* Type not forced: use element tag as type. */ 559 560 switch(type) { 561 case CURL_ASN1_BOOLEAN: 562 return bool2str(elem->beg, elem->end); 563 case CURL_ASN1_INTEGER: 564 case CURL_ASN1_ENUMERATED: 565 return int2str(elem->beg, elem->end); 566 case CURL_ASN1_BIT_STRING: 567 return bit2str(elem->beg, elem->end); 568 case CURL_ASN1_OCTET_STRING: 569 return octet2str(elem->beg, elem->end); 570 case CURL_ASN1_NULL: 571 return strdup(""); 572 case CURL_ASN1_OBJECT_IDENTIFIER: 573 return OID2str(elem->beg, elem->end, TRUE); 574 case CURL_ASN1_UTC_TIME: 575 return UTime2str(elem->beg, elem->end); 576 case CURL_ASN1_GENERALIZED_TIME: 577 return GTime2str(elem->beg, elem->end); 578 case CURL_ASN1_UTF8_STRING: 579 case CURL_ASN1_NUMERIC_STRING: 580 case CURL_ASN1_PRINTABLE_STRING: 581 case CURL_ASN1_TELETEX_STRING: 582 case CURL_ASN1_IA5_STRING: 583 case CURL_ASN1_VISIBLE_STRING: 584 case CURL_ASN1_UNIVERSAL_STRING: 585 case CURL_ASN1_BMP_STRING: 586 return string2str(type, elem->beg, elem->end); 587 } 588 589 return (const char *) NULL; /* Unsupported. */ 590 } 591 592 static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn) 593 { 594 curl_asn1Element rdn; 595 curl_asn1Element atv; 596 curl_asn1Element oid; 597 curl_asn1Element value; 598 size_t l = 0; 599 const char *p1; 600 const char *p2; 601 const char *p3; 602 const char *str; 603 604 /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'. 605 Return the total string length, even if larger than `n'. */ 606 607 for(p1 = dn->beg; p1 < dn->end;) { 608 p1 = Curl_getASN1Element(&rdn, p1, dn->end); 609 for(p2 = rdn.beg; p2 < rdn.end;) { 610 p2 = Curl_getASN1Element(&atv, p2, rdn.end); 611 p3 = Curl_getASN1Element(&oid, atv.beg, atv.end); 612 Curl_getASN1Element(&value, p3, atv.end); 613 str = Curl_ASN1tostr(&oid, 0); 614 if(!str) 615 return -1; 616 617 /* Encode delimiter. 618 If attribute has a short uppercase name, delimiter is ", ". */ 619 if(l) { 620 for(p3 = str; isupper(*p3); p3++) 621 ; 622 for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { 623 if(l < n) 624 buf[l] = *p3; 625 l++; 626 } 627 } 628 629 /* Encode attribute name. */ 630 for(p3 = str; *p3; p3++) { 631 if(l < n) 632 buf[l] = *p3; 633 l++; 634 } 635 free((char *) str); 636 637 /* Generate equal sign. */ 638 if(l < n) 639 buf[l] = '='; 640 l++; 641 642 /* Generate value. */ 643 str = Curl_ASN1tostr(&value, 0); 644 if(!str) 645 return -1; 646 for(p3 = str; *p3; p3++) { 647 if(l < n) 648 buf[l] = *p3; 649 l++; 650 } 651 free((char *) str); 652 } 653 } 654 655 return l; 656 } 657 658 const char *Curl_DNtostr(curl_asn1Element *dn) 659 { 660 char *buf = (char *) NULL; 661 ssize_t n = encodeDN(buf, 0, dn); 662 663 /* Convert an ASN.1 distinguished name into a printable string. 664 Return the dynamically allocated string, or NULL if an error occurs. */ 665 666 if(n >= 0) { 667 buf = malloc(n + 1); 668 if(buf) { 669 encodeDN(buf, n + 1, dn); 670 buf[n] = '\0'; 671 } 672 } 673 return (const char *) buf; 674 } 675 676 /* 677 * X509 parser. 678 */ 679 680 int Curl_parseX509(curl_X509certificate *cert, 681 const char *beg, const char *end) 682 { 683 curl_asn1Element elem; 684 curl_asn1Element tbsCertificate; 685 const char *ccp; 686 static const char defaultVersion = 0; /* v1. */ 687 688 /* ASN.1 parse an X509 certificate into structure subfields. 689 Syntax is assumed to have already been checked by the SSL backend. 690 See RFC 5280. */ 691 692 cert->certificate.header = NULL; 693 cert->certificate.beg = beg; 694 cert->certificate.end = end; 695 696 /* Get the sequence content. */ 697 if(!Curl_getASN1Element(&elem, beg, end)) 698 return -1; /* Invalid bounds/size. */ 699 beg = elem.beg; 700 end = elem.end; 701 702 /* Get tbsCertificate. */ 703 beg = Curl_getASN1Element(&tbsCertificate, beg, end); 704 /* Skip the signatureAlgorithm. */ 705 beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); 706 /* Get the signatureValue. */ 707 Curl_getASN1Element(&cert->signature, beg, end); 708 709 /* Parse TBSCertificate. */ 710 beg = tbsCertificate.beg; 711 end = tbsCertificate.end; 712 /* Get optional version, get serialNumber. */ 713 cert->version.header = NULL; 714 cert->version.beg = &defaultVersion; 715 cert->version.end = &defaultVersion + sizeof defaultVersion;; 716 beg = Curl_getASN1Element(&elem, beg, end); 717 if(elem.tag == 0) { 718 Curl_getASN1Element(&cert->version, elem.beg, elem.end); 719 beg = Curl_getASN1Element(&elem, beg, end); 720 } 721 cert->serialNumber = elem; 722 /* Get signature algorithm. */ 723 beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); 724 /* Get issuer. */ 725 beg = Curl_getASN1Element(&cert->issuer, beg, end); 726 /* Get notBefore and notAfter. */ 727 beg = Curl_getASN1Element(&elem, beg, end); 728 ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end); 729 Curl_getASN1Element(&cert->notAfter, ccp, elem.end); 730 /* Get subject. */ 731 beg = Curl_getASN1Element(&cert->subject, beg, end); 732 /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ 733 beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end); 734 ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm, 735 cert->subjectPublicKeyInfo.beg, 736 cert->subjectPublicKeyInfo.end); 737 Curl_getASN1Element(&cert->subjectPublicKey, ccp, 738 cert->subjectPublicKeyInfo.end); 739 /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ 740 cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; 741 cert->extensions.tag = elem.tag = 0; 742 cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; 743 cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; 744 cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; 745 cert->extensions.header = NULL; 746 cert->extensions.beg = cert->extensions.end = ""; 747 if(beg < end) 748 beg = Curl_getASN1Element(&elem, beg, end); 749 if(elem.tag == 1) { 750 cert->issuerUniqueID = elem; 751 if(beg < end) 752 beg = Curl_getASN1Element(&elem, beg, end); 753 } 754 if(elem.tag == 2) { 755 cert->subjectUniqueID = elem; 756 if(beg < end) 757 beg = Curl_getASN1Element(&elem, beg, end); 758 } 759 if(elem.tag == 3) 760 Curl_getASN1Element(&cert->extensions, elem.beg, elem.end); 761 return 0; 762 } 763 764 static size_t copySubstring(char *to, const char *from) 765 { 766 size_t i; 767 768 /* Copy at most 64-characters, terminate with a newline and returns the 769 effective number of stored characters. */ 770 771 for(i = 0; i < 64; i++) { 772 to[i] = *from; 773 if(!*from++) 774 break; 775 } 776 777 to[i++] = '\n'; 778 return i; 779 } 780 781 static const char *dumpAlgo(curl_asn1Element *param, 782 const char *beg, const char *end) 783 { 784 curl_asn1Element oid; 785 786 /* Get algorithm parameters and return algorithm name. */ 787 788 beg = Curl_getASN1Element(&oid, beg, end); 789 param->header = NULL; 790 param->tag = 0; 791 param->beg = param->end = end; 792 if(beg < end) 793 Curl_getASN1Element(param, beg, end); 794 return OID2str(oid.beg, oid.end, TRUE); 795 } 796 797 static void do_pubkey_field(struct Curl_easy *data, int certnum, 798 const char *label, curl_asn1Element *elem) 799 { 800 const char *output; 801 802 /* Generate a certificate information record for the public key. */ 803 804 output = Curl_ASN1tostr(elem, 0); 805 if(output) { 806 if(data->set.ssl.certinfo) 807 Curl_ssl_push_certinfo(data, certnum, label, output); 808 if(!certnum) 809 infof(data, " %s: %s\n", label, output); 810 free((char *) output); 811 } 812 } 813 814 static void do_pubkey(struct Curl_easy *data, int certnum, 815 const char *algo, curl_asn1Element *param, 816 curl_asn1Element *pubkey) 817 { 818 curl_asn1Element elem; 819 curl_asn1Element pk; 820 const char *p; 821 const char *q; 822 unsigned long len; 823 unsigned int i; 824 825 /* Generate all information records for the public key. */ 826 827 /* Get the public key (single element). */ 828 Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); 829 830 if(strcasecompare(algo, "rsaEncryption")) { 831 p = Curl_getASN1Element(&elem, pk.beg, pk.end); 832 /* Compute key length. */ 833 for(q = elem.beg; !*q && q < elem.end; q++) 834 ; 835 len = (unsigned long)((elem.end - q) * 8); 836 if(len) 837 for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) 838 len--; 839 if(len > 32) 840 elem.beg = q; /* Strip leading zero bytes. */ 841 if(!certnum) 842 infof(data, " RSA Public Key (%lu bits)\n", len); 843 if(data->set.ssl.certinfo) { 844 q = curl_maprintf("%lu", len); 845 if(q) { 846 Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); 847 free((char *) q); 848 } 849 } 850 /* Generate coefficients. */ 851 do_pubkey_field(data, certnum, "rsa(n)", &elem); 852 Curl_getASN1Element(&elem, p, pk.end); 853 do_pubkey_field(data, certnum, "rsa(e)", &elem); 854 } 855 else if(strcasecompare(algo, "dsa")) { 856 p = Curl_getASN1Element(&elem, param->beg, param->end); 857 do_pubkey_field(data, certnum, "dsa(p)", &elem); 858 p = Curl_getASN1Element(&elem, p, param->end); 859 do_pubkey_field(data, certnum, "dsa(q)", &elem); 860 Curl_getASN1Element(&elem, p, param->end); 861 do_pubkey_field(data, certnum, "dsa(g)", &elem); 862 do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); 863 } 864 else if(strcasecompare(algo, "dhpublicnumber")) { 865 p = Curl_getASN1Element(&elem, param->beg, param->end); 866 do_pubkey_field(data, certnum, "dh(p)", &elem); 867 Curl_getASN1Element(&elem, param->beg, param->end); 868 do_pubkey_field(data, certnum, "dh(g)", &elem); 869 do_pubkey_field(data, certnum, "dh(pub_key)", &pk); 870 } 871 #if 0 /* Patent-encumbered. */ 872 else if(strcasecompare(algo, "ecPublicKey")) { 873 /* Left TODO. */ 874 } 875 #endif 876 } 877 878 CURLcode Curl_extract_certinfo(struct connectdata *conn, 879 int certnum, 880 const char *beg, 881 const char *end) 882 { 883 curl_X509certificate cert; 884 struct Curl_easy *data = conn->data; 885 curl_asn1Element param; 886 const char *ccp; 887 char *cp1; 888 size_t cl1; 889 char *cp2; 890 CURLcode result; 891 unsigned long version; 892 size_t i; 893 size_t j; 894 895 if(!data->set.ssl.certinfo) 896 if(certnum) 897 return CURLE_OK; 898 899 /* Prepare the certificate information for curl_easy_getinfo(). */ 900 901 /* Extract the certificate ASN.1 elements. */ 902 if(Curl_parseX509(&cert, beg, end)) 903 return CURLE_OUT_OF_MEMORY; 904 905 /* Subject. */ 906 ccp = Curl_DNtostr(&cert.subject); 907 if(!ccp) 908 return CURLE_OUT_OF_MEMORY; 909 if(data->set.ssl.certinfo) 910 Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); 911 if(!certnum) 912 infof(data, "%2d Subject: %s\n", certnum, ccp); 913 free((char *) ccp); 914 915 /* Issuer. */ 916 ccp = Curl_DNtostr(&cert.issuer); 917 if(!ccp) 918 return CURLE_OUT_OF_MEMORY; 919 if(data->set.ssl.certinfo) 920 Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); 921 if(!certnum) 922 infof(data, " Issuer: %s\n", ccp); 923 free((char *) ccp); 924 925 /* Version (always fits in less than 32 bits). */ 926 version = 0; 927 for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) 928 version = (version << 8) | *(const unsigned char *) ccp; 929 if(data->set.ssl.certinfo) { 930 ccp = curl_maprintf("%lx", version); 931 if(!ccp) 932 return CURLE_OUT_OF_MEMORY; 933 Curl_ssl_push_certinfo(data, certnum, "Version", ccp); 934 free((char *) ccp); 935 } 936 if(!certnum) 937 infof(data, " Version: %lu (0x%lx)\n", version + 1, version); 938 939 /* Serial number. */ 940 ccp = Curl_ASN1tostr(&cert.serialNumber, 0); 941 if(!ccp) 942 return CURLE_OUT_OF_MEMORY; 943 if(data->set.ssl.certinfo) 944 Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); 945 if(!certnum) 946 infof(data, " Serial Number: %s\n", ccp); 947 free((char *) ccp); 948 949 /* Signature algorithm .*/ 950 ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, 951 cert.signatureAlgorithm.end); 952 if(!ccp) 953 return CURLE_OUT_OF_MEMORY; 954 if(data->set.ssl.certinfo) 955 Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); 956 if(!certnum) 957 infof(data, " Signature Algorithm: %s\n", ccp); 958 free((char *) ccp); 959 960 /* Start Date. */ 961 ccp = Curl_ASN1tostr(&cert.notBefore, 0); 962 if(!ccp) 963 return CURLE_OUT_OF_MEMORY; 964 if(data->set.ssl.certinfo) 965 Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); 966 if(!certnum) 967 infof(data, " Start Date: %s\n", ccp); 968 free((char *) ccp); 969 970 /* Expire Date. */ 971 ccp = Curl_ASN1tostr(&cert.notAfter, 0); 972 if(!ccp) 973 return CURLE_OUT_OF_MEMORY; 974 if(data->set.ssl.certinfo) 975 Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); 976 if(!certnum) 977 infof(data, " Expire Date: %s\n", ccp); 978 free((char *) ccp); 979 980 /* Public Key Algorithm. */ 981 ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, 982 cert.subjectPublicKeyAlgorithm.end); 983 if(!ccp) 984 return CURLE_OUT_OF_MEMORY; 985 if(data->set.ssl.certinfo) 986 Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp); 987 if(!certnum) 988 infof(data, " Public Key Algorithm: %s\n", ccp); 989 do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); 990 free((char *) ccp); 991 992 /* TODO: extensions. */ 993 994 /* Signature. */ 995 ccp = Curl_ASN1tostr(&cert.signature, 0); 996 if(!ccp) 997 return CURLE_OUT_OF_MEMORY; 998 if(data->set.ssl.certinfo) 999 Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); 1000 if(!certnum) 1001 infof(data, " Signature: %s\n", ccp); 1002 free((char *) ccp); 1003 1004 /* Generate PEM certificate. */ 1005 result = Curl_base64_encode(data, cert.certificate.beg, 1006 cert.certificate.end - cert.certificate.beg, 1007 &cp1, &cl1); 1008 if(result) 1009 return result; 1010 /* Compute the number of characters in final certificate string. Format is: 1011 -----BEGIN CERTIFICATE-----\n 1012 <max 64 base64 characters>\n 1013 . 1014 . 1015 . 1016 -----END CERTIFICATE-----\n 1017 */ 1018 i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26; 1019 cp2 = malloc(i + 1); 1020 if(!cp2) { 1021 free(cp1); 1022 return CURLE_OUT_OF_MEMORY; 1023 } 1024 /* Build the certificate string. */ 1025 i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----"); 1026 for(j = 0; j < cl1; j += 64) 1027 i += copySubstring(cp2 + i, cp1 + j); 1028 i += copySubstring(cp2 + i, "-----END CERTIFICATE-----"); 1029 cp2[i] = '\0'; 1030 free(cp1); 1031 if(data->set.ssl.certinfo) 1032 Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); 1033 if(!certnum) 1034 infof(data, "%s\n", cp2); 1035 free(cp2); 1036 return CURLE_OK; 1037 } 1038 1039 #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ 1040 1041 #if defined(USE_GSKIT) 1042 1043 static const char *checkOID(const char *beg, const char *end, 1044 const char *oid) 1045 { 1046 curl_asn1Element e; 1047 const char *ccp; 1048 const char *p; 1049 bool matched; 1050 1051 /* Check if first ASN.1 element at `beg' is the given OID. 1052 Return a pointer in the source after the OID if found, else NULL. */ 1053 1054 ccp = Curl_getASN1Element(&e, beg, end); 1055 if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER) 1056 return (const char *) NULL; 1057 1058 p = OID2str(e.beg, e.end, FALSE); 1059 if(!p) 1060 return (const char *) NULL; 1061 1062 matched = !strcmp(p, oid); 1063 free((char *) p); 1064 return matched? ccp: (const char *) NULL; 1065 } 1066 1067 CURLcode Curl_verifyhost(struct connectdata *conn, 1068 const char *beg, const char *end) 1069 { 1070 struct Curl_easy *data = conn->data; 1071 curl_X509certificate cert; 1072 curl_asn1Element dn; 1073 curl_asn1Element elem; 1074 curl_asn1Element ext; 1075 curl_asn1Element name; 1076 const char *p; 1077 const char *q; 1078 char *dnsname; 1079 int matched = -1; 1080 size_t addrlen = (size_t) -1; 1081 ssize_t len; 1082 const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: 1083 conn->host.name; 1084 const char * const dispname = SSL_IS_PROXY()? 1085 conn->http_proxy.host.dispname: 1086 conn->host.dispname; 1087 #ifdef ENABLE_IPV6 1088 struct in6_addr addr; 1089 #else 1090 struct in_addr addr; 1091 #endif 1092 1093 /* Verify that connection server matches info in X509 certificate at 1094 `beg'..`end'. */ 1095 1096 if(!SSL_CONN_CONFIG(verifyhost)) 1097 return CURLE_OK; 1098 1099 if(Curl_parseX509(&cert, beg, end)) 1100 return CURLE_PEER_FAILED_VERIFICATION; 1101 1102 /* Get the server IP address. */ 1103 #ifdef ENABLE_IPV6 1104 if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr)) 1105 addrlen = sizeof(struct in6_addr); 1106 else 1107 #endif 1108 if(Curl_inet_pton(AF_INET, hostname, &addr)) 1109 addrlen = sizeof(struct in_addr); 1110 1111 /* Process extensions. */ 1112 for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) { 1113 p = Curl_getASN1Element(&ext, p, cert.extensions.end); 1114 /* Check if extension is a subjectAlternativeName. */ 1115 ext.beg = checkOID(ext.beg, ext.end, sanOID); 1116 if(ext.beg) { 1117 ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); 1118 /* Skip critical if present. */ 1119 if(elem.tag == CURL_ASN1_BOOLEAN) 1120 ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); 1121 /* Parse the octet string contents: is a single sequence. */ 1122 Curl_getASN1Element(&elem, elem.beg, elem.end); 1123 /* Check all GeneralNames. */ 1124 for(q = elem.beg; matched != 1 && q < elem.end;) { 1125 q = Curl_getASN1Element(&name, q, elem.end); 1126 switch(name.tag) { 1127 case 2: /* DNS name. */ 1128 len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, 1129 name.beg, name.end); 1130 if(len > 0 && (size_t)len == strlen(dnsname)) 1131 matched = Curl_cert_hostcheck(dnsname, hostname); 1132 else 1133 matched = 0; 1134 free(dnsname); 1135 break; 1136 1137 case 7: /* IP address. */ 1138 matched = (size_t) (name.end - q) == addrlen && 1139 !memcmp(&addr, q, addrlen); 1140 break; 1141 } 1142 } 1143 } 1144 } 1145 1146 switch(matched) { 1147 case 1: 1148 /* an alternative name matched the server hostname */ 1149 infof(data, "\t subjectAltName: %s matched\n", dispname); 1150 return CURLE_OK; 1151 case 0: 1152 /* an alternative name field existed, but didn't match and then 1153 we MUST fail */ 1154 infof(data, "\t subjectAltName does not match %s\n", dispname); 1155 return CURLE_PEER_FAILED_VERIFICATION; 1156 } 1157 1158 /* Process subject. */ 1159 name.header = NULL; 1160 name.beg = name.end = ""; 1161 q = cert.subject.beg; 1162 /* we have to look to the last occurrence of a commonName in the 1163 distinguished one to get the most significant one. */ 1164 while(q < cert.subject.end) { 1165 q = Curl_getASN1Element(&dn, q, cert.subject.end); 1166 for(p = dn.beg; p < dn.end;) { 1167 p = Curl_getASN1Element(&elem, p, dn.end); 1168 /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */ 1169 elem.beg = checkOID(elem.beg, elem.end, cnOID); 1170 if(elem.beg) 1171 name = elem; /* Latch CN. */ 1172 } 1173 } 1174 1175 /* Check the CN if found. */ 1176 if(!Curl_getASN1Element(&elem, name.beg, name.end)) 1177 failf(data, "SSL: unable to obtain common name from peer certificate"); 1178 else { 1179 len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); 1180 if(len < 0) { 1181 free(dnsname); 1182 return CURLE_OUT_OF_MEMORY; 1183 } 1184 if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ 1185 failf(data, "SSL: illegal cert name field"); 1186 else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) { 1187 infof(data, "\t common name: %s (matched)\n", dnsname); 1188 free(dnsname); 1189 return CURLE_OK; 1190 } 1191 else 1192 failf(data, "SSL: certificate subject name '%s' does not match " 1193 "target host name '%s'", dnsname, dispname); 1194 free(dnsname); 1195 } 1196 1197 return CURLE_PEER_FAILED_VERIFICATION; 1198 } 1199 1200 #endif /* USE_GSKIT */ 1201