in tls/s2n_x509_validator.c [200:285]
static uint8_t s2n_verify_host_information(struct s2n_x509_validator *validator, struct s2n_connection *conn, X509 *public_cert) {
(void)validator;
uint8_t verified = 0;
uint8_t san_found = 0;
/* Check SubjectAltNames before CommonName as per RFC 6125 6.4.4 */
STACK_OF(GENERAL_NAME) *names_list = X509_get_ext_d2i(public_cert, NID_subject_alt_name, NULL, NULL);
int n = sk_GENERAL_NAME_num(names_list);
for (int i = 0; i < n && !verified; i++) {
GENERAL_NAME *current_name = sk_GENERAL_NAME_value(names_list, i);
if (current_name->type == GEN_DNS) {
san_found = 1;
const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5);
size_t name_len = (size_t) ASN1_STRING_length(current_name->d.ia5);
verified = conn->verify_host_fn(name, name_len, conn->data_for_verify_host);
} else if (current_name->type == GEN_URI) {
const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5);
size_t name_len = (size_t) ASN1_STRING_length(current_name->d.ia5);
verified = conn->verify_host_fn(name, name_len, conn->data_for_verify_host);
} else if (current_name->type == GEN_IPADD) {
san_found = 1;
/* try to validate an IP address if it's in the subject alt name. */
const unsigned char *ip_addr = current_name->d.iPAddress->data;
size_t ip_addr_len = (size_t)current_name->d.iPAddress->length;
s2n_result parse_result = S2N_RESULT_ERROR;
s2n_stack_blob(address, INET6_ADDRSTRLEN + 1, INET6_ADDRSTRLEN + 1);
if (ip_addr_len == 4) {
parse_result = s2n_inet_ntop(AF_INET, ip_addr, &address);
} else if (ip_addr_len == 16) {
parse_result = s2n_inet_ntop(AF_INET6, ip_addr, &address);
}
/* strlen should be safe here since we made sure we were null terminated AND that inet_ntop succeeded */
if (s2n_result_is_ok(parse_result)) {
verified = conn->verify_host_fn(
(const char *)address.data,
strlen((const char *)address.data),
conn->data_for_verify_host);
}
}
}
GENERAL_NAMES_free(names_list);
/* if no SubjectAltNames of type DNS found, go to the common name. */
if (!verified && !san_found) {
X509_NAME *subject_name = X509_get_subject_name(public_cert);
if (subject_name) {
int next_idx = 0, curr_idx = -1;
while ((next_idx = X509_NAME_get_index_by_NID(subject_name, NID_commonName, curr_idx)) >= 0) {
curr_idx = next_idx;
}
if (curr_idx >= 0) {
ASN1_STRING *common_name =
X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, curr_idx));
if (common_name) {
char peer_cn[255];
static size_t peer_cn_size = sizeof(peer_cn);
POSIX_CHECKED_MEMSET(&peer_cn, 0, peer_cn_size);
/* X520CommonName allows the following ANSI string types per RFC 5280 Appendix A.1 */
if (ASN1_STRING_type(common_name) == V_ASN1_TELETEXSTRING ||
ASN1_STRING_type(common_name) == V_ASN1_PRINTABLESTRING ||
ASN1_STRING_type(common_name) == V_ASN1_UNIVERSALSTRING ||
ASN1_STRING_type(common_name) == V_ASN1_UTF8STRING ||
ASN1_STRING_type(common_name) == V_ASN1_BMPSTRING ) {
size_t len = (size_t) ASN1_STRING_length(common_name);
POSIX_ENSURE_LTE(len, sizeof(peer_cn) - 1);
POSIX_CHECKED_MEMCPY(peer_cn, ASN1_STRING_data(common_name), len);
verified = conn->verify_host_fn(peer_cn, len, conn->data_for_verify_host);
}
}
}
}
}
return verified;
}