@@ -331,229 +331,6 @@ bool InvalidRetryToken(
331
331
return false ;
332
332
}
333
333
334
- namespace {
335
-
336
- bool SplitHostname (
337
- const char * hostname,
338
- std::vector<std::string>* parts,
339
- const char delim = ' .' ) {
340
- static std::string check_str =
341
- " \x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30 "
342
- " \x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40 "
343
- " \x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50 "
344
- " \x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60 "
345
- " \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70 "
346
- " \x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F " ;
347
-
348
- std::stringstream str (hostname);
349
- std::string part;
350
- while (getline (str, part, delim)) {
351
- // if (part.length() == 0 ||
352
- // part.find_first_not_of(check_str) != std::string::npos) {
353
- // return false;
354
- // }
355
- for (size_t n = 0 ; n < part.length (); n++) {
356
- if (part[n] >= ' A' && part[n] <= ' Z' )
357
- part[n] = (part[n] | 0x20 ); // Lower case the letter
358
- if (check_str.find (part[n]) == std::string::npos)
359
- return false ;
360
- }
361
- parts->push_back (part);
362
- }
363
- return true ;
364
- }
365
-
366
- bool CheckCertNames (
367
- const std::vector<std::string>& host_parts,
368
- const std::string& name,
369
- bool use_wildcard = true ) {
370
-
371
- if (name.length () == 0 )
372
- return false ;
373
-
374
- std::vector<std::string> name_parts;
375
- if (!SplitHostname (name.c_str (), &name_parts))
376
- return false ;
377
-
378
- if (name_parts.size () != host_parts.size ())
379
- return false ;
380
-
381
- for (size_t n = host_parts.size () - 1 ; n > 0 ; --n) {
382
- if (host_parts[n] != name_parts[n])
383
- return false ;
384
- }
385
-
386
- if (name_parts[0 ].find (' *' ) == std::string::npos ||
387
- name_parts[0 ].find (" xn--" ) != std::string::npos) {
388
- return host_parts[0 ] == name_parts[0 ];
389
- }
390
-
391
- if (!use_wildcard)
392
- return false ;
393
-
394
- std::vector<std::string> sub_parts;
395
- SplitHostname (name_parts[0 ].c_str (), &sub_parts, ' *' );
396
-
397
- if (sub_parts.size () > 2 )
398
- return false ;
399
-
400
- if (name_parts.size () <= 2 )
401
- return false ;
402
-
403
- std::string prefix;
404
- std::string suffix;
405
- if (sub_parts.size () == 2 ) {
406
- prefix = sub_parts[0 ];
407
- suffix = sub_parts[1 ];
408
- } else {
409
- prefix = " " ;
410
- suffix = sub_parts[0 ];
411
- }
412
-
413
- if (prefix.length () + suffix.length () > host_parts[0 ].length ())
414
- return false ;
415
-
416
- if (host_parts[0 ].compare (0 , prefix.length (), prefix))
417
- return false ;
418
-
419
- if (host_parts[0 ].compare (
420
- host_parts[0 ].length () - suffix.length (),
421
- suffix.length (), suffix)) {
422
- return false ;
423
- }
424
-
425
- return true ;
426
- }
427
-
428
- } // namespace
429
-
430
- int VerifyHostnameIdentity (
431
- const crypto::SSLPointer& ssl,
432
- const char * hostname) {
433
- int err = X509_V_ERR_HOSTNAME_MISMATCH;
434
- crypto::X509Pointer cert (SSL_get_peer_certificate (ssl.get ()));
435
- if (!cert)
436
- return err;
437
-
438
- // There are several pieces of information we need from the cert at this point
439
- // 1. The Subject (if it exists)
440
- // 2. The collection of Alt Names (if it exists)
441
- //
442
- // The certificate may have many Alt Names. We only care about the ones that
443
- // are prefixed with 'DNS:', 'URI:', or 'IP Address:'. We might check
444
- // additional ones later but we'll start with these.
445
- //
446
- // Ideally, we'd be able to *just* use OpenSSL's built in name checking for
447
- // this (SSL_set1_host and X509_check_host) but it does not appear to do
448
- // checking on URI or IP Address Alt names, which is unfortunate. We need
449
- // both of those to retain compatibility with the peer identity verification
450
- // Node.js already does elsewhere. At the very least, we'll use
451
- // X509_check_host here first as a first step. If it is successful, awesome,
452
- // there's nothing else for us to do. Return and be happy!
453
- if (X509_check_host (
454
- cert.get (),
455
- hostname,
456
- strlen (hostname),
457
- X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT |
458
- X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS |
459
- X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS,
460
- nullptr ) > 0 ) {
461
- return 0 ;
462
- }
463
-
464
- if (X509_check_ip_asc (
465
- cert.get (),
466
- hostname,
467
- X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT) > 0 ) {
468
- return 0 ;
469
- }
470
-
471
- // If we've made it this far, then we have to perform a more check
472
- return VerifyHostnameIdentity (
473
- hostname,
474
- crypto::GetCertificateCN (cert.get ()),
475
- crypto::GetCertificateAltNames (cert.get ()));
476
- }
477
-
478
- int VerifyHostnameIdentity (
479
- const char * hostname,
480
- const std::string& cert_cn,
481
- const std::unordered_multimap<std::string, std::string>& altnames) {
482
-
483
- int err = X509_V_ERR_HOSTNAME_MISMATCH;
484
-
485
- // 1. If the hostname is an IP address (v4 or v6), the certificate is valid
486
- // if and only if there is an 'IP Address:' alt name specifying the same
487
- // IP address. The IP address must be canonicalized to ensure a proper
488
- // check. It's possible that the X509_check_ip_asc covers this. If so,
489
- // we can remove this check.
490
-
491
- if (SocketAddress::is_numeric_host (hostname)) {
492
- auto ips = altnames.equal_range (" ip" );
493
- for (auto ip = ips.first ; ip != ips.second ; ++ip) {
494
- if (ip->second .compare (hostname) == 0 ) {
495
- // Success!
496
- return 0 ;
497
- }
498
- }
499
- // No match, and since the hostname is an IP address, skip any
500
- // further checks
501
- return err;
502
- }
503
-
504
- auto dns_names = altnames.equal_range (" dns" );
505
- auto uri_names = altnames.equal_range (" uri" );
506
-
507
- size_t dns_count = std::distance (dns_names.first , dns_names.second );
508
- size_t uri_count = std::distance (uri_names.first , uri_names.second );
509
-
510
- std::vector<std::string> host_parts;
511
- SplitHostname (hostname, &host_parts);
512
-
513
- // 2. If there no 'DNS:' or 'URI:' Alt names, if the certificate has a
514
- // Subject, then we need to extract the CN field from the Subject. and
515
- // check that the hostname matches the CN, taking into consideration
516
- // the possibility of a wildcard in the CN. If there is a match, congrats,
517
- // we have a valid certificate. Return and be happy.
518
-
519
- if (dns_count == 0 && uri_count == 0 ) {
520
- if (cert_cn.length () > 0 && CheckCertNames (host_parts, cert_cn))
521
- return 0 ;
522
- // No match, and since there are no dns or uri entries, return
523
- return err;
524
- }
525
-
526
- // 3. If, however, there are 'DNS:' and 'URI:' Alt names, things become more
527
- // complicated. Essentially, we need to iterate through each 'DNS:' and
528
- // 'URI:' Alt name to find one that matches. The 'DNS:' Alt names are
529
- // relatively simple but may include wildcards. The 'URI:' Alt names
530
- // require the name to be parsed as a URL, then extract the hostname from
531
- // the URL, which is then checked against the hostname. If you find a
532
- // match, yay! Return and be happy. (Note, it's possible that the 'DNS:'
533
- // check in this step is redundant to the X509_check_host check. If so,
534
- // we can simplify by removing those checks here.)
535
-
536
- // First, let's check dns names
537
- for (auto name = dns_names.first ; name != dns_names.second ; ++name) {
538
- if (name->first .length () > 0 &&
539
- CheckCertNames (host_parts, name->second )) {
540
- return 0 ;
541
- }
542
- }
543
-
544
- // Then, check uri names
545
- for (auto name = uri_names.first ; name != uri_names.second ; ++name) {
546
- if (name->first .length () > 0 &&
547
- CheckCertNames (host_parts, name->second , false )) {
548
- return 0 ;
549
- }
550
- }
551
-
552
- // 4. Failing all of the previous checks, we assume the certificate is
553
- // invalid for an unspecified reason.
554
- return err;
555
- }
556
-
557
334
// Get the ALPN protocol identifier that was negotiated for the session
558
335
Local<Value> GetALPNProtocol (const QuicSession& session) {
559
336
QuicCryptoContext* ctx = session.crypto_context ();
@@ -747,10 +524,17 @@ SSL_QUIC_METHOD quic_method = SSL_QUIC_METHOD{
747
524
void SetHostname (const crypto::SSLPointer& ssl, const std::string& hostname) {
748
525
// If the hostname is an IP address, use an empty string
749
526
// as the hostname instead.
750
- if (SocketAddress::is_numeric_host (hostname.c_str ())) {
527
+ X509_VERIFY_PARAM* param = SSL_get0_param (ssl.get ());
528
+ X509_VERIFY_PARAM_set_hostflags (param, 0 );
529
+
530
+ if (UNLIKELY (SocketAddress::is_numeric_host (hostname.c_str ()))) {
751
531
SSL_set_tlsext_host_name (ssl.get (), " " );
532
+ CHECK_EQ (X509_VERIFY_PARAM_set1_host (param, " " , 0 ), 1 );
752
533
} else {
753
534
SSL_set_tlsext_host_name (ssl.get (), hostname.c_str ());
535
+ CHECK_EQ (
536
+ X509_VERIFY_PARAM_set1_host (param, hostname.c_str (), hostname.length ()),
537
+ 1 );
754
538
}
755
539
}
756
540
0 commit comments