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