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