int php_mongodb_matches_san_list(X509 *peer, const char *subject_name) /* {{{ */ { int i, len; unsigned char *cert_name = NULL; char ipbuffer[64]; GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0); int alt_name_count = sk_GENERAL_NAME_num(alt_names); for (i = 0; i < alt_name_count; i++) { GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i); if (san->type == GEN_DNS) { ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName); if ((size_t)ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) { OPENSSL_free(cert_name); /* prevent null-byte poisoning*/ continue; } /* accommodate valid FQDN entries ending in "." */ len = strlen((const char*)cert_name); if (len && strcmp((const char *)&cert_name[len-1], ".") == 0) { cert_name[len-1] = '\0'; } if (php_mongodb_matches_wildcard_name(subject_name, (const char *)cert_name) == SUCCESS) { OPENSSL_free(cert_name); return SUCCESS; } OPENSSL_free(cert_name); } else if (san->type == GEN_IPADD) { if (san->d.iPAddress->length == 4) { sprintf(ipbuffer, "%d.%d.%d.%d", san->d.iPAddress->data[0], san->d.iPAddress->data[1], san->d.iPAddress->data[2], san->d.iPAddress->data[3] ); if (strcasecmp(subject_name, (const char*)ipbuffer) == 0) { return SUCCESS; } } /* No, we aren't bothering to check IPv6 addresses. Why? * Because IP SAN names are officially deprecated and are * not allowed by CAs starting in 2015. Deal with it. */ } } return FAILURE; }
/** * Check if certificate can be used as a CA to sign standard X509 certs * Return 1 if true; 0 if not. */ int verify_x509IsCA(X509 *cert) { int idret; /* final argument to X509_check_purpose() is whether to check for CAness */ idret = X509_check_purpose(cert, X509_PURPOSE_SSL_CLIENT, 1); if (idret == 1) return 1; else if (idret == 0) return 0; else { verify_log( L_WARN, "Purpose warning code = %d", idret ); return 1; } #if 0 BASIC_CONSTRAINTS * x509v3_bc = NULL; int index = -1; int critical; if((x509v3_bc = X509_get_ext_d2i(cert, NID_basic_constraints, &critical, &index)) && x509v3_bc->ca) { *type = GLOBUS_GSI_CERT_UTILS_TYPE_CA; goto exit; } #endif }
/** * Implements signing certificate selector for EstEID ID-Cards. * * @param certificates list of certificates to choose from. List of all certificates * found ID-card. * @return should return the selected certificate. * @throws SignException throws exception if no suitable certificate was found. */ digidoc::PKCS11Signer::PKCS11Cert digidoc::EstEIDSigner::selectSigningCertificate( const std::vector<PKCS11Signer::PKCS11Cert> &certificates) const throw(SignException) { // Find EstEID signing certificate if(certificates.empty()) THROW_SIGNEXCEPTION("Could not find certificate."); for(std::vector<PKCS11Signer::PKCS11Cert>::const_iterator i = certificates.begin(); i < certificates.end(); ++i) { ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING*)X509_get_ext_d2i(i->cert, NID_key_usage, 0, 0); if(!keyusage) continue; for(int n = 0; n < 9; ++n) { if(ASN1_BIT_STRING_get_bit(keyusage, n) && n == 1) { ASN1_BIT_STRING_free( keyusage ); return *i; } } ASN1_BIT_STRING_free( keyusage ); } THROW_SIGNEXCEPTION("Could not find certificate."); return PKCS11Signer::PKCS11Cert(); }
/** * Tries to find a match for hostname in the certificate's Subject Alternative Name extension. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it. * Returns NoSANPresent if the SAN extension was not present in the certificate. */ static HostnameValidationResult matches_subject_alternative_name(const char *hostname, const X509 *server_cert) { HostnameValidationResult result = MatchNotFound; int i; int san_names_nb = -1; STACK_OF(GENERAL_NAME) *san_names = NULL; // Try to extract the names within the SAN extension from the certificate san_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL); if (san_names == NULL) { return NoSANPresent; } san_names_nb = sk_GENERAL_NAME_num(san_names); // Check each name within the extension for (i=0; i<san_names_nb; i++) { const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i); if (current_name->type == GEN_DNS) { // Current name is a DNS name, let's check it result = validate_name(hostname, current_name->d.dNSName); if (result != MatchNotFound) { break; } } } sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); return result; }
static int verify_hostname(X509 *cert, const char *hostname) { int len; X509_NAME *subj; char cname[1000]; int i, found; STACK_OF(GENERAL_NAME) *subj_alt_names; /* try the DNS subjectAltNames */ found = 0; if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) { int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names); for (i = 0; !found && i < num_subj_alt_names; i++) { GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i); if (subj_alt_name->type == GEN_DNS && strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length && host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data))) found = 1; } sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free); } if (found) return 0; /* try the common name */ if (!(subj = X509_get_subject_name(cert))) return error("cannot get certificate subject"); if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0) return error("cannot get certificate common name"); if (strlen(cname) == (size_t)len && host_matches(hostname, cname)) return 0; return error("certificate owner '%s' does not match hostname '%s'", cname, hostname); }
/* retrieve basic constraints ingredients */ BOOL modssl_X509_getBC(X509 *cert, int *ca, int *pathlen) { BASIC_CONSTRAINTS *bc; BIGNUM *bn = NULL; char *cp; bc = X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL); if (bc == NULL) return FALSE; *ca = bc->ca; *pathlen = -1 /* unlimited */; if (bc->pathlen != NULL) { if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL) { BASIC_CONSTRAINTS_free(bc); return FALSE; } if ((cp = BN_bn2dec(bn)) == NULL) { BN_free(bn); BASIC_CONSTRAINTS_free(bc); return FALSE; } *pathlen = atoi(cp); OPENSSL_free(cp); BN_free(bn); } BASIC_CONSTRAINTS_free(bc); return TRUE; }
std::unique_ptr<std::list<std::string>> SSLUtil::getSubjectAltName( const X509* cert) { #ifdef OPENSSL_GE_101 auto nameList = folly::make_unique<std::list<std::string>>(); GENERAL_NAMES* names = (GENERAL_NAMES*)X509_get_ext_d2i( (X509*)cert, NID_subject_alt_name, nullptr, nullptr); if (names) { auto guard = folly::makeGuard([names] { GENERAL_NAMES_free(names); }); size_t count = sk_GENERAL_NAME_num(names); CHECK(count < std::numeric_limits<int>::max()); for (int i = 0; i < (int)count; ++i) { GENERAL_NAME* generalName = sk_GENERAL_NAME_value(names, i); if (generalName->type == GEN_DNS) { ASN1_STRING* s = generalName->d.dNSName; const char* name = (const char*)ASN1_STRING_data(s); // I can't find any docs on what a negative return value here // would mean, so I'm going to ignore it. auto len = ASN1_STRING_length(s); DCHECK(len >= 0); if (size_t(len) != strlen(name)) { // Null byte(s) in the name; return an error rather than depending on // the caller to safely handle this case. return nullptr; } nameList->emplace_back(name); } } } return nameList; #else return nullptr; #endif }
/* Return the responder URI specified in the given certificate, or * NULL if none specified. */ static const char *extract_responder_uri(X509 *cert, apr_pool_t *pool) { STACK_OF(ACCESS_DESCRIPTION) *values; char *result = NULL; int j; values = X509_get_ext_d2i(cert, NID_info_access, NULL, NULL); if (!values) { return NULL; } for (j = 0; j < sk_ACCESS_DESCRIPTION_num(values) && !result; j++) { ACCESS_DESCRIPTION *value = sk_ACCESS_DESCRIPTION_value(values, j); /* Name found in extension, and is a URI: */ if (OBJ_obj2nid(value->method) == NID_ad_OCSP && value->location->type == GEN_URI) { result = apr_pstrdup(pool, (char *)value->location->d.uniformResourceIdentifier->data); } } AUTHORITY_INFO_ACCESS_free(values); return result; }
/* * Check if the certificate is revoked using OCSP. * Current implementation aren't using OCSP to validate the certificate. * If the OCSP server is set and the cert Key Usage is set as critical, * stop swupd operation. * * TODO: Implement proper check of OCSP. */ static int validate_authority(X509 *cert) { AUTHORITY_INFO_ACCESS *info; int n, i; // Check if Authority Information Access is critical if (!is_x509_ext_critical(cert, NID_info_access)) { return 0; } debug("Authority Information Access is critical. Checking certificate revocation method\n"); // Check if the OCSP URI is set info = X509_get_ext_d2i(cert, NID_info_access, NULL, NULL); if (!info) { goto error; } n = sk_ACCESS_DESCRIPTION_num(info); for (i = 0; i < n; i++) { ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) { error("OCSP uri found, but method not supported\n"); return -1; } } AUTHORITY_INFO_ACCESS_free(info); error: error("Supported Authority Information Access methods not found in the certificate.\n"); return -1; }
bool PeerID::Certificate::checkAltNames(boost::asio::ip::address& address) const { GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>( X509_get_ext_d2i(x509_, NID_subject_alt_name, 0, 0)); BOOST_SCOPE_EXIT(gens){ GENERAL_NAMES_free(gens); }BOOST_SCOPE_EXIT_END; for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i) { GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i); if (gen->type == GEN_IPADD) { ASN1_OCTET_STRING* ip = gen->d.iPAddress; if (ip->type == V_ASN1_OCTET_STRING && ip->data) { return ( (address.is_v4() && ip->length == 4 && std::memcmp(address.to_v4().to_bytes().data(), ip->data, 4) == 0) || (address.is_v6() && ip->length == 16 && std::memcmp(address.to_v6().to_bytes().data(), ip->data, 16) == 0) ); } } } }
static void setup_crldp(X509 *x) { int i; x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); }
/* Gets information about the peer's X509 cert as a tsi_peer object. */ static tsi_result peer_from_x509(X509* cert, int include_certificate_type, tsi_peer* peer) { /* TODO(jboeuf): Maybe add more properties. */ GENERAL_NAMES* subject_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0); int subject_alt_name_count = (subject_alt_names != NULL) ? sk_GENERAL_NAME_num(subject_alt_names) : 0; size_t property_count = (include_certificate_type ? 1 : 0) + 1 /* common name */ + subject_alt_name_count; tsi_result result = tsi_construct_peer(property_count, peer); if (result != TSI_OK) return result; do { if (include_certificate_type) { result = tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, &peer->properties[0]); if (result != TSI_OK) break; } result = peer_property_from_x509_common_name( cert, &peer->properties[include_certificate_type ? 1 : 0]); if (result != TSI_OK) break; if (subject_alt_name_count != 0) { result = add_subject_alt_names_properties_to_peer(peer, subject_alt_names, subject_alt_name_count); if (result != TSI_OK) break; } } while (0); if (subject_alt_names != NULL) { sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free); } if (result != TSI_OK) tsi_peer_destruct(peer); return result; }
static int check_alt_names(X509 *cert, const char *hostname) { STACK_OF(GENERAL_NAME) *alt_names; int i, num; int ret = 1; union { struct in_addr v4; struct in6_addr v6; } ip; unsigned ip_size = 0; /* check whether @hostname is an ip address */ if (strchr(hostname, ':') != NULL) { ip_size = 16; ret = inet_pton(AF_INET6, hostname, &ip.v6); } else { ip_size = 4; ret = inet_pton(AF_INET, hostname, &ip.v4); } if (ret == 0) return -1; ret = -1; alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (!alt_names) return ret; num = sk_GENERAL_NAME_num(alt_names); tdsdump_log(TDS_DBG_INFO1, "Alt names number %d\n", num); for (i = 0; i < num; ++i) { const char *altptr; size_t altlen; const GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i); if (!name) continue; altptr = (const char *) ASN1_STRING_data(name->d.ia5); altlen = (size_t) ASN1_STRING_length(name->d.ia5); if (name->type == GEN_DNS && ip_size == 0) { ret = 0; if (!check_name_match(name->d.dNSName, hostname)) continue; } else if (name->type == GEN_IPADD && ip_size != 0) { ret = 0; if (altlen != ip_size || memcmp(altptr, &ip, altlen) != 0) continue; } else { continue; } sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); return 1; } sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); return ret; }
char * check_alt_names(char *host, char *fqdn, X509 *x509) { char *found, *buf; const GENERAL_NAMES *ans; const GENERAL_NAME *p; int n; ans = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL); if (ans == NULL) return (NULL); n = sk_GENERAL_NAME_num(ans); found = NULL; while (n-- > 0 && found == NULL) { p = sk_GENERAL_NAME_value(ans, n); if (p == NULL || p->type != GEN_DNS) continue; if (ASN1_STRING_to_UTF8((u_char **)&buf, p->d.dNSName) <= 0) continue; if (fnmatch(buf, host, FNM_NOESCAPE|FNM_CASEFOLD) == 0 || (fqdn != NULL && fnmatch(buf, fqdn, FNM_NOESCAPE|FNM_CASEFOLD) == 0)) found = buf; OPENSSL_free(buf); } sk_GENERAL_NAME_free(ans); return (found); }
// retrieve the key usage, which specifies how the cert can be used. // LLSD _key_usage_ext(X509* cert) { LLSD result; ASN1_STRING *usage_str = (ASN1_STRING *)X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL); if(usage_str) { result = LLSD::emptyArray(); long usage = 0; if(usage_str->length > 0) { usage = usage_str->data[0]; if(usage_str->length > 1) { usage |= usage_str->data[1] << 8; } } ASN1_STRING_free(usage_str); if(usage) { if(usage & KU_DIGITAL_SIGNATURE) result.append(LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE)); if(usage & KU_NON_REPUDIATION) result.append(LLSD((std::string)CERT_KU_NON_REPUDIATION)); if(usage & KU_KEY_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT)); if(usage & KU_DATA_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_DATA_ENCIPHERMENT)); if(usage & KU_KEY_AGREEMENT) result.append(LLSD((std::string)CERT_KU_KEY_AGREEMENT)); if(usage & KU_KEY_CERT_SIGN) result.append(LLSD((std::string)CERT_KU_CERT_SIGN)); if(usage & KU_CRL_SIGN) result.append(LLSD((std::string)CERT_KU_CRL_SIGN)); if(usage & KU_ENCIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_ENCIPHER_ONLY)); if(usage & KU_DECIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_DECIPHER_ONLY)); } } return result; }
// Retrieve the basic constraints info LLSD _basic_constraints_ext(X509* cert) { LLSD result; BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL); if(bs) { result = LLSD::emptyMap(); // Determines whether the cert can be used as a CA result[CERT_BASIC_CONSTRAINTS_CA] = (bool)bs->ca; if(bs->pathlen) { // the pathlen determines how deep a certificate chain can be from // this CA if((bs->pathlen->type == V_ASN1_NEG_INTEGER) || !bs->ca) { result[CERT_BASIC_CONSTRAINTS_PATHLEN] = 0; } else { result[CERT_BASIC_CONSTRAINTS_PATHLEN] = (int)ASN1_INTEGER_get(bs->pathlen); } } } return result; }
/******************************************************************************* 函数名称: cert_ku_accept 功能描述: 查看某个证书是否有某种密钥用途 输入参数: X509 *x:证书 u32 kusage:密钥用途 输出参数: 无 返 回 值: 1,有该密钥用途;-1,没有 -------------------------------------------------------------------------------- 最近一次修改记录: 修改作者:王朝 修改目的:添加新函数 修改日期:2009年12月28日 *********************************************************************************/ s32 cert_ku_accept(X509 *x,u32 kusage) { ASN1_BIT_STRING *usage = NULL; if(NULL != (usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) { if(usage->length > 0) { x->ex_kusage = usage->data[0]; if(usage->length > 1) { x->ex_kusage |= usage->data[1] << 8; } } else { x->ex_kusage = 0; } ASN1_BIT_STRING_free(usage); if( (x)->ex_kusage & (kusage) ) { return 1; } else { return -1; } } else { return -1; } }
static int verify_hostname(const char *hostname, X509 *cert, char *errbuf, size_t errlen) { int i; /* domainname is the "domain" we wan't to access (actually hostname * with first part of the DNS name removed) */ const char *domainname = strchr(hostname, '.'); if(domainname != NULL) { domainname++; if(strlen(domainname) == 0) domainname = NULL; } // First check commonName X509_NAME *subjectName; char commonName[256]; subjectName = X509_get_subject_name(cert); if(X509_NAME_get_text_by_NID(subjectName, NID_commonName, commonName, sizeof(commonName)) != -1) { if(!strcmp(commonName, hostname)) return 0; } // Then check altNames GENERAL_NAMES *names = X509_get_ext_d2i( cert, NID_subject_alt_name, 0, 0); if(names == NULL) { snprintf(errbuf, errlen, "SSL: No subjectAltName extension"); return -1; } const int num_names = sk_GENERAL_NAME_num(names); for(i = 0; i < num_names; ++i ) { GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i); unsigned char *dns; int match; if(name->type != GEN_DNS) continue; ASN1_STRING_to_UTF8(&dns, name->d.dNSName); if(dns[0] == '*' && dns[1] == '.') { match = domainname != NULL && !strcasecmp((char *)dns+2, domainname); } else { match = !strcasecmp((char *)dns, hostname); } OPENSSL_free(dns); if(match) return 0; } snprintf(errbuf, errlen, "SSL: Hostname mismatch"); return -1; }
/* based on verify_extract_name from tls_client.c in postfix */ static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname) { int gen_index, gen_count; gboolean matched = FALSE, has_dns_name = FALSE; const char *cert_dns_name; char *cert_subject_cn; const GENERAL_NAME *gn; STACK_OF(GENERAL_NAME) * gens; GString *alt_names; alt_names = g_string_new(""); /* Verify the dNSName(s) in the peer certificate against the hostname. */ gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0); if (gens) { gen_count = sk_GENERAL_NAME_num(gens); for (gen_index = 0; gen_index < gen_count && !matched; ++gen_index) { gn = sk_GENERAL_NAME_value(gens, gen_index); if (gn->type != GEN_DNS) continue; /* Even if we have an invalid DNS name, we still ultimately ignore the CommonName, because subjectAltName:DNS is present (though malformed). */ has_dns_name = TRUE; cert_dns_name = tls_dns_name(gn); if (cert_dns_name && *cert_dns_name) { g_string_append_printf(alt_names, " '%s'", cert_dns_name); matched = match_hostname(cert_dns_name, hostname); } } /* Free stack *and* member GENERAL_NAME objects */ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); } if (has_dns_name) { if (! matched) { /* The CommonName in the issuer DN is obsolete when SubjectAltName is available. */ g_warning("None of the Subject Alt Names%s in the certificate match hostname '%s'", alt_names->str, hostname); } g_string_free(alt_names, TRUE); return matched; } else { /* No subjectAltNames, look at CommonName */ g_string_free(alt_names, TRUE); cert_subject_cn = tls_text_name(X509_get_subject_name(cert), NID_commonName); if (cert_subject_cn && *cert_subject_cn) { matched = match_hostname(cert_subject_cn, hostname); if (! matched) { g_warning("SSL certificate common name '%s' doesn't match host name '%s'", cert_subject_cn, hostname); } } else { g_warning("No subjectAltNames and no valid common name in certificate"); } free(cert_subject_cn); } return matched; }
/* * For each name in the cert. Iterate them. Call the callback. If one returns true, then consider it validated, * if none of them return true, the cert is considered invalid. */ static uint8_t s2n_verify_host_information(struct s2n_x509_validator *validator, struct s2n_connection *conn, X509 *public_cert) { 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); } } GENERAL_NAMES_free(names_list); /* if no SubjectAltNames of type DNS found, go to the common name. */ if (!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); memset_check(&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); lte_check(len, sizeof(peer_cn) - 1); memcpy_check(peer_cn, ASN1_STRING_data(common_name), len); verified = conn->verify_host_fn(peer_cn, len, conn->data_for_verify_host); } } } } } return verified; }
/* check the identity in a certificate against a hostname */ RD_BOOL crypto_cert_verify_peer_identity(CryptoCert cert, const char * peer) { X509_NAME *subject_name = NULL; X509_NAME_ENTRY *entry = NULL; ASN1_STRING *asn1str = NULL; //GENERAL_NAMES *subjectAltNames = NULL; unsigned char *ustr = NULL; char *str = NULL; int i, len; #if 0 /* Check cert for subjectAltName extensions */ /* things to check: ipv4/ipv6 address, hostname in normal form and in DC= form */ i = -1; for (;;) { subjectAltNames = X509_get_ext_d2i(cert->px509, NID_subject_alt_name, NULL, NULL); if (ext == NULL) break; }n /* Check against ip address of server */ #endif /* Check commonName */ subject_name = X509_get_subject_name(cert->px509); if (!subject_name) { printf("crypto_cert_verify_peer_identity: failed to get subject name\n"); goto exit; } /* try to find a common name that matches the peer hostname */ /* TODO: cn migth also be in DC=www,DC=redhat,DC=com format? */ i = -1; for (;;) { entry = NULL; i = X509_NAME_get_index_by_NID(subject_name, NID_commonName, i); if (i == -1) break; entry = X509_NAME_get_entry(subject_name, i); asn1str = X509_NAME_ENTRY_get_data(entry); len = ASN1_STRING_to_UTF8(&ustr, asn1str); str = (char *)ustr; if (strcmp(str, peer) == 0) break; /* found a match */ } if (!entry) { printf("crypto_cert_verify_peer_identity: certificate belongs to %s, " "but connection is to %s\n", str ? str : "unknown id", peer); return False; } exit: return True; }
static void CheckCRL(X509 *x509) { int idx = -1; do { int critical = -1; STACK_OF(DIST_POINT) *crls = X509_get_ext_d2i(x509, NID_crl_distribution_points, &critical, &idx); if (crls == NULL) { if (critical >= 0) { /* Found but fails to parse */ SetError(ERR_INVALID); continue; } /* Not found */ break; } for (int i = 0; i < sk_DIST_POINT_num(crls); i++) { DIST_POINT *dp = sk_DIST_POINT_value(crls, i); if (dp->distpoint == NULL && dp->CRLissuer == NULL) { SetError(ERR_INVALID_CRL_DIST_POINT); } if (dp->distpoint != NULL && dp->distpoint->type == 0) { /* full name */ for (int j = 0; j < sk_GENERAL_NAME_num(dp->distpoint->name.fullname); j++) { GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->distpoint->name.fullname, j); int type; ASN1_STRING *uri = GENERAL_NAME_get0_value(gen, &type); if (type == GEN_URI) { CheckValidURL(ASN1_STRING_get0_data(uri), ASN1_STRING_length(uri)); } else { SetInfo(INF_CRL_NOT_URL); } CheckGeneralNameType(gen); } } else { /* relative name */ SetWarning(WARN_CRL_RELATIVE); } } sk_DIST_POINT_pop_free(crls, DIST_POINT_free); } while (1); }
/* This code is based heavily on the example provided in "Secure Programming * Cookbook for C and C++". */ int _mosquitto_verify_certificate_hostname(X509 *cert, const char *hostname) { int i; char name[256]; X509_NAME *subj; bool have_san_dns = false; STACK_OF(GENERAL_NAME) *san; const GENERAL_NAME *nval; const unsigned char *data; unsigned char ipv6_addr[16]; unsigned char ipv4_addr[4]; int ipv6_ok; int ipv4_ok; #ifdef WIN32 ipv6_ok = InetPton(AF_INET6, hostname, &ipv6_addr); ipv4_ok = InetPton(AF_INET, hostname, &ipv4_addr); #else ipv6_ok = inet_pton(AF_INET6, hostname, &ipv6_addr); ipv4_ok = inet_pton(AF_INET, hostname, &ipv4_addr); #endif san = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if(san){ for(i=0; i<sk_GENERAL_NAME_num(san); i++){ nval = sk_GENERAL_NAME_value(san, i); if(nval->type == GEN_DNS){ data = ASN1_STRING_data(nval->d.dNSName); if(data && match_hostname((char *)data, hostname)){ return 1; } have_san_dns = true; }else if(nval->type == GEN_IPADD){ data = ASN1_STRING_data(nval->d.iPAddress); if(nval->d.iPAddress->length == 4 && ipv4_ok){ if(!memcmp(ipv4_addr, data, 4)){ return 1; } }else if(nval->d.iPAddress->length == 16 && ipv6_ok){ if(!memcmp(ipv6_addr, data, 16)){ return 1; } } } } if(have_san_dns){ /* Only check CN if subjectAltName DNS entry does not exist. */ return 0; } } subj = X509_get_subject_name(cert); if(X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0){ name[sizeof(name) - 1] = '\0'; if (!strcasecmp(name, hostname)) return 1; } return 0; }
static int verify_callback(int ok, X509_STORE_CTX *ctx) { char *userid; X509 *xs; PROXY_CERT_INFO_EXTENSION *pci; char *credstr; PVFS_credentials *credentials; char error_msg[256]; int ret; /* prior verifies have succeeded */ if (ok == 1) { /* parse the credential string uid/gid from the policy */ xs = ctx->current_cert; if (xs->ex_flags & EXFLAG_PROXY) { /* get userid for error logging */ userid = (char *) X509_STORE_CTX_get_ex_data(ctx, get_proxy_auth_ex_data_userid()); /* get credentials in {UID}/{GID} form from cert policy */ pci = (PROXY_CERT_INFO_EXTENSION *) X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL); if (pci->proxyPolicy->policy != NULL && pci->proxyPolicy->policy->length > 0) { credstr = (char *) pci->proxyPolicy->policy->data; credentials = (PVFS_credentials *) X509_STORE_CTX_get_ex_data( ctx, get_proxy_auth_ex_data_cred()); ret = parse_credentials(credstr, &credentials->uid, &credentials->gid); if (ret != 0) { _snprintf(error_msg, sizeof(error_msg), "User %s: proxy " "certificate contains invalid credential policy", userid); report_cert_error(error_msg); ok = 0; } } else { _snprintf(error_msg, sizeof(error_msg), "User %s: proxy " "certificate contains no credential policy", userid); report_cert_error(error_msg); ok = 0; } PROXY_CERT_INFO_EXTENSION_free(pci); } } return ok; }
static PARCCryptoHash * _GetPublickKeyDigest(PARCPkcs12KeyStore *keystore) { parcSecurity_AssertIsInitialized(); assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore"); if (keystore->public_key_digest == NULL) { AUTHORITY_KEYID *akid = X509_get_ext_d2i(keystore->x509_cert, NID_authority_key_identifier, NULL, NULL); if (akid != NULL) { ASN1_OCTET_STRING *skid = X509_get_ext_d2i(keystore->x509_cert, NID_subject_key_identifier, NULL, NULL); if (skid != NULL) { keystore->public_key_digest = parcBuffer_PutArray(parcBuffer_Allocate(skid->length), skid->length, skid->data); parcBuffer_Flip(keystore->public_key_digest); ASN1_OCTET_STRING_free(skid); } AUTHORITY_KEYID_free(akid); } } // If we could not load the digest from the certificate, then calculate it from the public key. if (keystore->public_key_digest == NULL) { uint8_t digestBuffer[SHA256_DIGEST_LENGTH]; int result = ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(), X509_get_X509_PUBKEY(keystore->x509_cert), digestBuffer, NULL); if (result != 1) { assertTrue(0, "Could not compute digest over certificate public key"); } else { keystore->public_key_digest = parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer); parcBuffer_Flip(keystore->public_key_digest); } } // This stores a reference, so keystore->public_key_digest will remain valid // even if the cryptoHasher is destroyed return parcCryptoHash_Create(PARC_HASH_SHA256, keystore->public_key_digest); }
// retrieve the subject key identifier of the cert LLSD _subject_key_identifier_ext(X509 *cert) { LLSD result; ASN1_OCTET_STRING *skeyid = (ASN1_OCTET_STRING *)X509_get_ext_d2i(cert, NID_subject_key_identifier, NULL, NULL); if(skeyid) { result = cert_string_from_octet_string(skeyid); } return result; }
int eventer_ssl_get_san_values(eventer_ssl_ctx_t *ctx, X509_STORE_CTX *x509ctx) { STACK_OF(GENERAL_NAME) * altnames; X509 *peer; int pos = 0; if(!x509ctx) return 0; peer = X509_STORE_CTX_get_current_cert(x509ctx); altnames = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL); if (altnames) { int i; int numalts = sk_GENERAL_NAME_num(altnames); char cn[4096]; mtev_boolean written = mtev_false; memset(cn, 0, 4096); for (i = 0; i < numalts; i++) { const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); if (check->type != GEN_DNS) { continue; } ASN1_STRING *data = check->d.dNSName; if (written) { /* Leave space for comma, space, data, and null byte */ if (data->length + pos > (int)sizeof(cn) - 3) { continue; } cn[pos] = ','; cn[pos+1] = ' '; pos+=2; } else { /* Leave space for data and null byte */ if (data->length + pos > (int)sizeof(cn) - 1) { continue; } written = mtev_true; } memcpy(cn+pos, data->data, data->length); cn[data->length+pos] = '\0'; pos = strlen(cn); } if (pos > 0) { if (ctx->san_list != NULL) { free(ctx->san_list); } ctx->san_list = strdup(cn); } sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free); } return 1; }
static bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) { bool retval = false; X509_EXTENSION *pExt; char *buf = 0; int length = 0; GENERAL_NAMES *extensions; int nid = OBJ_txt2nid(fieldname); extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL); if ( extensions ) { int numalts; int i; /* get amount of alternatives, * RFC2459 claims there MUST be at least * one, but we don't depend on it... */ numalts = sk_GENERAL_NAME_num(extensions); /* loop through all alternatives */ for (i=0; i<numalts; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i ); switch (name->type) { case GEN_EMAIL: ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5); if ( strlen (buf) != name->d.ia5->length ) { msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); OPENSSL_free (buf); } else { strncpynt(out, buf, size); OPENSSL_free(buf); retval = true; } break; default: msg (D_TLS_ERRORS, "ASN1 ERROR: can not handle field type %i", name->type); break; } } sk_GENERAL_NAME_free (extensions); } return retval; }
/* Server certificate name check, logic adapted from libcurl */ static int _SSL_check_server_cert(SSL *ssl, const char *hostname) { X509 *cert; X509_NAME *subject; const GENERAL_NAME *altname; STACK_OF(GENERAL_NAME) *altnames; ASN1_STRING *tmp; int i, n, match = -1; const char *p; if (SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE || (cert = SSL_get_peer_certificate(ssl)) == NULL) { return (1); } /* Check subjectAltName */ if ((altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL)) != NULL) { n = sk_GENERAL_NAME_num(altnames); for (i = 0; i < n && match != 1; i++) { altname = sk_GENERAL_NAME_value(altnames, i); p = (char *)ASN1_STRING_data(altname->d.ia5); if (altname->type == GEN_DNS) { match = (ASN1_STRING_length(altname->d.ia5) == strlen(p) && match_pattern(hostname, p)); } } GENERAL_NAMES_free(altnames); } /* No subjectAltName, try CN */ if (match == -1 && (subject = X509_get_subject_name(cert)) != NULL) { for (i = -1; (n = X509_NAME_get_index_by_NID(subject, NID_commonName, i)) >= 0; ) { i = n; } if (i >= 0) { if ((tmp = X509_NAME_ENTRY_get_data( X509_NAME_get_entry(subject, i))) != NULL && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { p = (char *)ASN1_STRING_data(tmp); match = (ASN1_STRING_length(tmp) == strlen(p) && match_pattern(hostname, p)); } } } X509_free(cert); return (match > 0); }
/** * Returns current certificate key usage bits * * @return key usage bits */ std::vector<digidoc::X509Cert::KeyUsage> digidoc::X509Cert::getKeyUsage() const throw(IOException) { ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING*)X509_get_ext_d2i(cert, NID_key_usage, 0, 0); if(!keyusage) return std::vector<KeyUsage>(); std::vector<KeyUsage> usage; for(int n = 0; n < 9; ++n) { if(ASN1_BIT_STRING_get_bit(keyusage, n)) usage.push_back(KeyUsage(n)); } ASN1_BIT_STRING_free(keyusage); return usage; }