| 569 | }; |
| 570 | |
| 571 | bool tlsCheckCertificateAgainstAllowlist(tls_connection* conn, std::set<sdsstring> allowlist, const char** commonName){ |
| 572 | if (allowlist.empty()){ |
| 573 | // An empty list implies acceptance of all |
| 574 | return true; |
| 575 | } |
| 576 | |
| 577 | X509 * cert = SSL_get_peer_certificate(conn->ssl); |
| 578 | TCleanup certClen([cert]{X509_free(cert);}); |
| 579 | |
| 580 | /* Check the common name (CN) of the certificate first */ |
| 581 | X509_NAME_ENTRY * ne = X509_NAME_get_entry(X509_get_subject_name(cert), X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1)); |
| 582 | *commonName = reinterpret_cast<const char*>(ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(ne))); |
| 583 | |
| 584 | tlsSetCertificateFingerprint(conn, cert); |
| 585 | |
| 586 | if (tlsCheckAgainstAllowlist(*commonName, allowlist)) { |
| 587 | return true; |
| 588 | } |
| 589 | |
| 590 | /* If that fails, check through the subject alternative names (SANs) as well */ |
| 591 | GENERAL_NAMES* subjectAltNames = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); |
| 592 | if (subjectAltNames != nullptr){ |
| 593 | for (int i = 0; i < sk_GENERAL_NAME_num(subjectAltNames); i++) |
| 594 | { |
| 595 | GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i); |
| 596 | /* Short circuit if one of the SANs match. |
| 597 | * We only support DNS, EMAIL, URI, and IP (specifically IPv4) */ |
| 598 | switch (generalName->type) |
| 599 | { |
| 600 | case GEN_EMAIL: |
| 601 | if (tlsCheckAgainstAllowlist(reinterpret_cast<const char*>(ASN1_STRING_get0_data(generalName->d.rfc822Name)), allowlist)){ |
| 602 | sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free); |
| 603 | return true; |
| 604 | } |
| 605 | break; |
| 606 | case GEN_DNS: |
| 607 | if (tlsCheckAgainstAllowlist(reinterpret_cast<const char*>(ASN1_STRING_get0_data(generalName->d.dNSName)), allowlist)){ |
| 608 | sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free); |
| 609 | return true; |
| 610 | } |
| 611 | break; |
| 612 | case GEN_URI: |
| 613 | if (tlsCheckAgainstAllowlist(reinterpret_cast<const char*>(ASN1_STRING_get0_data(generalName->d.uniformResourceIdentifier)), allowlist)){ |
| 614 | sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free); |
| 615 | return true; |
| 616 | } |
| 617 | break; |
| 618 | case GEN_IPADD: |
| 619 | { |
| 620 | int ipLen = ASN1_STRING_length(generalName->d.iPAddress); |
| 621 | if (ipLen == 4){ //IPv4 case |
| 622 | char addr[INET_ADDRSTRLEN]; |
| 623 | inet_ntop(AF_INET, ASN1_STRING_get0_data(generalName->d.iPAddress), addr, INET_ADDRSTRLEN); |
| 624 | if (tlsCheckAgainstAllowlist(addr, allowlist)){ |
| 625 | sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free); |
| 626 | return true; |
| 627 | } |
| 628 | } else if (ipLen == 16) { // IPv6 case |
no test coverage detected