Example #1
2
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;
}
Example #2
0
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;
}
Example #3
0
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)
					);
			}
		}
	}
}
Example #4
0
/* 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;
}
Example #5
0
static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm,
                                    X509_REVOKED *rev)
{
    int i;

    if (!rev->issuer) {
        if (!nm)
            return 1;
        if (!X509_NAME_cmp(nm, X509_CRL_get_issuer(crl)))
            return 1;
        return 0;
    }

    if (!nm)
        nm = X509_CRL_get_issuer(crl);

    for (i = 0; i < sk_GENERAL_NAME_num(rev->issuer); i++) {
        GENERAL_NAME *gen = sk_GENERAL_NAME_value(rev->issuer, i);
        if (gen->type != GEN_DIRNAME)
            continue;
        if (!X509_NAME_cmp(nm, gen->d.directoryName))
            return 1;
    }
    return 0;

}
Example #6
0
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
}
Example #7
0
static void setup_dp(X509 *x, DIST_POINT *dp)
	{
	X509_NAME *iname = NULL;
	int i;
	if (dp->reasons)
		{
		if (dp->reasons->length > 0)
			dp->dp_reasons = dp->reasons->data[0];
		if (dp->reasons->length > 1)
			dp->dp_reasons |= (dp->reasons->data[1] << 8);
		dp->dp_reasons &= CRLDP_ALL_REASONS;
		}
	else
		dp->dp_reasons = CRLDP_ALL_REASONS;
	if (!dp->distpoint || (dp->distpoint->type != 1))
		return;
	for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++)
		{
		GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
		if (gen->type == GEN_DIRNAME)
			{
			iname = gen->d.directoryName;
			break;
			}
		}
	if (!iname)
		iname = X509_get_issuer_name(x);

	DIST_POINT_set_dpname(dp->distpoint, iname);

	}
Example #8
0
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);
}
Example #9
0
int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr) {
    int loc, i, l, n, r = 0;
    char *v;
    X509_EXTENSION *ex;
    STACK_OF(GENERAL_NAME) *alt;
    GENERAL_NAME *gn;

    debug(DBG_DBG, "subjectaltnameaddr");

    loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
    if (loc < 0)
	return r;

    ex = X509_get_ext(cert, loc);
    alt = X509V3_EXT_d2i(ex);
    if (!alt)
	return r;

    n = sk_GENERAL_NAME_num(alt);
    for (i = 0; i < n; i++) {
	gn = sk_GENERAL_NAME_value(alt, i);
	if (gn->type != GEN_IPADD)
	    continue;
	r = -1;
	v = (char *)ASN1_STRING_data(gn->d.ia5);
	l = ASN1_STRING_length(gn->d.ia5);
	if (((family == AF_INET && l == sizeof(struct in_addr)) || (family == AF_INET6 && l == sizeof(struct in6_addr)))
	    && !memcmp(v, &addr, l)) {
	    r = 1;
	    break;
	}
    }
    GENERAL_NAMES_free(alt);
    return r;
}
/**
* 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;
}
Example #11
0
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);
}
Example #12
0
File: tcp.c Project: yfqian/libsvc
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;
}
Example #13
0
/* 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;
}
void OpenSSLCertificate::parse() {
	if (!cert) {
		return;
	}

	// Subject name
	X509_NAME* subjectName = X509_get_subject_name(cert.get());
	if (subjectName) {
		// Subject name
		ByteArray subjectNameData;
		subjectNameData.resize(256);
		X509_NAME_oneline(X509_get_subject_name(cert.get()), reinterpret_cast<char*>(subjectNameData.getData()), subjectNameData.getSize());
		this->subjectName = std::string(reinterpret_cast<const char*>(subjectNameData.getData()));

		// Common name
		int cnLoc = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1);
		while (cnLoc != -1) {
			X509_NAME_ENTRY* cnEntry = X509_NAME_get_entry(subjectName, cnLoc);
			ASN1_STRING* cnData = X509_NAME_ENTRY_get_data(cnEntry);
			commonNames.push_back(ByteArray(cnData->data, cnData->length).toString());
			cnLoc = X509_NAME_get_index_by_NID(subjectName, NID_commonName, cnLoc);
		}
	}

	// subjectAltNames
	int subjectAltNameLoc = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1);
	if(subjectAltNameLoc != -1) {
		X509_EXTENSION* extension = X509_get_ext(cert.get(), subjectAltNameLoc);
		boost::shared_ptr<GENERAL_NAMES> generalNames(reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(extension)), GENERAL_NAMES_free);
		boost::shared_ptr<ASN1_OBJECT> xmppAddrObject(OBJ_txt2obj(ID_ON_XMPPADDR_OID, 1), ASN1_OBJECT_free);
		boost::shared_ptr<ASN1_OBJECT> dnsSRVObject(OBJ_txt2obj(ID_ON_DNSSRV_OID, 1), ASN1_OBJECT_free);
		for (int i = 0; i < sk_GENERAL_NAME_num(generalNames.get()); ++i) {
			GENERAL_NAME* generalName = sk_GENERAL_NAME_value(generalNames.get(), i);
			if (generalName->type == GEN_OTHERNAME) {
				OTHERNAME* otherName = generalName->d.otherName;
				if (OBJ_cmp(otherName->type_id, xmppAddrObject.get()) == 0) {
					// XmppAddr
					if (otherName->value->type != V_ASN1_UTF8STRING) {
						continue;
					}
					ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string;
					addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString());
				}
				else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) {
					// SRVName
					if (otherName->value->type != V_ASN1_IA5STRING) {
						continue;
					}
					ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string;
					addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString());
				}
			}
			else if (generalName->type == GEN_DNS) {
				// DNSName
				addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString());
			}
		}
	}
}
Example #15
0
/*
 * 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;
}
Example #16
0
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);
}
Example #17
0
/* 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 void add_alt_names(struct http_ctx *ctx, struct http_cert *cert,
			  GENERAL_NAMES *names)
{
	int num, i;

	num = sk_GENERAL_NAME_num(names);
	for (i = 0; i < num; i++) {
		const GENERAL_NAME *name;
		name = sk_GENERAL_NAME_value(names, i);
		add_alt_name(ctx, cert, name);
	}
}
Example #19
0
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;
}
Example #20
0
int subjectaltnameregexp(X509 *cert, int type, const char *exact,  const regex_t *regex) {
    int loc, i, l, n, r = 0;
    char *s, *v;
    X509_EXTENSION *ex;
    STACK_OF(GENERAL_NAME) *alt;
    GENERAL_NAME *gn;

    debug(DBG_DBG, "subjectaltnameregexp");

    loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
    if (loc < 0)
	return r;

    ex = X509_get_ext(cert, loc);
    alt = X509V3_EXT_d2i(ex);
    if (!alt)
	return r;

    n = sk_GENERAL_NAME_num(alt);
    for (i = 0; i < n; i++) {
	gn = sk_GENERAL_NAME_value(alt, i);
	if (gn->type != type)
	    continue;
	r = -1;
	v = (char *)ASN1_STRING_data(gn->d.ia5);
	l = ASN1_STRING_length(gn->d.ia5);
	if (l <= 0)
	    continue;
#ifdef DEBUG
	printfchars(NULL, gn->type == GEN_DNS ? "dns" : "uri", NULL, v, l);
#endif
	if (exact) {
	    if (memcmp(v, exact, l))
		continue;
	} else {
	    s = stringcopy((char *)v, l);
	    if (!s) {
		debug(DBG_ERR, "malloc failed");
		continue;
	    }
	    if (regexec(regex, s, 0, NULL, 0)) {
		free(s);
		continue;
	    }
	    free(s);
	}
	r = 1;
	break;
    }
    GENERAL_NAMES_free(alt);
    return r;
}
Example #21
0
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;
}
Example #22
0
/* 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);
}
Example #23
0
int X509_check_issued(X509 *issuer, X509 *subject)
{
  if(X509_NAME_cmp(X509_get_subject_name(issuer),
      X509_get_issuer_name(subject)))
        return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
  x509v3_cache_extensions(issuer);
  x509v3_cache_extensions(subject);
  if(subject->akid) {
    /* Check key ids (if present) */
    if(subject->akid->keyid && issuer->skid &&
     ASN1_OCTET_STRING_cmp(subject->akid->keyid, issuer->skid) )
        return X509_V_ERR_AKID_SKID_MISMATCH;
    /* Check serial number */
    if(subject->akid->serial &&
      ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
            subject->akid->serial))
        return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
    /* Check issuer name */
    if(subject->akid->issuer) {
      /* Ugh, for some peculiar reason AKID includes
       * SEQUENCE OF GeneralName. So look for a DirName.
       * There may be more than one but we only take any
       * notice of the first.
       */
      GENERAL_NAMES *gens;
      GENERAL_NAME *gen;
      X509_NAME *nm = NULL;
      int i;
      gens = subject->akid->issuer;
      for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
        gen = sk_GENERAL_NAME_value(gens, i);
        if(gen->type == GEN_DIRNAME) {
          nm = gen->d.dirn;
          break;
        }
      }
      if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
        return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
    }
  }
  if(subject->ex_flags & EXFLAG_PROXY)
    {
    if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
      return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
    }
  else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
    return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
  return X509_V_OK;
}
Example #24
0
/* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */
BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids)
{
    STACK_OF(GENERAL_NAME) *names;
    BIO *bio;
    X509_NAME *subj;
    char **cpp;
    int i, n;

    if (!x509 || !(*ids = apr_array_make(p, 0, sizeof(char *)))) {
        *ids = NULL;
        return FALSE;
    }

    /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */
    if ((names = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL)) &&
        (bio = BIO_new(BIO_s_mem()))) {
        GENERAL_NAME *name;

        for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
            name = sk_GENERAL_NAME_value(names, i);
            if (name->type == GEN_DNS) {
                ASN1_STRING_print_ex(bio, name->d.ia5, ASN1_STRFLGS_ESC_CTRL|
                                     ASN1_STRFLGS_UTF8_CONVERT);
                n = BIO_pending(bio);
                if (n > 0) {
                    cpp = (char **)apr_array_push(*ids);
                    *cpp = apr_palloc(p, n+1);
                    n = BIO_read(bio, *cpp, n);
                    (*cpp)[n] = NUL;
                }
            }
        }
        BIO_free(bio);
    }

    if (names)
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);

    /* Second, the CN-IDs (commonName attributes in the subject DN) */
    subj = X509_get_subject_name(x509);
    i = -1;
    while ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) != -1) {
        cpp = (char **)apr_array_push(*ids);
        *cpp = SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i));
    }

    return apr_is_empty_array(*ids) ? FALSE : TRUE;
}
static int tls_match_altsubject(X509 *cert, const char *match)
{
	GENERAL_NAME *gen;
	char *field, *tmp;
	void *ext;
	int i, found = 0;
	size_t len;

	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);

	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
		gen = sk_GENERAL_NAME_value(ext, i);
		switch (gen->type) {
		case GEN_EMAIL:
			field = "EMAIL";
			break;
		case GEN_DNS:
			field = "DNS";
			break;
		case GEN_URI:
			field = "URI";
			break;
		default:
			field = NULL;
			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
				   "unsupported type=%d", gen->type);
			break;
		}

		if (!field)
			continue;

		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
			   field, gen->d.ia5->data);
		len = os_strlen(field) + 1 +
			strlen((char *) gen->d.ia5->data) + 1;
		tmp = os_malloc(len);
		if (tmp == NULL)
			continue;
		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
		if (strstr(tmp, match))
			found++;
		os_free(tmp);
	}

	return found;
}
Example #26
0
/* See RFC 5280 section 4.2.1.6 for SubjectAltName details. */
static int
tls_cert_get_altnames(struct tls *ctx, struct tls_cert *cert, X509 *x509_cert)
{
	STACK_OF(GENERAL_NAME) *altname_stack = NULL;
	GENERAL_NAME *altname;
	int count, i;
	int rv = -1;

	altname_stack = X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL);
	if (altname_stack == NULL)
		return 0;

	count = sk_GENERAL_NAME_num(altname_stack);
	if (count == 0) {
		rv = 0;
		goto out;
	}

	cert->subject_alt_names = calloc(sizeof (struct tls_cert_general_name), count);
	if (cert->subject_alt_names == NULL) {
		tls_set_error(ctx, "calloc");
		goto out;
	}

	for (i = 0; i < count; i++) {
		altname = sk_GENERAL_NAME_value(altname_stack, i);

		if (altname->type == GEN_DNS) {
			rv = tls_load_alt_ia5string(ctx, altname->d.dNSName, cert, TLS_CERT_GNAME_DNS, 1, UB_GNAME_DNS, "dns");
		} else if (altname->type == GEN_EMAIL) {
			rv = tls_load_alt_ia5string(ctx, altname->d.rfc822Name, cert, TLS_CERT_GNAME_EMAIL, 1, UB_GNAME_EMAIL, "email");
		} else if (altname->type == GEN_URI) {
			rv = tls_load_alt_ia5string(ctx, altname->d.uniformResourceIdentifier, cert, TLS_CERT_GNAME_URI, 1, UB_GNAME_URI, "uri");
		} else if (altname->type == GEN_IPADD) {
			rv = tls_load_alt_ipaddr(ctx, altname->d.iPAddress, cert);
		} else {
			/* ignore unknown types */
			rv = 0;
		}
		if (rv < 0)
			goto out;
	}
	rv = 0;
out:
	sk_GENERAL_NAME_pop_free(altname_stack, GENERAL_NAME_free);
	return rv;
}
Example #27
0
int get_subjectaltname(X509* cert, char* buf, int buf_len){

/*
    Copy "," separated dNSName values
    of the subjectAltName extension, to pBuf
*/

  GENERAL_NAMES *gens;
  GENERAL_NAME  *gen;
  int i;
  char *sub_str= buf;
  int space_taken=0;
  int space_left= buf_len;

  gens = X509_get_ext_d2i(cert , NID_subject_alt_name, NULL, NULL);

  for(i = 0; i < sk_GENERAL_NAME_num(gens); i++){
      gen = sk_GENERAL_NAME_value(gens, i);
      syslog(LOG_INFO,"1sub_str");

      if((gen->type == GEN_DNS)||(gen->type == GEN_URI)){
          if(0 < space_left)
	  space_taken= copy_csv_to_buffer(sub_str, (char*)gen->d.ia5->data, buf_len, space_left);
	  space_left= space_left -space_taken;
      }

      if(gen->type == GEN_IPADD) {
          if(0 < space_left) {
              const int oline_len = 40;
	      char oline[oline_len];
	      oline[0]='\0';
	      ip_to_string(oline, oline_len, gen);
	      space_taken= copy_csv_to_buffer(sub_str,  oline, buf_len, space_left);
	      space_left= space_left - space_taken;
	  }
      }

      syslog(LOG_INFO,"2 sub_str: %s space_taken:%d space_left:%d",sub_str, space_taken, space_left);
  }

  sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
  return CERT_OK;

}
Example #28
0
int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
	{

	if(!akid)
		return X509_V_OK;

	/* Check key ids (if present) */
	if(akid->keyid && issuer->skid &&
		 ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) )
				return X509_V_ERR_AKID_SKID_MISMATCH;
	/* Check serial number */
	if(akid->serial &&
		ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
				return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
	/* Check issuer name */
	if(akid->issuer)
		{
		/* Ugh, for some peculiar reason AKID includes
		 * SEQUENCE OF GeneralName. So look for a DirName.
		 * There may be more than one but we only take any
		 * notice of the first.
		 */
		GENERAL_NAMES *gens;
		GENERAL_NAME *gen;
		X509_NAME *nm = NULL;
		int i;
		gens = akid->issuer;
		for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
			{
			gen = sk_GENERAL_NAME_value(gens, i);
			if(gen->type == GEN_DIRNAME)
				{
				nm = gen->d.dirn;
				break;
				}
			}
		if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
			return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
		}
	return X509_V_OK;
	}
/**
 * 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
			char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName);

			// Make sure there isn't an embedded NUL character in the DNS name
			if (ASN1_STRING_length(current_name->d.dNSName)
					!= strlen(dns_name)) {
				result = MalformedCertificate;
				break;
			} else { // Compare expected hostname with the DNS name
				if (hostmatch(hostname, dns_name) == CURL_HOST_MATCH) {
					result = MatchFound;
					break;
				}
			}
		}
	}
	sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);

	return result;
}
Example #30
0
static int openssl_xext_totable(lua_State* L, X509_EXTENSION *x)
{
  lua_newtable(L);
  openssl_push_asn1object(L, x->object);
  lua_setfield(L, -2, "object");

  PUSH_ASN1_OCTET_STRING(L, x->value);
  lua_setfield(L, -2, "value");

  AUXILIAR_SET(L, -1, "critical", x->critical, boolean);

  switch (x->object->nid)
  {
  case NID_subject_alt_name:
  {
    int i;
    int n_general_names;

    STACK_OF(GENERAL_NAME) *values = X509V3_EXT_d2i(x);

    if (values == NULL)
      break;

    /* Push ret[oid] */
    openssl_push_asn1object(L, x->object);
    lua_newtable(L);
    n_general_names = sk_GENERAL_NAME_num(values);
    for (i = 0; i < n_general_names; i++)
    {
      GENERAL_NAME *general_name = sk_GENERAL_NAME_value(values, i);
      openssl_push_general_name(L, general_name);
      lua_rawseti(L, -2, i + 1);
    }
    lua_settable(L, -3);
  }
  default:
    break;
  }
  return 1;
};