int ssl_check_subject_altname(X509 *cert, char *host) { STACK_OF(GENERAL_NAME) *altname_stack = NULL; union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; int addrlen, type; int count, i; int rv = -1; altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (altname_stack == NULL) return -1; if (inet_pton(AF_INET, host, &addrbuf) == 1) { type = GEN_IPADD; addrlen = 4; } else if (inet_pton(AF_INET6, host, &addrbuf) == 1) { type = GEN_IPADD; addrlen = 16; } else type = GEN_DNS; count = sk_GENERAL_NAME_num(altname_stack); for (i = 0; i < count; i++) { GENERAL_NAME *altname; altname = sk_GENERAL_NAME_value(altname_stack, i); if (altname->type != type) continue; if (type == GEN_DNS) { unsigned char *data; int format; format = ASN1_STRING_type(altname->d.dNSName); if (format == V_ASN1_IA5STRING) { data = ASN1_STRING_data(altname->d.dNSName); if (ASN1_STRING_length(altname->d.dNSName) != (int)strlen(data)) { fprintf(ttyout, "%s: NUL byte in " "subjectAltName, probably a " "malicious certificate.\n", getprogname()); rv = -2; break; } if (ssl_match_hostname(data, host) == 0) { rv = 0; break; } } else fprintf(ttyout, "%s: unhandled subjectAltName " "dNSName encoding (%d)\n", getprogname(), format); } else if (type == GEN_IPADD) { unsigned char *data; int datalen; datalen = ASN1_STRING_length(altname->d.iPAddress); data = ASN1_STRING_data(altname->d.iPAddress); if (datalen == addrlen && memcmp(data, &addrbuf, addrlen) == 0) { rv = 0; break; } } } sk_GENERAL_NAME_free(altname_stack); return rv; }
gboolean tls_verify_certificate_name(X509 *cert, const gchar *host_name) { gchar pattern_buf[256]; gint ext_ndx; gboolean found = FALSE, result = FALSE; ext_ndx = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); if (ext_ndx >= 0) { /* ok, there's a subjectAltName extension, check that */ X509_EXTENSION *ext; STACK_OF(GENERAL_NAME) *alt_names; GENERAL_NAME *gen_name; ext = X509_get_ext(cert, ext_ndx); alt_names = X509V3_EXT_d2i(ext); if (alt_names) { gint num, i; num = sk_GENERAL_NAME_num(alt_names); for (i = 0; !result && i < num; i++) { gen_name = sk_GENERAL_NAME_value(alt_names, i); if (gen_name->type == GEN_DNS) { guchar *dnsname = ASN1_STRING_data(gen_name->d.dNSName); guint dnsname_len = ASN1_STRING_length(gen_name->d.dNSName); if (dnsname_len > sizeof(pattern_buf) - 1) { found = TRUE; result = FALSE; break; } memcpy(pattern_buf, dnsname, dnsname_len); pattern_buf[dnsname_len] = 0; /* we have found a DNS name as alternative subject name */ found = TRUE; result = tls_wildcard_match(host_name, pattern_buf); } else if (gen_name->type == GEN_IPADD) { char *dotted_ip = inet_ntoa(*(struct in_addr *) gen_name->d.iPAddress->data); g_strlcpy(pattern_buf, dotted_ip, sizeof(pattern_buf)); found = TRUE; result = strcasecmp(host_name, pattern_buf) == 0; } } sk_GENERAL_NAME_free(alt_names); } } if (!found) { /* hmm. there was no subjectAltName (this is deprecated, but still * widely used), look up the Subject, most specific CN */ X509_NAME *name; name = X509_get_subject_name(cert); if (X509_NAME_get_text_by_NID(name, NID_commonName, pattern_buf, sizeof(pattern_buf)) != -1) { result = tls_wildcard_match(host_name, pattern_buf); } } if (!result) { msg_error("Certificate subject does not match configured hostname", evt_tag_str("hostname", host_name), evt_tag_str("certificate", pattern_buf), NULL); } else { msg_verbose("Certificate subject matches configured hostname", evt_tag_str("hostname", host_name), evt_tag_str("certificate", pattern_buf), NULL); } return result; }
int ma_ssl_verify_server_cert(MARIADB_SSL *cssl) { X509 *cert; MYSQL *mysql; X509_NAME *x509sn; int cn_pos; X509_NAME_ENTRY *cn_entry; ASN1_STRING *cn_asn1; const char *cn_str; SSL *ssl; MARIADB_PVIO *pvio; if (!cssl || !cssl->ssl) return 1; ssl= (SSL *)cssl->ssl; mysql= (MYSQL *)SSL_get_app_data(ssl); pvio= mysql->net.pvio; if (!mysql->host) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), "Invalid (empty) hostname"); return 1; } if (!(cert= SSL_get_peer_certificate(ssl))) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), "Unable to get server certificate"); return 1; } x509sn= X509_get_subject_name(cert); if ((cn_pos= X509_NAME_get_index_by_NID(x509sn, NID_commonName, -1)) < 0) goto error; if (!(cn_entry= X509_NAME_get_entry(x509sn, cn_pos))) goto error; if (!(cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry))) goto error; cn_str = (char *)ASN1_STRING_data(cn_asn1); /* Make sure there is no embedded \0 in the CN */ if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn_str)) goto error; if (strcmp(cn_str, mysql->host)) goto error; X509_free(cert); return 0; error: X509_free(cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), "Validation of SSL server certificate failed"); return 1; }
inline size_t string::size() { return ASN1_STRING_length(ptr().get()); }
static int tlso_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in ) { tlso_session *s = (tlso_session *)sess; int i, ret = LDAP_LOCAL_ERROR; X509 *x; const char *name; char *ptr; int ntype = IS_DNS, nlen; #ifdef LDAP_PF_INET6 struct in6_addr addr; #else struct in_addr addr; #endif if( ldap_int_hostname && ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) { name = ldap_int_hostname; } else { name = name_in; } nlen = strlen(name); x = tlso_get_cert(s); if (!x) { Debug( LDAP_DEBUG_ANY, "TLS: unable to get peer certificate.\n", 0, 0, 0 ); /* If this was a fatal condition, things would have * aborted long before now. */ return LDAP_SUCCESS; } #ifdef LDAP_PF_INET6 if (inet_pton(AF_INET6, name, &addr)) { ntype = IS_IP6; } else #endif if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; } i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); if (i >= 0) { X509_EXTENSION *ex; STACK_OF(GENERAL_NAME) *alt; ex = X509_get_ext(x, i); alt = X509V3_EXT_d2i(ex); if (alt) { int n, len2 = 0; char *domain = NULL; GENERAL_NAME *gn; if (ntype == IS_DNS) { domain = strchr(name, '.'); if (domain) { len2 = nlen - (domain-name); } } n = sk_GENERAL_NAME_num(alt); for (i=0; i<n; i++) { char *sn; int sl; gn = sk_GENERAL_NAME_value(alt, i); if (gn->type == GEN_DNS) { if (ntype != IS_DNS) continue; sn = (char *) ASN1_STRING_data(gn->d.ia5); sl = ASN1_STRING_length(gn->d.ia5); /* ignore empty */ if (sl == 0) continue; /* Is this an exact match? */ if ((nlen == sl) && !strncasecmp(name, sn, nlen)) { break; } /* Is this a wildcard match? */ if (domain && (sn[0] == '*') && (sn[1] == '.') && (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2)) { break; } } else if (gn->type == GEN_IPADD) { if (ntype == IS_DNS) continue; sn = (char *) ASN1_STRING_data(gn->d.ia5); sl = ASN1_STRING_length(gn->d.ia5); #ifdef LDAP_PF_INET6 if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) { continue; } else #endif if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) { continue; } if (!memcmp(sn, &addr, sl)) { break; } } } GENERAL_NAMES_free(alt); if (i < n) { /* Found a match */ ret = LDAP_SUCCESS; } } } if (ret != LDAP_SUCCESS) { X509_NAME *xn; X509_NAME_ENTRY *ne; ASN1_OBJECT *obj; ASN1_STRING *cn = NULL; int navas; /* find the last CN */ obj = OBJ_nid2obj( NID_commonName ); if ( !obj ) goto no_cn; /* should never happen */ xn = X509_get_subject_name(x); navas = X509_NAME_entry_count( xn ); for ( i=navas-1; i>=0; i-- ) { ne = X509_NAME_get_entry( xn, i ); if ( !OBJ_cmp( X509_NAME_ENTRY_get_object(ne), obj )) { cn = X509_NAME_ENTRY_get_data( ne ); break; } } if( !cn ) { no_cn: Debug( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n", 0, 0, 0 ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); } else if ( cn->length == nlen && strncasecmp( name, (char *) cn->data, nlen ) == 0 ) { ret = LDAP_SUCCESS; } else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) { char *domain = strchr(name, '.'); if( domain ) { int dlen; dlen = nlen - (domain-name); /* Is this a wildcard match? */ if ((dlen == cn->length-1) && !strncasecmp(domain, (char *) &cn->data[1], dlen)) { ret = LDAP_SUCCESS; } } } if( ret == LDAP_LOCAL_ERROR ) { Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " "common name in certificate (%.*s).\n", name, cn->length, cn->data ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: hostname does not match CN in peer certificate")); } } X509_free(x); return ret; }
/** * From gnutls and spice red_peer.c * TODO: switch to gnutls and get rid of this * * This function will check if the given certificate's subject matches * the given hostname. This is a basic implementation of the matching * described in RFC2818 (HTTPS), which takes into account wildcards, * and the DNSName/IPAddress subject alternative name PKIX extension. * * Returns: 1 for a successful match, and 0 on failure. **/ static int verify_hostname(X509* cert, const char *hostname) { GENERAL_NAMES* subject_alt_names; int found_dns_name = 0; struct in_addr addr; int addr_len = 0; int cn_match = 0; if (!cert) { SPICE_DEBUG("warning: no cert!"); return 0; } // only IpV4 supported if (inet_aton(hostname, &addr)) { addr_len = sizeof(struct in_addr); } /* try matching against: * 1) a DNS name as an alternative name (subjectAltName) extension * in the certificate * 2) the common name (CN) in the certificate * * either of these may be of the form: *.domain.tld * * only try (2) if there is no subjectAltName extension of * type dNSName */ /* Check through all included subjectAltName extensions, comparing * against all those of type dNSName. */ subject_alt_names = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (subject_alt_names) { int num_alts = sk_GENERAL_NAME_num(subject_alt_names); int i; for (i = 0; i < num_alts; i++) { const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i); if (name->type == GEN_DNS) { found_dns_name = 1; if (_gnutls_hostname_compare((char *)ASN1_STRING_data(name->d.dNSName), ASN1_STRING_length(name->d.dNSName), hostname)) { SPICE_DEBUG("alt name match=%s", ASN1_STRING_data(name->d.dNSName)); GENERAL_NAMES_free(subject_alt_names); return 1; } } else if (name->type == GEN_IPADD) { int alt_ip_len = ASN1_STRING_length(name->d.iPAddress); found_dns_name = 1; if ((addr_len == alt_ip_len)&& !memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) { SPICE_DEBUG("alt name IP match=%s", inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName)))); GENERAL_NAMES_free(subject_alt_names); return 1; } } } GENERAL_NAMES_free(subject_alt_names); } if (found_dns_name) { SPICE_DEBUG("warning: SubjectAltName mismatch"); return 0; } /* extracting commonNames */ X509_NAME* subject = X509_get_subject_name(cert); if (subject) { int pos = -1; X509_NAME_ENTRY* cn_entry; ASN1_STRING* cn_asn1; while ((pos = X509_NAME_get_index_by_NID(subject, NID_commonName, pos)) != -1) { cn_entry = X509_NAME_get_entry(subject, pos); if (!cn_entry) { continue; } cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry); if (!cn_asn1) { continue; } if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1), ASN1_STRING_length(cn_asn1), hostname)) { SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1)); cn_match = 1; break; } } } if (!cn_match) SPICE_DEBUG("warning: common name mismatch"); return cn_match; }
static int dh_cms_encrypt(CMS_RecipientInfo *ri) { EVP_PKEY_CTX *pctx; EVP_PKEY *pkey; EVP_CIPHER_CTX *ctx; int keylen; X509_ALGOR *talg, *wrap_alg = NULL; ASN1_OBJECT *aoid; ASN1_BIT_STRING *pubkey; ASN1_STRING *wrap_str; ASN1_OCTET_STRING *ukm; unsigned char *penc = NULL, *dukm = NULL; int penclen; size_t dukmlen = 0; int rv = 0; int kdf_type, wrap_nid; const EVP_MD *kdf_md; pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (!pctx) return 0; /* Get ephemeral key */ pkey = EVP_PKEY_CTX_get0_pkey(pctx); if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey, NULL, NULL, NULL)) goto err; X509_ALGOR_get0(&aoid, NULL, NULL, talg); /* Is everything uninitialised? */ if (aoid == OBJ_nid2obj(NID_undef)) { ASN1_INTEGER *pubk = BN_to_ASN1_INTEGER(pkey->pkey.dh->pub_key, NULL); if (!pubk) goto err; /* Set the key */ penclen = i2d_ASN1_INTEGER(pubk, &penc); ASN1_INTEGER_free(pubk); if (penclen <= 0) goto err; ASN1_STRING_set0(pubkey, penc, penclen); pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT; penc = NULL; X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber), V_ASN1_UNDEF, NULL); } /* See if custom paraneters set */ kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx); if (kdf_type <= 0) goto err; if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md)) goto err; if (kdf_type == EVP_PKEY_DH_KDF_NONE) { kdf_type = EVP_PKEY_DH_KDF_X9_42; if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0) goto err; } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42) /* Unknown KDF */ goto err; if (kdf_md == NULL) { /* Only SHA1 supported */ kdf_md = EVP_sha1(); if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0) goto err; } else if (EVP_MD_type(kdf_md) != NID_sha1) /* Unsupported digest */ goto err; if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm)) goto err; /* Get wrap NID */ ctx = CMS_RecipientInfo_kari_get0_ctx(ri); wrap_nid = EVP_CIPHER_CTX_type(ctx); if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0) goto err; keylen = EVP_CIPHER_CTX_key_length(ctx); /* Package wrap algorithm in an AlgorithmIdentifier */ wrap_alg = X509_ALGOR_new(); if (!wrap_alg) goto err; wrap_alg->algorithm = OBJ_nid2obj(wrap_nid); wrap_alg->parameter = ASN1_TYPE_new(); if (!wrap_alg->parameter) goto err; if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0) goto err; if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) { ASN1_TYPE_free(wrap_alg->parameter); wrap_alg->parameter = NULL; } if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) goto err; if (ukm) { dukmlen = ASN1_STRING_length(ukm); dukm = BUF_memdup(ASN1_STRING_data(ukm), dukmlen); if (!dukm) goto err; } if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) goto err; dukm = NULL; /* * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter * of another AlgorithmIdentifier. */ penc = NULL; penclen = i2d_X509_ALGOR(wrap_alg, &penc); if (!penc || !penclen) goto err; wrap_str = ASN1_STRING_new(); if (!wrap_str) goto err; ASN1_STRING_set0(wrap_str, penc, penclen); penc = NULL; X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH), V_ASN1_SEQUENCE, wrap_str); rv = 1; err: OPENSSL_free(penc); X509_ALGOR_free(wrap_alg); return rv; }
/* Quote from RFC2818 section 3.1 "Server Identity" If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead. Matching is performed using the matching rules specified by [RFC2459]. If more than one identity of a given type is present in the certificate (e.g., more than one dNSName name, a match in any one of the set is considered acceptable.) Names may contain the wildcard character * which is considered to match any single domain name component or component fragment. E.g., *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com but not bar.com. In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI. */ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) { bool matched = FALSE; /* no alternative match yet */ int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ int addrlen = 0; struct SessionHandle *data = conn->data; STACK_OF(GENERAL_NAME) *altnames; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif CURLcode res = CURLE_OK; #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in6_addr); } else #endif if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in_addr); } /* get a "list" of alternative names */ altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); if(altnames) { 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(altnames); /* loop through all alternatives while none has matched */ for (i=0; (i<numalts) && !matched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ const char *altptr = (char *)ASN1_STRING_data(check->d.ia5); int altlen; switch(target) { case GEN_DNS: /* name/pattern comparison */ /* The OpenSSL man page explicitly says: "In general it cannot be assumed that the data returned by ASN1_STRING_data() is null terminated or does not contain embedded nulls." But also that "The actual format of the data will depend on the actual string type itself: for example for and IA5String the data will be ASCII" Gisle researched the OpenSSL sources: "I checked the 0.9.6 and 0.9.8 sources before my patch and it always 0-terminates an IA5String." */ if (cert_hostcheck(altptr, conn->host.name)) matched = TRUE; break; case GEN_IPADD: /* IP address comparison */ /* compare alternative IP address if the data chunk is the same size our server IP address is */ altlen = ASN1_STRING_length(check->d.ia5); if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) matched = TRUE; break; } } } GENERAL_NAMES_free(altnames); } if(matched) /* an alternative name matched the server hostname */ infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); else { /* we have to look to the last occurence of a commonName in the distinguished one to get the most significant one. */ int j,i=-1 ; /* The following is done because of a bug in 0.9.6b */ unsigned char *nulstr = (unsigned char *)""; unsigned char *peer_CN = nulstr; X509_NAME *name = X509_get_subject_name(server_cert) ; if (name) while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0) i=j; /* we have the name entry and we will now convert this to a string that we can use for comparison. Doing this we support BMPstring, UTF8 etc. */ if (i>=0) { ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input is already UTF-8 encoded. We check for this case and copy the raw string manually to avoid the problem. This code can be made conditional in the future when OpenSSL has been fixed. Work-around brought by Alexis S. L. Carvalho. */ if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { j = ASN1_STRING_length(tmp); if (j >= 0) { peer_CN = OPENSSL_malloc(j+1); if (peer_CN) { memcpy(peer_CN, ASN1_STRING_data(tmp), j); peer_CN[j] = '\0'; } } } else /* not a UTF8 name */ j = ASN1_STRING_to_UTF8(&peer_CN, tmp); } if (peer_CN == nulstr) peer_CN = NULL; if (!peer_CN) { if(data->set.ssl.verifyhost > 1) { failf(data, "SSL: unable to obtain common name from peer certificate"); return CURLE_SSL_PEER_CERTIFICATE; } else { /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we output a note about the situation */ infof(data, "\t common name: WARNING couldn't obtain\n"); } } else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) { if(data->set.ssl.verifyhost > 1) { failf(data, "SSL: certificate subject name '%s' does not match " "target host name '%s'", peer_CN, conn->host.dispname); res = CURLE_SSL_PEER_CERTIFICATE; } else infof(data, "\t common name: %s (does not match '%s')\n", peer_CN, conn->host.dispname); } else { infof(data, "\t common name: %s (matched)\n", peer_CN); } if(peer_CN) OPENSSL_free(peer_CN); } return res; }
int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags) { int i, ret = 0; long l; unsigned char *p; OCSP_CERTID *cid = NULL; OCSP_BASICRESP *br = NULL; OCSP_RESPID *rid = NULL; OCSP_RESPDATA *rd = NULL; OCSP_CERTSTATUS *cst = NULL; OCSP_REVOKEDINFO *rev = NULL; OCSP_SINGLERESP *single = NULL; OCSP_RESPBYTES *rb = o->responseBytes; if (BIO_puts(bp,"OCSP Response Data:\n") <= 0) goto err; l=ASN1_ENUMERATED_get(o->responseStatus); if (BIO_printf(bp," OCSP Response Status: %s (0x%lx)\n", OCSP_response_status_str(l), l) <= 0) goto err; if (rb == NULL) return 1; if (BIO_puts(bp," Response Type: ") <= 0) goto err; if(i2a_ASN1_OBJECT(bp, rb->responseType) <= 0) goto err; if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) { BIO_puts(bp," (unknown response type)\n"); return 1; } p = ASN1_STRING_data(rb->response); i = ASN1_STRING_length(rb->response); if (!(br = OCSP_response_get1_basic(o))) goto err; rd = br->tbsResponseData; l=ASN1_INTEGER_get(rd->version); if (BIO_printf(bp,"\n Version: %lu (0x%lx)\n", l+1,l) <= 0) goto err; if (BIO_puts(bp," Responder Id: ") <= 0) goto err; rid = rd->responderId; switch (rid->type) { case V_OCSP_RESPID_NAME: X509_NAME_print_ex(bp, rid->value.byName, 0, XN_FLAG_ONELINE); break; case V_OCSP_RESPID_KEY: i2a_ASN1_STRING(bp, rid->value.byKey, V_ASN1_OCTET_STRING); break; } if (BIO_printf(bp,"\n Produced At: ")<=0) goto err; if (!ASN1_GENERALIZEDTIME_print(bp, rd->producedAt)) goto err; if (BIO_printf(bp,"\n Responses:\n") <= 0) goto err; for (i = 0; i < sk_OCSP_SINGLERESP_num(rd->responses); i++) { if (! sk_OCSP_SINGLERESP_value(rd->responses, i)) continue; single = sk_OCSP_SINGLERESP_value(rd->responses, i); cid = single->certId; if(ocsp_certid_print(bp, cid, 4) <= 0) goto err; cst = single->certStatus; if (BIO_printf(bp," Cert Status: %s", OCSP_cert_status_str(cst->type)) <= 0) goto err; if (cst->type == V_OCSP_CERTSTATUS_REVOKED) { rev = cst->value.revoked; if (BIO_printf(bp, "\n Revocation Time: ") <= 0) goto err; if (!ASN1_GENERALIZEDTIME_print(bp, rev->revocationTime)) goto err; if (rev->revocationReason) { l=ASN1_ENUMERATED_get(rev->revocationReason); if (BIO_printf(bp, "\n Revocation Reason: %s (0x%lx)", OCSP_crl_reason_str(l), l) <= 0) goto err; } } if (BIO_printf(bp,"\n This Update: ") <= 0) goto err; if (!ASN1_GENERALIZEDTIME_print(bp, single->thisUpdate)) goto err; if (single->nextUpdate) { if (BIO_printf(bp,"\n Next Update: ") <= 0)goto err; if (!ASN1_GENERALIZEDTIME_print(bp,single->nextUpdate)) goto err; } if (!BIO_write(bp,"\n",1)) goto err; if (!X509V3_extensions_print(bp, "Response Single Extensions", single->singleExtensions, flags, 8)) goto err; if (!BIO_write(bp,"\n",1)) goto err; } if (!X509V3_extensions_print(bp, "Response Extensions", rd->responseExtensions, flags, 4)) if(X509_signature_print(bp, br->signatureAlgorithm, br->signature) <= 0) goto err; for (i=0; i<sk_X509_num(br->certs); i++) { X509_print(bp, sk_X509_value(br->certs,i)); PEM_write_bio_X509(bp,sk_X509_value(br->certs,i)); } ret = 1; err: OCSP_BASICRESP_free(br); return ret; }
gboolean z_proxy_ssl_host_iface_check_name_method(ZProxyHostIface *s, const gchar *host_name, gchar *reason_buf, gsize reason_len) { ZProxySslHostIface *self = Z_CAST(s, ZProxySslHostIface); gint ext_ndx; gboolean found = FALSE, result = FALSE; gchar pattern_buf[256]; if (self->hostname_checked) return self->hostname_check_result; pattern_buf[0] = 0; ext_ndx = X509_get_ext_by_NID(self->server_cert, NID_subject_alt_name, -1); if (ext_ndx >= 0) { /* ok, there's a subjectAltName extension, check that */ X509_EXTENSION *ext; STACK_OF(GENERAL_NAME) *alt_names; GENERAL_NAME *gen_name; ext = X509_get_ext(self->server_cert, ext_ndx); alt_names = X509V3_EXT_d2i(ext); if (alt_names) { gint num, i; num = sk_GENERAL_NAME_num(alt_names); for (i = 0; i < num; i++) { gen_name = sk_GENERAL_NAME_value(alt_names, i); if (gen_name->type == GEN_DNS) { guchar *dnsname = ASN1_STRING_data(gen_name->d.dNSName); guint dnsname_len = ASN1_STRING_length(gen_name->d.dNSName); if (dnsname_len > sizeof(pattern_buf) - 1) { found = TRUE; result = FALSE; break; } memcpy(pattern_buf, dnsname, dnsname_len); pattern_buf[dnsname_len] = 0; /* we have found a DNS name as alternative subject name */ found = TRUE; result = z_proxy_ssl_host_iface_check_wildcard(s->owner, host_name, pattern_buf); break; } else if (gen_name->type == GEN_IPADD) { z_inet_ntoa(pattern_buf, sizeof(pattern_buf), *(struct in_addr *) gen_name->d.iPAddress->data); found = TRUE; result = strcmp(host_name, pattern_buf) == 0; break; } } sk_GENERAL_NAME_free(alt_names); } } if (!found) { /* hmm. there was no subjectAltName (this is deprecated, but still * widely used), look up the Subject, most specific CN */ X509_NAME *name; name = X509_get_subject_name(self->server_cert); if (X509_NAME_get_text_by_NID(name, NID_commonName, pattern_buf, sizeof(pattern_buf)) != -1) { result = z_proxy_ssl_host_iface_check_wildcard(s->owner, host_name, pattern_buf); } } if (!result && reason_buf) { g_snprintf(reason_buf, reason_len, "Certificate does not belong to target host (certificate: %s, host %s)", pattern_buf, host_name); } self->hostname_checked = TRUE; self->hostname_check_result = result; return result; }
bool ssl_check_certificate (int fd, const char *host) { X509 *cert; GENERAL_NAMES *subjectAltNames; char common_name[256]; long vresult; bool success = true; bool alt_name_checked = false; /* If the user has specified --no-check-cert, we still want to warn him about problems with the server's certificate. */ const char *severity = opt.check_cert ? _("ERROR") : _("WARNING"); struct openssl_transport_context *ctx = fd_transport_context (fd); SSL *conn = ctx->conn; assert (conn != NULL); cert = SSL_get_peer_certificate (conn); if (!cert) { logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"), severity, quotearg_style (escape_quoting_style, host)); success = false; goto no_cert; /* must bail out since CERT is NULL */ } IF_DEBUG { char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0); char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0); DEBUGP (("certificate:\n subject: %s\n issuer: %s\n", quotearg_n_style (0, escape_quoting_style, subject), quotearg_n_style (1, escape_quoting_style, issuer))); OPENSSL_free (subject); OPENSSL_free (issuer); } vresult = SSL_get_verify_result (conn); if (vresult != X509_V_OK) { char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0); logprintf (LOG_NOTQUIET, _("%s: cannot verify %s's certificate, issued by %s:\n"), severity, quotearg_n_style (0, escape_quoting_style, host), quote_n (1, issuer)); /* Try to print more user-friendly (and translated) messages for the frequent verification errors. */ switch (vresult) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: logprintf (LOG_NOTQUIET, _(" Unable to locally verify the issuer's authority.\n")); break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: logprintf (LOG_NOTQUIET, _(" Self-signed certificate encountered.\n")); break; case X509_V_ERR_CERT_NOT_YET_VALID: logprintf (LOG_NOTQUIET, _(" Issued certificate not yet valid.\n")); break; case X509_V_ERR_CERT_HAS_EXPIRED: logprintf (LOG_NOTQUIET, _(" Issued certificate has expired.\n")); break; default: /* For the less frequent error strings, simply provide the OpenSSL error message. */ logprintf (LOG_NOTQUIET, " %s\n", X509_verify_cert_error_string (vresult)); } success = false; /* Fall through, so that the user is warned about *all* issues with the cert (important with --no-check-certificate.) */ } /* Check that HOST matches the common name in the certificate. #### The following remains to be done: - When matching against common names, it should loop over all common names and choose the most specific one, i.e. the last one, not the first one, which the current code picks. - Ensure that ASN1 strings from the certificate are encoded as UTF-8 which can be meaningfully compared to HOST. */ subjectAltNames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL); if (subjectAltNames) { /* Test subject alternative names */ /* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)? * Signal it by host_in_octet_string. */ ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host); int numaltnames = sk_GENERAL_NAME_num (subjectAltNames); int i; for (i=0; i < numaltnames; i++) { const GENERAL_NAME *name = sk_GENERAL_NAME_value (subjectAltNames, i); if (name) { if (host_in_octet_string) { if (name->type == GEN_IPADD) { /* Check for ipAddress */ /* TODO: Should we convert between IPv4-mapped IPv6 * addresses and IPv4 addresses? */ alt_name_checked = true; if (!ASN1_STRING_cmp (host_in_octet_string, name->d.iPAddress)) break; } } else if (name->type == GEN_DNS) { /* dNSName should be IA5String (i.e. ASCII), however who * does trust CA? Convert it into UTF-8 for sure. */ unsigned char *name_in_utf8 = NULL; /* Check for dNSName */ alt_name_checked = true; if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName)) { /* Compare and check for NULL attack in ASN1_STRING */ if (pattern_match ((char *)name_in_utf8, host) && (strlen ((char *)name_in_utf8) == (size_t) ASN1_STRING_length (name->d.dNSName))) { OPENSSL_free (name_in_utf8); break; } OPENSSL_free (name_in_utf8); } } } } sk_GENERAL_NAME_free (subjectAltNames); if (host_in_octet_string) ASN1_OCTET_STRING_free(host_in_octet_string); if (alt_name_checked == true && i >= numaltnames) { logprintf (LOG_NOTQUIET, _("%s: no certificate subject alternative name matches\n" "\trequested host name %s.\n"), severity, quote_n (1, host)); success = false; } } if (alt_name_checked == false) { /* Test commomName */ X509_NAME *xname = X509_get_subject_name(cert); common_name[0] = '\0'; X509_NAME_get_text_by_NID (xname, NID_commonName, common_name, sizeof (common_name)); if (!pattern_match (common_name, host)) { logprintf (LOG_NOTQUIET, _("\ %s: certificate common name %s doesn't match requested host name %s.\n"), severity, quote_n (0, common_name), quote_n (1, host)); success = false; }
static bool verifyHost(const std::string& host, const X509* cert) { if (host.empty() || cert == nullptr) { return false; } bool matched = false; STACK_OF(GENERAL_NAME)* altnames = (stack_st_GENERAL_NAME*)X509_get_ext_d2i( (X509*)cert, NID_subject_alt_name, nullptr, nullptr); int target = GEN_DNS; /// See x509v3.h in openssl project. struct in_addr addr4; struct in6_addr addr6; uint8_t ipver = 4; size_t addrlen = 0; bool result = true; if (inet_pton(AF_INET, host.c_str(), &addr4) == 1) { addrlen = sizeof(addr4); target = GEN_IPADD; /// See x509v3.h in openssl project. } else if (inet_pton(AF_INET6, host.c_str(), &addr6) == 1) { addrlen = sizeof(addr6); target = GEN_IPADD; ipver = 6; } if (altnames) { 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(altnames); /* loop through all alternatives while none has matched */ for (i = 0; (i < numalts) && !matched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME* check = sk_GENERAL_NAME_value(altnames, i); /* only check alternatives of the same type the target is */ if (check->type == target) { /* get data and length */ const char* altptr = (char*)ASN1_STRING_data(check->d.ia5); size_t altlen = (size_t)ASN1_STRING_length(check->d.ia5); switch (target) { case GEN_DNS: /* name/pattern comparison */ if ((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ certHostCheck(altptr, host.c_str())) { matched = true; } break; case GEN_IPADD: /* IP address comparison */ /* compare alternative IP address if the data chunk is the same size our server IP address is */ if (altlen == addrlen) { if (ipver == 4 && memcmp(altptr, &addr4, altlen) == 0) { matched = true; } else if (ipver == 6 && memcmp(altptr, &addr6, altlen) == 0) { matched = true; } } break; default: break; } } } GENERAL_NAMES_free(altnames); } if (matched) { // Success. } else if (altnames) { result = false; } else { /* If here, we have to look to the last occurrence of a commonName in the distinguished one to get the most significant one. */ /* Common name must be domain name. See: https://tools.ietf.org/html/rfc2818#section-3.1 */ if (target == GEN_IPADD) { return false; } int j, i = -1; /* The following is done because of a bug in 0.9.6b */ std::string peerCNStr; X509_NAME* name = X509_get_subject_name((X509*)cert); if (name) { while ((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) { i = j; } } /* we have the name entry and we will now convert this to a string that we can use for comparison. Doing this we support BMPstring, UTF8 etc. */ if (i >= 0) { ASN1_STRING* tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); unsigned char* peer_CN = nullptr; if (tmp) { j = ASN1_STRING_to_UTF8(&peer_CN, tmp); int cnLen = (int)strlen((char*)peer_CN); if (peer_CN && cnLen != j) { result = false; } else { peerCNStr = std::string((const char*)peer_CN, cnLen); OPENSSL_free(peer_CN); } } } if (!result) /* error already detected, pass through */ ; else if (peerCNStr.empty()) { result = false; } else if (!certHostCheck(peerCNStr, host)) { result = false; } } return result; }
/* int openssl_signerinfo_parse(lua_State*L) { PKCS7_SIGNER_INFO * si = CHECK_OBJECT(1,PKCS7_SIGNER_INFO,"openssl.pkcs7_signer_info"); si-> } */ static LUA_FUNCTION(openssl_pkcs7_parse) { PKCS7 * p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7"); STACK_OF(X509) *certs = NULL; STACK_OF(X509_CRL) *crls = NULL; int i = OBJ_obj2nid(p7->type); lua_newtable(L); AUXILIAR_SET(L, -1, "type", OBJ_nid2ln(i), string); switch (i) { case NID_pkcs7_signed: { PKCS7_SIGNED *sign = p7->d.sign; PKCS7* c = sign->contents; PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(sign->signer_info, 0); (void*)si; certs = sign->cert ? sign->cert : NULL; crls = sign->crl ? sign->crl : NULL; #if 0 typedef struct pkcs7_signed_st { ASN1_INTEGER *version; /* version 1 */ STACK_OF(X509_ALGOR) *md_algs; /* md used */ STACK_OF(X509) *cert; /* [ 0 ] */ STACK_OF(X509_CRL) *crl; /* [ 1 ] */ STACK_OF(PKCS7_SIGNER_INFO) *signer_info; struct pkcs7_st *contents; } PKCS7_SIGNED; #endif AUXILIAR_SETOBJECT(L, sk_X509_ALGOR_dup(sign->md_algs), "openssl.stack_of_x509_algor", -1, "md_algs"); AUXILIAR_SETOBJECT(L, sk_PKCS7_SIGNER_INFO_dup(sign->signer_info), "openssl.stack_of_pkcs7_signer_info", -1, "signer_info"); AUXILIAR_SET(L, -1, "detached", PKCS7_is_detached(p7), boolean); if (c) { AUXILIAR_SETOBJECT(L, PKCS7_dup(c), "openssl.pkcs7", -1, "contents"); } if (!PKCS7_is_detached(p7)) { AUXILIAR_SETOBJECT(L, p7->d.sign->contents, "openssl.pkcs7", -1, "content"); } } break; case NID_pkcs7_signedAndEnveloped: certs = p7->d.signed_and_enveloped->cert; crls = p7->d.signed_and_enveloped->crl; break; case NID_pkcs7_enveloped: { /* BIO * mem = BIO_new(BIO_s_mem()); BIO * v_p7bio = PKCS7_dataDecode(p7,pkey,NULL,NULL); BUF_MEM *bptr = NULL; unsigned char src[4096]; int len; while((len = BIO_read(v_p7bio,src,4096))>0){ BIO_write(mem, src, len); } BIO_free(v_p7bio); BIO_get_mem_ptr(mem, &bptr); if((int)*puiDataLen < bptr->length) { *puiDataLen = bptr->length; ret = SAR_MemoryErr; }else{ *puiDataLen = bptr->length; memcpy(pucData,bptr->data, bptr->length); } */ } break; case NID_pkcs7_digest: { PKCS7_DIGEST* d = p7->d.digest; PKCS7* c = d->contents; ASN1_OCTET_STRING *data = d->digest; (void*)c; AUXILIAR_SET(L, -1, "type", "digest", string); if (data) { int dlen = ASN1_STRING_length(data); unsigned char* dptr = ASN1_STRING_data(data); AUXILIAR_SETLSTR(L, -1, "digest", (const char*)dptr, dlen); } } break; case NID_pkcs7_data: { ASN1_OCTET_STRING *data = p7->d.data; int dlen = ASN1_STRING_length(data); unsigned char* dptr = ASN1_STRING_data(data); AUXILIAR_SET(L, -1, "type", "data", string); AUXILIAR_SETLSTR(L, -1, "data", (const char*)dptr, dlen); } break; default: break; }
/** check if a provided cert matches a passed hostname */ bool _mongoc_ssl_check_cert (SSL *ssl, const char *host, bool weak_cert_validation) { X509 *peer; X509_NAME *subject_name; X509_NAME_ENTRY *entry; ASN1_STRING *entry_data; char *check; int length; int idx; int r = 0; long verify_status; size_t addrlen = 0; struct in_addr addr; int i; int n_sans = -1; int target = GEN_DNS; STACK_OF (GENERAL_NAME) * sans = NULL; BSON_ASSERT (ssl); BSON_ASSERT (host); if (weak_cert_validation) { return true; } /** if the host looks like an IP address, match that, otherwise we assume we * have a DNS name */ if (inet_pton (AF_INET, host, &addr)) { target = GEN_IPADD; addrlen = sizeof (struct in_addr); } peer = SSL_get_peer_certificate (ssl); if (!peer) { return false; } verify_status = SSL_get_verify_result (ssl); /** TODO: should we return this somehow? */ if (verify_status == X509_V_OK) { /* get's a stack of alt names that we can iterate through */ sans = (STACK_OF (GENERAL_NAME) *) X509_get_ext_d2i ( (X509 *)peer, NID_subject_alt_name, NULL, NULL); if (sans) { n_sans = sk_GENERAL_NAME_num (sans); /* loop through the stack, or until we find a match */ for (i = 0; i < n_sans && !r; i++) { const GENERAL_NAME *name = sk_GENERAL_NAME_value (sans, i); /* skip entries that can't apply, I.e. IP entries if we've got a * DNS host */ if (name->type == target) { check = (char *)ASN1_STRING_data (name->d.ia5); length = ASN1_STRING_length (name->d.ia5); switch (target) { case GEN_DNS: /* check that we don't have an embedded null byte */ if ((length == bson_strnlen (check, length)) && _mongoc_ssl_hostcheck (check, host)) { r = 1; } break; case GEN_IPADD: if ((length == addrlen) && !memcmp (check, &addr, length)) { r = 1; } break; default: BSON_ASSERT (0); break; } } } GENERAL_NAMES_free (sans); } else { subject_name = X509_get_subject_name (peer); if (subject_name) { idx = -1; i = -1; /* skip to the last common name */ while ((idx = X509_NAME_get_index_by_NID (subject_name, NID_commonName, i)) >= 0) { i = idx; } if (i >= 0) { entry = X509_NAME_get_entry (subject_name, i); entry_data = X509_NAME_ENTRY_get_data (entry); if (entry_data) { /* TODO: I've heard tell that old versions of SSL crap out * when calling ASN1_STRING_to_UTF8 on already utf8 data. * Check up on that */ length = ASN1_STRING_to_UTF8 ((unsigned char **)&check, entry_data); if (length >= 0) { /* check for embedded nulls */ if ((length == bson_strnlen (check, length)) && _mongoc_ssl_hostcheck (check, host)) { r = 1; } OPENSSL_free (check); } } } } } }
static Str ssl_check_cert_ident(X509 * x, char *hostname) { int i; Str ret = NULL; bool match_ident = false; /* * All we need to do here is check that the CN matches. * * From RFC2818 3.1 Server Identity: * If a subjectAltName extension of type dNSName is present, that MUST * be used as the identity. Otherwise, the (most specific) Common Name * field in the Subject field of the certificate MUST be used. Although * the use of the Common Name is existing practice, it is deprecated and * Certification Authorities are encouraged to use the dNSName instead. */ i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); if (i >= 0) { X509_EXTENSION *ex; STACK_OF(GENERAL_NAME) * alt; ex = X509_get_ext(x, i); alt = X509V3_EXT_d2i(ex); if (alt) { int n; GENERAL_NAME *gn; X509V3_EXT_METHOD *method; Str seen_dnsname = NULL; n = sk_GENERAL_NAME_num(alt); for (i = 0; i < n; i++) { gn = sk_GENERAL_NAME_value(alt, i); if (gn->type == GEN_DNS) { char *sn = ASN1_STRING_data(gn->d.ia5); int sl = ASN1_STRING_length(gn->d.ia5); if (!seen_dnsname) seen_dnsname = Strnew(); /* replace \0 to make full string visible to user */ if (sl != strlen(sn)) { int i; for (i = 0; i < sl; ++i) { if (!sn[i]) sn[i] = '!'; } } Strcat_m_charp(seen_dnsname, sn, " ", NULL); if (sl == strlen(sn) /* catch \0 in SAN */ && ssl_match_cert_ident(sn, sl, hostname)) break; } } method = X509V3_EXT_get(ex); sk_GENERAL_NAME_free(alt); if (i < n) /* Found a match */ match_ident = true; else if (seen_dnsname) /* FIXME: gettextize? */ ret = Sprintf("Bad cert ident from %s: dNSName=%s", hostname, seen_dnsname->ptr); } } if (match_ident == false && ret == NULL) { X509_NAME *xn; char buf[2048]; int slen; xn = X509_get_subject_name(x); slen = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)); if ( slen == -1) /* FIXME: gettextize? */ ret = Strnew_charp("Unable to get common name from peer cert"); else if (slen != strlen(buf) || !ssl_match_cert_ident(buf, strlen(buf), hostname)) { /* replace \0 to make full string visible to user */ if (slen != strlen(buf)) { int i; for (i = 0; i < slen; ++i) { if (!buf[i]) buf[i] = '!'; } } /* FIXME: gettextize? */ ret = Sprintf("Bad cert ident %s from %s", buf, hostname); } } return ret; }
static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) { int rv = 0; X509_ALGOR *alg, *kekalg = NULL; ASN1_OCTET_STRING *ukm; const unsigned char *p; unsigned char *dukm = NULL; size_t dukmlen = 0; int keylen, plen; const EVP_CIPHER *kekcipher; EVP_CIPHER_CTX *kekctx; if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) goto err; /* * For DH we only have one OID permissible. If ever any more get defined * we will need something cleverer. */ if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) { DHerr(DH_F_DH_CMS_SET_SHARED_INFO, DH_R_KDF_PARAMETER_ERROR); goto err; } if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0) goto err; if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0) goto err; if (alg->parameter->type != V_ASN1_SEQUENCE) goto err; p = alg->parameter->value.sequence->data; plen = alg->parameter->value.sequence->length; kekalg = d2i_X509_ALGOR(NULL, &p, plen); if (!kekalg) goto err; kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); if (!kekctx) goto err; kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE) goto err; if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) goto err; if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) goto err; keylen = EVP_CIPHER_CTX_key_length(kekctx); if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) goto err; /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */ if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(EVP_CIPHER_type(kekcipher))) <= 0) goto err; if (ukm) { dukmlen = ASN1_STRING_length(ukm); dukm = BUF_memdup(ASN1_STRING_data(ukm), dukmlen); if (!dukm) goto err; } if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) goto err; dukm = NULL; rv = 1; err: X509_ALGOR_free(kekalg); OPENSSL_free(dukm); return rv; }
static int verify_server_cert(SSL *ssl, const char *host) { X509 *cert; X509_NAME *peer_name; ASN1_STRING *str; unsigned char *peer_cn = NULL; int matched = -1, type = GEN_DNS; GENERAL_NAMES *alts; struct in6_addr addr6; struct in_addr addr4; void *addr; int i = -1,j; if (SSL_get_verify_result(ssl) != X509_V_OK) { giterr_set(GITERR_SSL, "The SSL certificate is invalid"); return GIT_ECERTIFICATE; } /* Try to parse the host as an IP address to see if it is */ if (p_inet_pton(AF_INET, host, &addr4)) { type = GEN_IPADD; addr = &addr4; } else { if(p_inet_pton(AF_INET6, host, &addr6)) { type = GEN_IPADD; addr = &addr6; } } cert = SSL_get_peer_certificate(ssl); if (!cert) { giterr_set(GITERR_SSL, "the server did not provide a certificate"); return -1; } /* Check the alternative names */ alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (alts) { int num; num = sk_GENERAL_NAME_num(alts); for (i = 0; i < num && matched != 1; i++) { const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); const char *name = (char *) ASN1_STRING_data(gn->d.ia5); size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); /* Skip any names of a type we're not looking for */ if (gn->type != type) continue; if (type == GEN_DNS) { /* If it contains embedded NULs, don't even try */ if (memchr(name, '\0', namelen)) continue; if (check_host_name(name, host) < 0) matched = 0; else matched = 1; } else if (type == GEN_IPADD) { /* Here name isn't so much a name but a binary representation of the IP */ matched = !!memcmp(name, addr, namelen); } } } GENERAL_NAMES_free(alts); if (matched == 0) goto cert_fail_name; if (matched == 1) return 0; /* If no alternative names are available, check the common name */ peer_name = X509_get_subject_name(cert); if (peer_name == NULL) goto on_error; if (peer_name) { /* Get the index of the last CN entry */ while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0) i = j; } if (i < 0) goto on_error; str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i)); if (str == NULL) goto on_error; /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */ if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) { int size = ASN1_STRING_length(str); if (size > 0) { peer_cn = OPENSSL_malloc(size + 1); GITERR_CHECK_ALLOC(peer_cn); memcpy(peer_cn, ASN1_STRING_data(str), size); peer_cn[size] = '\0'; } } else { int size = ASN1_STRING_to_UTF8(&peer_cn, str); GITERR_CHECK_ALLOC(peer_cn); if (memchr(peer_cn, '\0', size)) goto cert_fail_name; } if (check_host_name((char *)peer_cn, host) < 0) goto cert_fail_name; OPENSSL_free(peer_cn); return 0; on_error: OPENSSL_free(peer_cn); return ssl_set_error(ssl, 0); cert_fail_name: OPENSSL_free(peer_cn); giterr_set(GITERR_SSL, "hostname does not match certificate"); return GIT_ECERTIFICATE; }
X509_ATTRIBUTE* openssl_new_xattribute(lua_State*L, X509_ATTRIBUTE** a, int idx, const char* eprefix) { int arttype; size_t len = 0; int nid; const char* data = NULL; lua_getfield(L, idx, "object"); nid = openssl_get_nid(L, -1); if (nid == NID_undef) { if (eprefix) { luaL_error(L, "%s field object is invalid value", eprefix); } else luaL_argcheck(L, nid != NID_undef, idx, "field object is invalid value"); } lua_pop(L, 1); lua_getfield(L, idx, "type"); arttype = luaL_checkint(L, -1); if (arttype == V_ASN1_UNDEF || arttype == 0) { if (eprefix) { luaL_error(L, "%s field type is not invalid value", eprefix); } else luaL_argcheck(L, nid != NID_undef, idx, "field type is not invalid value"); } lua_pop(L, 1); lua_getfield(L, idx, "value"); if (lua_isstring(L, -1)) { data = lua_tolstring(L, -1, &len); } else if (auxiliar_isgroup(L, "openssl.asn1group", -1)) { ASN1_STRING* value = CHECK_GROUP(-1, ASN1_STRING, "openssl.asn1group"); if (ASN1_STRING_type(value) != arttype) { if (eprefix) luaL_error(L, "%s field value not match type", eprefix); else luaL_argcheck(L, ASN1_STRING_type(value) == arttype, idx, "field value not match type"); } data = (const char *)ASN1_STRING_data(value); len = ASN1_STRING_length(value); } else { if (eprefix) { luaL_error(L, "%s filed value only accept string or asn1_string", eprefix); } else luaL_argerror(L, idx, "filed value only accept string or asn1_string"); } lua_pop(L, 1); if (data) return X509_ATTRIBUTE_create_by_NID(a, nid, arttype, data, len); return 0; }