1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at 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_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS) 26 27#include <curl/curl.h> 28#include "urldata.h" 29#include "strequal.h" 30#include "hostcheck.h" 31#include "vtls/vtls.h" 32#include "sendf.h" 33#include "inet_pton.h" 34#include "curl_base64.h" 35#include "x509asn1.h" 36 37#define _MPRINTF_REPLACE /* use our functions only */ 38#include <curl/mprintf.h> 39 40#include "curl_memory.h" 41/* The last #include file should be: */ 42#include "memdebug.h" 43 44 45/* ASN.1 OIDs. */ 46static const char cnOID[] = "2.5.4.3"; /* Common name. */ 47static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */ 48 49static const curl_OID OIDtable[] = { 50 { "1.2.840.10040.4.1", "dsa" }, 51 { "1.2.840.10040.4.3", "dsa-with-sha1" }, 52 { "1.2.840.10045.2.1", "ecPublicKey" }, 53 { "1.2.840.10045.3.0.1", "c2pnb163v1" }, 54 { "1.2.840.10045.4.1", "ecdsa-with-SHA1" }, 55 { "1.2.840.10046.2.1", "dhpublicnumber" }, 56 { "1.2.840.113549.1.1.1", "rsaEncryption" }, 57 { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" }, 58 { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" }, 59 { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" }, 60 { "1.2.840.113549.1.1.10", "RSASSA-PSS" }, 61 { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" }, 62 { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" }, 63 { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" }, 64 { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" }, 65 { "1.2.840.113549.2.2", "md2" }, 66 { "1.2.840.113549.2.5", "md5" }, 67 { "1.3.14.3.2.26", "sha1" }, 68 { cnOID, "CN" }, 69 { "2.5.4.4", "SN" }, 70 { "2.5.4.5", "serialNumber" }, 71 { "2.5.4.6", "C" }, 72 { "2.5.4.7", "L" }, 73 { "2.5.4.8", "ST" }, 74 { "2.5.4.9", "streetAddress" }, 75 { "2.5.4.10", "O" }, 76 { "2.5.4.11", "OU" }, 77 { "2.5.4.12", "title" }, 78 { "2.5.4.13", "description" }, 79 { "2.5.4.17", "postalCode" }, 80 { "2.5.4.41", "name" }, 81 { "2.5.4.42", "givenName" }, 82 { "2.5.4.43", "initials" }, 83 { "2.5.4.44", "generationQualifier" }, 84 { "2.5.4.45", "X500UniqueIdentifier" }, 85 { "2.5.4.46", "dnQualifier" }, 86 { "2.5.4.65", "pseudonym" }, 87 { "1.2.840.113549.1.9.1", "emailAddress" }, 88 { "2.5.4.72", "role" }, 89 { sanOID, "subjectAltName" }, 90 { "2.5.29.18", "issuerAltName" }, 91 { "2.5.29.19", "basicConstraints" }, 92 { "2.16.840.1.101.3.4.2.4", "sha224" }, 93 { "2.16.840.1.101.3.4.2.1", "sha256" }, 94 { "2.16.840.1.101.3.4.2.2", "sha384" }, 95 { "2.16.840.1.101.3.4.2.3", "sha512" }, 96 { (const char *) NULL, (const char *) NULL } 97}; 98 99/* 100 * Lightweight ASN.1 parser. 101 * In particular, it does not check for syntactic/lexical errors. 102 * It is intended to support certificate information gathering for SSL backends 103 * that offer a mean to get certificates as a whole, but do not supply 104 * entry points to get particular certificate sub-fields. 105 * Please note there is no pretention here to rewrite a full SSL library. 106 */ 107 108 109const char * Curl_getASN1Element(curl_asn1Element * elem, 110 const char * beg, const char * end) 111{ 112 unsigned char b; 113 unsigned long len; 114 curl_asn1Element lelem; 115 116 /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' 117 ending at `end'. 118 Returns a pointer in source string after the parsed element, or NULL 119 if an error occurs. */ 120 121 if(beg >= end || !*beg) 122 return (const char *) NULL; 123 124 /* Process header byte. */ 125 b = (unsigned char) *beg++; 126 elem->constructed = (b & 0x20) != 0; 127 elem->class = (b >> 6) & 3; 128 b &= 0x1F; 129 if(b == 0x1F) 130 return (const char *) NULL; /* Long tag values not supported here. */ 131 elem->tag = b; 132 133 /* Process length. */ 134 if(beg >= end) 135 return (const char *) NULL; 136 b = (unsigned char) *beg++; 137 if(!(b & 0x80)) 138 len = b; 139 else if(!(b &= 0x7F)) { 140 /* Unspecified length. Since we have all the data, we can determine the 141 effective length by skipping element until an end element is found. */ 142 if(!elem->constructed) 143 return (const char *) NULL; 144 elem->beg = beg; 145 while(beg < end && *beg) { 146 beg = Curl_getASN1Element(&lelem, beg, end); 147 if(!beg) 148 return (const char *) NULL; 149 } 150 if(beg >= end) 151 return (const char *) NULL; 152 elem->end = beg; 153 return beg + 1; 154 } 155 else if(beg + b > end) 156 return (const char *) NULL; /* Does not fit in source. */ 157 else { 158 /* Get long length. */ 159 len = 0; 160 do { 161 if(len & 0xFF000000L) 162 return (const char *) NULL; /* Lengths > 32 bits are not supported. */ 163 len = (len << 8) | (unsigned char) *beg++; 164 } while(--b); 165 } 166 if((unsigned long) (end - beg) < len) 167 return (const char *) NULL; /* Element data does not fit in source. */ 168 elem->beg = beg; 169 elem->end = beg + len; 170 return elem->end; 171} 172 173static const curl_OID * searchOID(const char * oid) 174{ 175 const curl_OID * op; 176 177 /* Search the null terminated OID or OID identifier in local table. 178 Return the table entry pointer or NULL if not found. */ 179 180 for(op = OIDtable; op->numoid; op++) 181 if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid)) 182 return op; 183 184 return (const curl_OID *) NULL; 185} 186 187static const char * bool2str(const char * beg, const char * end) 188{ 189 /* Convert an ASN.1 Boolean value into its string representation. 190 Return the dynamically allocated string, or NULL if source is not an 191 ASN.1 Boolean value. */ 192 193 if(end - beg != 1) 194 return (const char *) NULL; 195 return strdup(*beg? "TRUE": "FALSE"); 196} 197 198static const char * octet2str(const char * beg, const char * end) 199{ 200 size_t n = end - beg; 201 char * buf; 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 buf = malloc(3 * n + 1); 207 if(buf) 208 for(n = 0; beg < end; n += 3) 209 snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); 210 return buf; 211} 212 213static const char * bit2str(const char * beg, const char * end) 214 215{ 216 /* Convert an ASN.1 bit string to a printable string. 217 Return the dynamically allocated string, or NULL if an error occurs. */ 218 219 if(++beg > end) 220 return (const char *) NULL; 221 return octet2str(beg, end); 222} 223 224static const char * int2str(const char * beg, const char * end) 225{ 226 long val = 0; 227 size_t n = end - beg; 228 229 /* Convert an ASN.1 integer value into its string representation. 230 Return the dynamically allocated string, or NULL if source is not an 231 ASN.1 integer value. */ 232 233 if(!n) 234 return (const char *) NULL; 235 236 if(n > 4) 237 return octet2str(beg, end); 238 239 /* Represent integers <= 32-bit as a single value. */ 240 if(*beg & 0x80) 241 val = ~val; 242 243 do 244 val = (val << 8) | *(const unsigned char *) beg++; 245 while(beg < end); 246 return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val); 247} 248 249static ssize_t 250utf8asn1str(char * * to, int type, const char * from, const char * end) 251{ 252 size_t inlength = end - from; 253 int size = 1; 254 size_t outlength; 255 int charsize; 256 unsigned int wc; 257 char * buf; 258 259 /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the 260 destination buffer dynamically. The allocation size will normally be too 261 large: this is to avoid buffer overflows. 262 Terminate the string with a nul byte and return the converted 263 string length. */ 264 265 *to = (char *) NULL; 266 switch (type) { 267 case CURL_ASN1_BMP_STRING: 268 size = 2; 269 break; 270 case CURL_ASN1_UNIVERSAL_STRING: 271 size = 4; 272 break; 273 case CURL_ASN1_NUMERIC_STRING: 274 case CURL_ASN1_PRINTABLE_STRING: 275 case CURL_ASN1_TELETEX_STRING: 276 case CURL_ASN1_IA5_STRING: 277 case CURL_ASN1_VISIBLE_STRING: 278 case CURL_ASN1_UTF8_STRING: 279 break; 280 default: 281 return -1; /* Conversion not supported. */ 282 } 283 284 if(inlength % size) 285 return -1; /* Length inconsistent with character size. */ 286 buf = malloc(4 * (inlength / size) + 1); 287 if(!buf) 288 return -1; /* Not enough memory. */ 289 290 if(type == CURL_ASN1_UTF8_STRING) { 291 /* Just copy. */ 292 outlength = inlength; 293 if(outlength) 294 memcpy(buf, from, outlength); 295 } 296 else { 297 for(outlength = 0; from < end;) { 298 wc = 0; 299 switch (size) { 300 case 4: 301 wc = (wc << 8) | *(const unsigned char *) from++; 302 wc = (wc << 8) | *(const unsigned char *) from++; 303 case 2: 304 wc = (wc << 8) | *(const unsigned char *) from++; 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 337static 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 349static 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 369static 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 408static 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 438static 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 501static 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 540const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) 541{ 542 static const char zero = '\0'; 543 544 /* Convert an ASN.1 element to a printable string. 545 Return the dynamically allocated string, or NULL if an error occurs. */ 546 547 if(elem->constructed) 548 return (const char *) NULL; /* No conversion of structured elements. */ 549 550 if(!type) 551 type = elem->tag; /* Type not forced: use element tag as type. */ 552 553 switch (type) { 554 case CURL_ASN1_BOOLEAN: 555 return bool2str(elem->beg, elem->end); 556 case CURL_ASN1_INTEGER: 557 case CURL_ASN1_ENUMERATED: 558 return int2str(elem->beg, elem->end); 559 case CURL_ASN1_BIT_STRING: 560 return bit2str(elem->beg, elem->end); 561 case CURL_ASN1_OCTET_STRING: 562 return octet2str(elem->beg, elem->end); 563 case CURL_ASN1_NULL: 564 return strdup(&zero); 565 case CURL_ASN1_OBJECT_IDENTIFIER: 566 return OID2str(elem->beg, elem->end, TRUE); 567 case CURL_ASN1_UTC_TIME: 568 return UTime2str(elem->beg, elem->end); 569 case CURL_ASN1_GENERALIZED_TIME: 570 return GTime2str(elem->beg, elem->end); 571 case CURL_ASN1_UTF8_STRING: 572 case CURL_ASN1_NUMERIC_STRING: 573 case CURL_ASN1_PRINTABLE_STRING: 574 case CURL_ASN1_TELETEX_STRING: 575 case CURL_ASN1_IA5_STRING: 576 case CURL_ASN1_VISIBLE_STRING: 577 case CURL_ASN1_UNIVERSAL_STRING: 578 case CURL_ASN1_BMP_STRING: 579 return string2str(type, elem->beg, elem->end); 580 } 581 582 return (const char *) NULL; /* Unsupported. */ 583} 584 585static ssize_t encodeDN(char * buf, size_t n, curl_asn1Element * dn) 586{ 587 curl_asn1Element rdn; 588 curl_asn1Element atv; 589 curl_asn1Element oid; 590 curl_asn1Element value; 591 size_t l = 0; 592 const char * p1; 593 const char * p2; 594 const char * p3; 595 const char * str; 596 597 /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'. 598 Return the total string length, even if larger than `n'. */ 599 600 for(p1 = dn->beg; p1 < dn->end;) { 601 p1 = Curl_getASN1Element(&rdn, p1, dn->end); 602 for(p2 = rdn.beg; p2 < rdn.end;) { 603 p2 = Curl_getASN1Element(&atv, p2, rdn.end); 604 p3 = Curl_getASN1Element(&oid, atv.beg, atv.end); 605 Curl_getASN1Element(&value, p3, atv.end); 606 str = Curl_ASN1tostr(&oid, 0); 607 if(!str) 608 return -1; 609 610 /* Encode delimiter. 611 If attribute has a short uppercase name, delimiter is ", ". */ 612 if(l) { 613 for(p3 = str; isupper(*p3); p3++) 614 ; 615 for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { 616 if(l < n) 617 buf[l] = *p3; 618 l++; 619 } 620 } 621 622 /* Encode attribute name. */ 623 for(p3 = str; *p3; p3++) { 624 if(l < n) 625 buf[l] = *p3; 626 l++; 627 } 628 free((char *) str); 629 630 /* Generate equal sign. */ 631 if(l < n) 632 buf[l] = '='; 633 l++; 634 635 /* Generate value. */ 636 str = Curl_ASN1tostr(&value, 0); 637 if(!str) 638 return -1; 639 for(p3 = str; *p3; p3++) { 640 if(l < n) 641 buf[l] = *p3; 642 l++; 643 } 644 free((char *) str); 645 } 646 } 647 648 return l; 649} 650 651const char * Curl_DNtostr(curl_asn1Element * dn) 652{ 653 char * buf = (char *) NULL; 654 ssize_t n = encodeDN(buf, 0, dn); 655 656 /* Convert an ASN.1 distinguished name into a printable string. 657 Return the dynamically allocated string, or NULL if an error occurs. */ 658 659 if(n >= 0) { 660 buf = malloc(n + 1); 661 if(buf) { 662 encodeDN(buf, n + 1, dn); 663 buf[n] = '\0'; 664 } 665 } 666 return (const char *) buf; 667} 668 669/* 670 * X509 parser. 671 */ 672 673void Curl_parseX509(curl_X509certificate * cert, 674 const char * beg, const char * end) 675{ 676 curl_asn1Element elem; 677 curl_asn1Element tbsCertificate; 678 const char * ccp; 679 static const char defaultVersion = 0; /* v1. */ 680 681 /* ASN.1 parse an X509 certificate into structure subfields. 682 Syntax is assumed to have already been checked by the SSL backend. 683 See RFC 5280. */ 684 685 cert->certificate.beg = beg; 686 cert->certificate.end = end; 687 688 /* Get the sequence content. */ 689 Curl_getASN1Element(&elem, beg, end); 690 beg = elem.beg; 691 end = elem.end; 692 693 /* Get tbsCertificate. */ 694 beg = Curl_getASN1Element(&tbsCertificate, beg, end); 695 /* Skip the signatureAlgorithm. */ 696 beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); 697 /* Get the signatureValue. */ 698 Curl_getASN1Element(&cert->signature, beg, end); 699 700 /* Parse TBSCertificate. */ 701 beg = tbsCertificate.beg; 702 end = tbsCertificate.end; 703 /* Get optional version, get serialNumber. */ 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(&elem, beg, end); 724 ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm, 725 elem.beg, elem.end); 726 Curl_getASN1Element(&cert->subjectPublicKey, ccp, elem.end); 727 /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ 728 cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; 729 cert->extensions.tag = elem.tag = 0; 730 cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; 731 cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; 732 cert->extensions.beg = cert->extensions.end = ""; 733 if(beg < end) 734 beg = Curl_getASN1Element(&elem, beg, end); 735 if(elem.tag == 1) { 736 cert->issuerUniqueID = elem; 737 if(beg < end) 738 beg = Curl_getASN1Element(&elem, beg, end); 739 } 740 if(elem.tag == 2) { 741 cert->subjectUniqueID = elem; 742 if(beg < end) 743 beg = Curl_getASN1Element(&elem, beg, end); 744 } 745 if(elem.tag == 3) 746 Curl_getASN1Element(&cert->extensions, elem.beg, elem.end); 747} 748 749static size_t copySubstring(char * to, const char * from) 750{ 751 size_t i; 752 753 /* Copy at most 64-characters, terminate with a newline and returns the 754 effective number of stored characters. */ 755 756 for(i = 0; i < 64; i++) { 757 to[i] = *from; 758 if(!*from++) 759 break; 760 } 761 762 to[i++] = '\n'; 763 return i; 764} 765 766static const char * dumpAlgo(curl_asn1Element * param, 767 const char * beg, const char * end) 768{ 769 curl_asn1Element oid; 770 771 /* Get algorithm parameters and return algorithm name. */ 772 773 beg = Curl_getASN1Element(&oid, beg, end); 774 param->tag = 0; 775 param->beg = param->end = end; 776 if(beg < end) 777 Curl_getASN1Element(param, beg, end); 778 return OID2str(oid.beg, oid.end, TRUE); 779} 780 781static void do_pubkey_field(struct SessionHandle * data, int certnum, 782 const char * label, curl_asn1Element * elem) 783{ 784 const char * output; 785 786 /* Generate a certificate information record for the public key. */ 787 788 output = Curl_ASN1tostr(elem, 0); 789 if(output) { 790 if(data->set.ssl.certinfo) 791 Curl_ssl_push_certinfo(data, certnum, label, output); 792 if(!certnum) 793 infof(data, " %s: %s\n", label, output); 794 free((char *) output); 795 } 796} 797 798static void do_pubkey(struct SessionHandle * data, int certnum, 799 const char * algo, curl_asn1Element * param, 800 curl_asn1Element * pubkey) 801{ 802 curl_asn1Element elem; 803 curl_asn1Element pk; 804 const char * p; 805 const char * q; 806 unsigned long len; 807 unsigned int i; 808 809 /* Generate all information records for the public key. */ 810 811 /* Get the public key (single element). */ 812 Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); 813 814 if(curl_strequal(algo, "rsaEncryption")) { 815 p = Curl_getASN1Element(&elem, pk.beg, pk.end); 816 /* Compute key length. */ 817 for(q = elem.beg; !*q && q < elem.end; q++) 818 ; 819 len = (elem.end - q) * 8; 820 if(len) 821 for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) 822 len--; 823 if(len > 32) 824 elem.beg = q; /* Strip leading zero bytes. */ 825 if(!certnum) 826 infof(data, " RSA Public Key (%lu bits)\n", len); 827 if(data->set.ssl.certinfo) { 828 q = curl_maprintf("%lu", len); 829 if(q) { 830 Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); 831 free((char *) q); 832 } 833 } 834 /* Generate coefficients. */ 835 do_pubkey_field(data, certnum, "rsa(n)", &elem); 836 Curl_getASN1Element(&elem, p, pk.end); 837 do_pubkey_field(data, certnum, "rsa(e)", &elem); 838 } 839 else if(curl_strequal(algo, "dsa")) { 840 p = Curl_getASN1Element(&elem, param->beg, param->end); 841 do_pubkey_field(data, certnum, "dsa(p)", &elem); 842 p = Curl_getASN1Element(&elem, p, param->end); 843 do_pubkey_field(data, certnum, "dsa(q)", &elem); 844 Curl_getASN1Element(&elem, p, param->end); 845 do_pubkey_field(data, certnum, "dsa(g)", &elem); 846 do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); 847 } 848 else if(curl_strequal(algo, "dhpublicnumber")) { 849 p = Curl_getASN1Element(&elem, param->beg, param->end); 850 do_pubkey_field(data, certnum, "dh(p)", &elem); 851 Curl_getASN1Element(&elem, param->beg, param->end); 852 do_pubkey_field(data, certnum, "dh(g)", &elem); 853 do_pubkey_field(data, certnum, "dh(pub_key)", &pk); 854 } 855#if 0 /* Patent-encumbered. */ 856 else if(curl_strequal(algo, "ecPublicKey")) { 857 /* Left TODO. */ 858 } 859#endif 860} 861 862CURLcode Curl_extract_certinfo(struct connectdata * conn, 863 int certnum, 864 const char * beg, 865 const char * end) 866{ 867 curl_X509certificate cert; 868 struct SessionHandle * data = conn->data; 869 curl_asn1Element param; 870 const char * ccp; 871 char * cp1; 872 size_t cl1; 873 char * cp2; 874 CURLcode cc; 875 unsigned long version; 876 size_t i; 877 size_t j; 878 879 if(!data->set.ssl.certinfo) 880 if(certnum) 881 return CURLE_OK; 882 883 /* Prepare the certificate information for curl_easy_getinfo(). */ 884 885 /* Extract the certificate ASN.1 elements. */ 886 Curl_parseX509(&cert, beg, end); 887 888 /* Subject. */ 889 ccp = Curl_DNtostr(&cert.subject); 890 if(!ccp) 891 return CURLE_OUT_OF_MEMORY; 892 if(data->set.ssl.certinfo) 893 Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); 894 if(!certnum) 895 infof(data, "%2d Subject: %s\n", certnum, ccp); 896 free((char *) ccp); 897 898 /* Issuer. */ 899 ccp = Curl_DNtostr(&cert.issuer); 900 if(!ccp) 901 return CURLE_OUT_OF_MEMORY; 902 if(data->set.ssl.certinfo) 903 Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); 904 if(!certnum) 905 infof(data, " Issuer: %s\n", ccp); 906 free((char *) ccp); 907 908 /* Version (always fits in less than 32 bits). */ 909 version = 0; 910 for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) 911 version = (version << 8) | *(const unsigned char *) ccp; 912 if(data->set.ssl.certinfo) { 913 ccp = curl_maprintf("%lx", version); 914 if(!ccp) 915 return CURLE_OUT_OF_MEMORY; 916 Curl_ssl_push_certinfo(data, certnum, "Version", ccp); 917 free((char *) ccp); 918 } 919 if(!certnum) 920 infof(data, " Version: %lu (0x%lx)\n", version + 1, version); 921 922 /* Serial number. */ 923 ccp = Curl_ASN1tostr(&cert.serialNumber, 0); 924 if(!ccp) 925 return CURLE_OUT_OF_MEMORY; 926 if(data->set.ssl.certinfo) 927 Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); 928 if(!certnum) 929 infof(data, " Serial Number: %s\n", ccp); 930 free((char *) ccp); 931 932 /* Signature algorithm .*/ 933 ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, 934 cert.signatureAlgorithm.end); 935 if(!ccp) 936 return CURLE_OUT_OF_MEMORY; 937 if(data->set.ssl.certinfo) 938 Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); 939 if(!certnum) 940 infof(data, " Signature Algorithm: %s\n", ccp); 941 free((char *) ccp); 942 943 /* Start Date. */ 944 ccp = Curl_ASN1tostr(&cert.notBefore, 0); 945 if(!ccp) 946 return CURLE_OUT_OF_MEMORY; 947 if(data->set.ssl.certinfo) 948 Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); 949 if(!certnum) 950 infof(data, " Start Date: %s\n", ccp); 951 free((char *) ccp); 952 953 /* Expire Date. */ 954 ccp = Curl_ASN1tostr(&cert.notAfter, 0); 955 if(!ccp) 956 return CURLE_OUT_OF_MEMORY; 957 if(data->set.ssl.certinfo) 958 Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); 959 if(!certnum) 960 infof(data, " Expire Date: %s\n", ccp); 961 free((char *) ccp); 962 963 /* Public Key Algorithm. */ 964 ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, 965 cert.subjectPublicKeyAlgorithm.end); 966 if(!ccp) 967 return CURLE_OUT_OF_MEMORY; 968 if(data->set.ssl.certinfo) 969 Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp); 970 if(!certnum) 971 infof(data, " Public Key Algorithm: %s\n", ccp); 972 do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); 973 free((char *) ccp); 974 975/* TODO: extensions. */ 976 977 /* Signature. */ 978 ccp = Curl_ASN1tostr(&cert.signature, 0); 979 if(!ccp) 980 return CURLE_OUT_OF_MEMORY; 981 if(data->set.ssl.certinfo) 982 Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); 983 if(!certnum) 984 infof(data, " Signature: %s\n", ccp); 985 free((char *) ccp); 986 987 /* Generate PEM certificate. */ 988 cc = Curl_base64_encode(data, cert.certificate.beg, 989 cert.certificate.end - cert.certificate.beg, 990 &cp1, &cl1); 991 if(cc != CURLE_OK) 992 return cc; 993 /* Compute the number of characters in final certificate string. Format is: 994 -----BEGIN CERTIFICATE-----\n 995 <max 64 base64 characters>\n 996 . 997 . 998 . 999 -----END CERTIFICATE-----\n 1000 */ 1001 i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26; 1002 cp2 = malloc(i + 1); 1003 if(!cp2) { 1004 free(cp1); 1005 return CURLE_OUT_OF_MEMORY; 1006 } 1007 /* Build the certificate string. */ 1008 i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----"); 1009 for(j = 0; j < cl1; j += 64) 1010 i += copySubstring(cp2 + i, cp1 + j); 1011 i += copySubstring(cp2 + i, "-----END CERTIFICATE-----"); 1012 cp2[i] = '\0'; 1013 free(cp1); 1014 if(data->set.ssl.certinfo) 1015 Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); 1016 if(!certnum) 1017 infof(data, "%s\n", cp2); 1018 free(cp2); 1019 return CURLE_OK; 1020} 1021 1022#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */ 1023 1024#if defined(USE_QSOSSL) || defined(USE_GSKIT) 1025 1026static const char * checkOID(const char * beg, const char * end, 1027 const char * oid) 1028{ 1029 curl_asn1Element e; 1030 const char * ccp; 1031 const char * p; 1032 bool matched; 1033 1034 /* Check if first ASN.1 element at `beg' is the given OID. 1035 Return a pointer in the source after the OID if found, else NULL. */ 1036 1037 ccp = Curl_getASN1Element(&e, beg, end); 1038 if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER) 1039 return (const char *) NULL; 1040 1041 p = OID2str(e.beg, e.end, FALSE); 1042 if(!p) 1043 return (const char *) NULL; 1044 1045 matched = !strcmp(p, oid); 1046 free((char *) p); 1047 return matched? ccp: (const char *) NULL; 1048} 1049 1050CURLcode Curl_verifyhost(struct connectdata * conn, 1051 const char * beg, const char * end) 1052{ 1053 struct SessionHandle * data = conn->data; 1054 curl_X509certificate cert; 1055 curl_asn1Element dn; 1056 curl_asn1Element elem; 1057 curl_asn1Element ext; 1058 curl_asn1Element name; 1059 int i; 1060 const char * p; 1061 const char * q; 1062 char * dnsname; 1063 int matched = -1; 1064 size_t addrlen = (size_t) -1; 1065 ssize_t len; 1066#ifdef ENABLE_IPV6 1067 struct in6_addr addr; 1068#else 1069 struct in_addr addr; 1070#endif 1071 1072 /* Verify that connection server matches info in X509 certificate at 1073 `beg'..`end'. */ 1074 1075 if(!data->set.ssl.verifyhost) 1076 return CURLE_OK; 1077 1078 if(!beg) 1079 return CURLE_PEER_FAILED_VERIFICATION; 1080 Curl_parseX509(&cert, beg, end); 1081 1082 /* Get the server IP address. */ 1083#ifdef ENABLE_IPV6 1084 if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr)) 1085 addrlen = sizeof(struct in6_addr); 1086 else 1087#endif 1088 if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) 1089 addrlen = sizeof(struct in_addr); 1090 1091 /* Process extensions. */ 1092 for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) { 1093 p = Curl_getASN1Element(&ext, p, cert.extensions.end); 1094 /* Check if extension is a subjectAlternativeName. */ 1095 ext.beg = checkOID(ext.beg, ext.end, sanOID); 1096 if(ext.beg) { 1097 ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); 1098 /* Skip critical if present. */ 1099 if(elem.tag == CURL_ASN1_BOOLEAN) 1100 ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); 1101 /* Parse the octet string contents: is a single sequence. */ 1102 Curl_getASN1Element(&elem, elem.beg, elem.end); 1103 /* Check all GeneralNames. */ 1104 for(q = elem.beg; matched != 1 && q < elem.end;) { 1105 q = Curl_getASN1Element(&name, q, elem.end); 1106 switch (name.tag) { 1107 case 2: /* DNS name. */ 1108 i = 0; 1109 len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, 1110 name.beg, name.end); 1111 if(len > 0) 1112 if(strlen(dnsname) == (size_t) len) 1113 i = Curl_cert_hostcheck((const char *) dnsname, conn->host.name); 1114 if(dnsname) 1115 free(dnsname); 1116 if(!i) 1117 return CURLE_PEER_FAILED_VERIFICATION; 1118 matched = i; 1119 break; 1120 1121 case 7: /* IP address. */ 1122 matched = (size_t) (name.end - q) == addrlen && 1123 !memcmp(&addr, q, addrlen); 1124 break; 1125 } 1126 } 1127 } 1128 } 1129 1130 switch (matched) { 1131 case 1: 1132 /* an alternative name matched the server hostname */ 1133 infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); 1134 return CURLE_OK; 1135 case 0: 1136 /* an alternative name field existed, but didn't match and then 1137 we MUST fail */ 1138 infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); 1139 return CURLE_PEER_FAILED_VERIFICATION; 1140 } 1141 1142 /* Process subject. */ 1143 name.beg = name.end = ""; 1144 q = cert.subject.beg; 1145 /* we have to look to the last occurrence of a commonName in the 1146 distinguished one to get the most significant one. */ 1147 while(q < cert.subject.end) { 1148 q = Curl_getASN1Element(&dn, q, cert.subject.end); 1149 for(p = dn.beg; p < dn.end;) { 1150 p = Curl_getASN1Element(&elem, p, dn.end); 1151 /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */ 1152 elem.beg = checkOID(elem.beg, elem.end, cnOID); 1153 if(elem.beg) 1154 name = elem; /* Latch CN. */ 1155 } 1156 } 1157 1158 /* Check the CN if found. */ 1159 if(!Curl_getASN1Element(&elem, name.beg, name.end)) 1160 failf(data, "SSL: unable to obtain common name from peer certificate"); 1161 else { 1162 len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); 1163 if(len < 0) { 1164 free(dnsname); 1165 return CURLE_OUT_OF_MEMORY; 1166 } 1167 if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ 1168 failf(data, "SSL: illegal cert name field"); 1169 else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) { 1170 infof(data, "\t common name: %s (matched)\n", dnsname); 1171 free(dnsname); 1172 return CURLE_OK; 1173 } 1174 else 1175 failf(data, "SSL: certificate subject name '%s' does not match " 1176 "target host name '%s'", dnsname, conn->host.dispname); 1177 free(dnsname); 1178 } 1179 1180 return CURLE_PEER_FAILED_VERIFICATION; 1181} 1182 1183#endif /* USE_QSOSSL or USE_GSKIT */ 1184