/** @file ssl_verify.c @author web, feh -- parts of code borrowed from Pavel Shramov; tx Peter Conrad @brief Compares 'hostname' against SubAltName DNS:hostname + DN: /CN=hostname */ #include "ucspissl.h" #include "case.h" #include "str.h" int ssl_verify(SSL *ssl,const char *hostname,stralloc *dnsout) { X509 *cert; STACK_OF(GENERAL_NAME) *extensions; const GENERAL_NAME *ext; char buf[SSL_NAME_LEN]; char *dnsname = 0; int i; int num; int len; int dname = 0; #if (OPENSSL_VERSION_NUMBER > 0x30100000L) cert = SSL_get1_peer_certificate(ssl); #else cert = SSL_get_peer_certificate(ssl); #endif if (!cert) return -1; if (SSL_get_verify_result(ssl) != X509_V_OK) return -2; if (hostname) { if (!stralloc_copys(dnsout,"")) return 1; extensions = X509_get_ext_d2i(cert,NID_subject_alt_name,0,0); num = sk_GENERAL_NAME_num(extensions); /* num = 0, if no SAN extensions */ for (i = 0; i < num; ++i) { ext = sk_GENERAL_NAME_value(extensions,i); if (ext->type == GEN_DNS) { if (ASN1_STRING_type(ext->d.dNSName) != V_ASN1_IA5STRING) continue; #if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L)) dnsname = (char *)ASN1_STRING_data(ext->d.dNSName); #else dnsname = (char *)ASN1_STRING_get0_data(ext->d.dNSName); #endif len = ASN1_STRING_length(ext->d.dNSName); if (len != str_len(dnsname)) continue; if (!stralloc_copyb(dnsout,dnsname,len)) return 1; if (case_diffs((char *)hostname,dnsname) == 0) return 0; dname = 1; } } if (!dname) { X509_NAME_get_text_by_NID(X509_get_subject_name(cert),NID_commonName,buf,sizeof(buf)); buf[SSL_NAME_LEN - 1] = 0; if (!stralloc_copyb(dnsout,buf,str_len(buf))) return 1; if (case_diffs((char *)hostname,buf) == 0) return 0; } return -3; } return 0; }