static int check_hostname(X509 *cert, const char *hostname) { int ret, i; X509_NAME *subject; ASN1_STRING *name; /* check by subject */ ret = check_alt_names(cert, hostname); if (ret >= 0) return ret; /* check by common name (old method) */ subject= X509_get_subject_name(cert); if (!subject) return 0; i = -1; while (X509_NAME_get_index_by_NID(subject, NID_commonName, i) >=0) i = X509_NAME_get_index_by_NID(subject, NID_commonName, i); if (i < 0) return 0; name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i)); if (!name) return 0; return check_name_match(name, hostname); }
int sslverify(struct server *srv, SSL *ssl, char **cause) { X509 *x509; int error; char *fqdn, name[256], *ptr, *ptr2; const char *s; if ((x509 = SSL_get_peer_certificate(ssl)) == NULL) { /* No certificate, error since we wanted to verify it. */ s = "no certificate"; goto error; } /* Verify certificate. */ if ((error = SSL_get_verify_result(ssl)) != X509_V_OK) { s = X509_verify_cert_error_string(error); goto error; } /* Get certificate name. */ X509_NAME_oneline(X509_get_subject_name(x509), name, sizeof name); /* Check for CN field. */ if ((ptr = strstr(name, "/CN=")) == NULL) { s = "CN missing"; goto error; } /* Verify CN field. */ getaddrs(srv->host, &fqdn, NULL); do { ptr += 4; ptr2 = strchr(ptr, '/'); if (ptr2 != NULL) *ptr2 = '\0'; /* Compare against both given host and FQDN. */ if (fnmatch(ptr, srv->host, FNM_NOESCAPE|FNM_CASEFOLD) == 0 || (fqdn != NULL && fnmatch(ptr, fqdn, FNM_NOESCAPE|FNM_CASEFOLD)) == 0) break; if (ptr2 != NULL) *ptr2 = '/'; } while ((ptr = strstr(ptr, "/CN=")) != NULL); /* No valid CN found. Try alternative names. */ if (ptr == NULL) ptr = check_alt_names(srv->host, fqdn, x509); if (fqdn != NULL) xfree(fqdn); /* No valid CN found. */ if (ptr == NULL) { s = "no matching CN"; goto error; } /* Valid CN found. */ X509_free(x509); return (0); error: xasprintf(cause, "certificate verification failed: %s", s); if (x509 != NULL) X509_free(x509); return (-1); }