示例#1
1
文件: ssl.c 项目: adrianimboden/burp
// This function taken from openvpn-2.2.1 and tidied up a bit.
static int setenv_x509(X509_NAME *x509, const char *type)
{
	int i, n;
	int fn_nid;
	ASN1_OBJECT *fn;
	ASN1_STRING *val;
	X509_NAME_ENTRY *ent;
	const char *objbuf;
	uint8_t *buf;
	char *name_expand;
	size_t name_expand_size;

	n=X509_NAME_entry_count (x509);
	for(i=0; i<n; ++i)
	{
		if(!(ent=X509_NAME_get_entry (x509, i))
		  || !(fn=X509_NAME_ENTRY_get_object(ent))
		  || !(val=X509_NAME_ENTRY_get_data(ent))
		  || (fn_nid=OBJ_obj2nid(fn))==NID_undef
		  || !(objbuf=OBJ_nid2sn(fn_nid)))
			continue;
		buf=(uint8_t *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
		if(ASN1_STRING_to_UTF8(&buf, val)<=0) continue;
		name_expand_size=64+strlen(objbuf);
		if(!(name_expand=(char *)malloc_w(name_expand_size, __func__)))
			return -1;
		snprintf(name_expand, name_expand_size,
			"X509_%s_%s", type, objbuf);
		sanitise(name_expand);
		sanitise((char*)buf);
		setenv(name_expand, (char*)buf, 1);
		free (name_expand);
		OPENSSL_free (buf);
	}
	return 0;
}
示例#2
0
/* tls_text_name - extract certificate property value by name */
static char *tls_text_name(X509_NAME *name, int nid)
{
	int     pos;
	X509_NAME_ENTRY *entry;
	ASN1_STRING *entry_str;
	int     utf8_length;
	unsigned char *utf8_value;
	char *result;

	if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
		return NULL;
	}

	entry = X509_NAME_get_entry(name, pos);
	g_return_val_if_fail(entry != NULL, NULL);
	entry_str = X509_NAME_ENTRY_get_data(entry);
	g_return_val_if_fail(entry_str != NULL, NULL);

	/* Convert everything into UTF-8. It's up to OpenSSL to do something
	   reasonable when converting ASCII formats that contain non-ASCII
	   content. */
	if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
		g_warning("Error decoding ASN.1 type=%d", ASN1_STRING_type(entry_str));
		return NULL;
	}

	if (has_internal_nul((char *)utf8_value, utf8_length)) {
		g_warning("NUL character in hostname in certificate");
		OPENSSL_free(utf8_value);
		return NULL;
	}

	result = g_strdup((char *) utf8_value);
	OPENSSL_free(utf8_value);
	return result;
}
示例#3
0
int tlsops_comp(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[1024];
	X509* cert;
	struct tcp_connection* c;
	X509_NAME* name;
	X509_NAME_ENTRY* e;
	ASN1_STRING* asn1;
	int nid = NID_commonName, index, my = 0, issuer = 0, ind_local;
	char* elem;
	str text;

	text.s = 0;
	/* copy callback value as we modify it */
	ind_local = param->pvn.u.isname.name.n;

	DBG("DEBUG:tlsops:tlsops_comp: ind_local = %x", ind_local);
	if (ind_local & CERT_PEER) {
		my = 0;
		ind_local = ind_local ^ CERT_PEER;
	} else if (ind_local & CERT_LOCAL) {
		my = 1;
		ind_local = ind_local ^ CERT_LOCAL;
	} else {
		LM_CRIT("could not determine certificate\n");
		return pv_get_null(msg, param, res);
	}

	if (ind_local & CERT_SUBJECT) {
		issuer = 0;
		ind_local = ind_local ^ CERT_SUBJECT;
	} else if (ind_local & CERT_ISSUER) {
		issuer = 1;
		ind_local = ind_local ^ CERT_ISSUER;
	} else {
		LM_CRIT("could not determine subject or issuer\n");
		return pv_get_null(msg, param, res);
	}

	switch(ind_local) {
		case COMP_CN: nid = NID_commonName;             break;
		case COMP_O:  nid = NID_organizationName;       break;
		case COMP_OU: nid = NID_organizationalUnitName; break;
		case COMP_C:  nid = NID_countryName;            break;
		case COMP_ST: nid = NID_stateOrProvinceName;    break;
		case COMP_L:  nid = NID_localityName;           break;
		default:      nid = NID_undef;
	}

	if (get_cert(&cert, &c, msg, my) < 0) return -1;

	name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert);
	if (!name) {
		LM_ERR("cannot extract subject or issuer name from peer"
				" certificate\n");
		goto err;
	}

	if (nid == NID_undef) { /* dump the whole cert info into buf */
		X509_NAME_oneline(name, buf, sizeof(buf));
		res->rs.s = buf;
		res->rs.len = strlen(buf);
		res->flags = PV_VAL_STR;
	} else {
		index = X509_NAME_get_index_by_NID(name, nid, -1);
		if (index == -1) {
			switch(ind_local) {
			case COMP_CN: elem = "CommonName";              break;
			case COMP_O:  elem = "OrganizationName";        break;
			case COMP_OU: elem = "OrganizationalUnitUname"; break;
			case COMP_C:  elem = "CountryName";             break;
			case COMP_ST: elem = "StateOrProvinceName";     break;
			case COMP_L:  elem = "LocalityName";            break;
			default:      elem = "Unknown";                 break;
			}
			DBG("DEBUG:tlsops:tlsops_comp: element %s not found in "
				"certificate subject/issuer\n", elem);
			goto err;
		}
	
		e = X509_NAME_get_entry(name, index);
		asn1 = X509_NAME_ENTRY_get_data(e);
		text.len = ASN1_STRING_to_UTF8((unsigned char**)(void*)&text.s, asn1);
		if (text.len < 0 || text.len >= 1024) {
			LM_ERR("failed to convert ASN1 string\n");
			goto err;
		}
		memcpy(buf, text.s, text.len);
		res->rs.s = buf;
		res->rs.len = text.len;
		res->flags = PV_VAL_STR;
	
		OPENSSL_free(text.s);
	}
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return 0;

 err:
	if (text.s) OPENSSL_free(text.s);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return pv_get_null(msg, param, res);
}
示例#4
0
/*! \brief
* creates a FILE * from the fd passed by the accept thread.
* This operation is potentially expensive (certificate verification),
* so we do it in the child thread context.
*
* \note must decrement ref count before returning NULL on error
*/
static void *handle_tcptls_connection(void *data)
{
	struct ast_tcptls_session_instance *tcptls_session = data;
#ifdef DO_SSL
	int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept;
	int ret;
	char err[256];
#endif

	/* TCP/TLS connections are associated with external protocols, and
	 * should not be allowed to execute 'dangerous' functions. This may
	 * need to be pushed down into the individual protocol handlers, but
	 * this seems like a good general policy.
	 */
	if (ast_thread_inhibit_escalations()) {
		ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection\n");
		ast_tcptls_close_session_file(tcptls_session);
		ao2_ref(tcptls_session, -1);
		return NULL;
	}

	tcptls_session->stream_cookie = tcptls_stream_alloc();
	if (!tcptls_session->stream_cookie) {
		ast_tcptls_close_session_file(tcptls_session);
		ao2_ref(tcptls_session, -1);
		return NULL;
	}

	/*
	* open a FILE * as appropriate.
	*/
	if (!tcptls_session->parent->tls_cfg) {
		tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL,
			tcptls_session->fd, -1);
		if (tcptls_session->f) {
			if (setvbuf(tcptls_session->f, NULL, _IONBF, 0)) {
				ast_tcptls_close_session_file(tcptls_session);
			}
		}
	}
#ifdef DO_SSL
	else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) {
		SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
		if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) {
			ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
		} else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie,
			tcptls_session->ssl, tcptls_session->fd, -1))) {
			if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
				|| (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
				X509 *peer;
				long res;
				peer = SSL_get_peer_certificate(tcptls_session->ssl);
				if (!peer) {
					ast_log(LOG_ERROR, "No peer SSL certificate to verify\n");
					ast_tcptls_close_session_file(tcptls_session);
					ao2_ref(tcptls_session, -1);
					return NULL;
				}

				res = SSL_get_verify_result(tcptls_session->ssl);
				if (res != X509_V_OK) {
					ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res));
					X509_free(peer);
					ast_tcptls_close_session_file(tcptls_session);
					ao2_ref(tcptls_session, -1);
					return NULL;
				}
				if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
					ASN1_STRING *str;
					unsigned char *str2;
					X509_NAME *name = X509_get_subject_name(peer);
					int pos = -1;
					int found = 0;

					for (;;) {
						/* Walk the certificate to check all available "Common Name" */
						/* XXX Probably should do a gethostbyname on the hostname and compare that as well */
						pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
						if (pos < 0) {
							break;
						}
						str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
						ret = ASN1_STRING_to_UTF8(&str2, str);
						if (ret < 0) {
							continue;
						}

						if (str2) {
							if (strlen((char *) str2) != ret) {
								ast_log(LOG_WARNING, "Invalid certificate common name length (contains NULL bytes?)\n");
							} else if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) {
								found = 1;
							}
							ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2);
							OPENSSL_free(str2);
						}
						if (found) {
							break;
						}
					}
					if (!found) {
						ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname);
						X509_free(peer);
						ast_tcptls_close_session_file(tcptls_session);
						ao2_ref(tcptls_session, -1);
						return NULL;
					}
				}
				X509_free(peer);
			}
		}
		if (!tcptls_session->f) {	/* no success opening descriptor stacking */
			SSL_free(tcptls_session->ssl);
		}
	}
#endif /* DO_SSL */

	if (!tcptls_session->f) {
		ast_tcptls_close_session_file(tcptls_session);
		ast_log(LOG_WARNING, "FILE * open failed!\n");
#ifndef DO_SSL
		if (tcptls_session->parent->tls_cfg) {
			ast_log(LOG_ERROR, "Attempted a TLS connection without OpenSSL support. This will not work!\n");
		}
#endif
		ao2_ref(tcptls_session, -1);
		return NULL;
	}

	if (tcptls_session->parent->worker_fn) {
		return tcptls_session->parent->worker_fn(tcptls_session);
	} else {
		return tcptls_session;
	}
}
示例#5
0
/*
 * This function is based on verifyhost in libcurl - I hope that it is correct.
 */
static int verify_ssl_host_name(X509 *server_cert, unsigned char *host)
{
	unsigned char ipv4_address[4];
#ifdef SUPPORT_IPV6
	unsigned char ipv6_address[16];
#endif
	unsigned char *address = NULL;
	int address_len = 0;
	int type = GEN_DNS;

	STACK_OF(GENERAL_NAME) *altnames;

	if (!numeric_ip_address(host, ipv4_address)) {
		address = ipv4_address;
		address_len = 4;
		type = GEN_IPADD;
	}
#ifdef SUPPORT_IPV6
	if (!numeric_ipv6_address(host, ipv6_address, NULL)) {
		address = ipv6_address;
		address_len = 16;
		type = GEN_IPADD;
	}
#endif

#if 1
	altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
	if (altnames) {
		int retval = 1;
		int i;
		int n_altnames = sk_GENERAL_NAME_num(altnames);
		for (i = 0; i < n_altnames; i++) {
			const GENERAL_NAME *altname = sk_GENERAL_NAME_value(altnames, i);
			const unsigned char *altname_ptr;
			int altname_len;
			if (altname->type != type) {
				if (altname->type == GEN_IPADD || altname->type == GEN_DNS || altname->type == GEN_URI)
					retval = S_INVALID_CERTIFICATE;
				continue;
			}
			altname_ptr = ASN1_STRING_data(altname->d.ia5);
			altname_len = ASN1_STRING_length(altname->d.ia5);
			if (type == GEN_IPADD) {
				if (altname_len == address_len && !memcmp(altname_ptr, address, address_len)) {
					retval = 0;
					break;
				}
			} else {
				if (altname_len == (int)strlen(cast_const_char altname_ptr) && !check_host_name(altname_ptr, host)) {
					retval = 0;
					break;
				}
			}
			retval = S_INVALID_CERTIFICATE;
		}
		sk_GENERAL_NAME_free(altnames);
		if (retval != 1)
			return retval;
	}
#endif

	{
		unsigned char *nulstr = cast_uchar "";
		unsigned char *peer_CN = nulstr;
		X509_NAME *name;
		int j, i = -1;
	
		retval = 1;

		name = X509_get_subject_name(server_cert);
		if (name)
			while ((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)
				i = j;
		if (i >= 0) {
			ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
			if (tmp) {
				if (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 {
					j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
				}
				if (peer_CN && (int)strlen(cast_const_char peer_CN) != j) {
					retval = S_INVALID_CERTIFICATE;
				}
			}
		}
		if (peer_CN && peer_CN != nulstr) {
			if (retval == 1 && !check_host_name(peer_CN, host))
				retval = 0;
			OPENSSL_free(peer_CN);
		}
		if (retval != 1)
			return retval;
	}

	return S_INVALID_CERTIFICATE;
}
示例#6
0
文件: SslUtils.C 项目: 913862627/wt
    std::vector<Wt::WSslCertificate::DnAttribute>
    getDnAttributes(struct X509_name_st *sn)
    {
      std::vector<Wt::WSslCertificate::DnAttribute> retval;
      
      if (!sn)
	return retval;

      int entries = X509_NAME_entry_count(sn);
      for (int i = 0; i < entries; ++i) {
	X509_NAME_ENTRY *entry = X509_NAME_get_entry(sn, i);
	ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(entry);
	ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);
	int nid = OBJ_obj2nid(obj);
      
	std::string value;
	{
	  char *s;
	  ASN1_STRING_to_UTF8((unsigned char **)(&s), data);
	  value = s;
	  OPENSSL_free(s);
	}

	Wt::WSslCertificate::DnAttributeName name;
        bool knownAttribute = true;
	switch (nid) {
	case NID_commonName:
	  name = Wt::WSslCertificate::CommonName; break;
	case NID_countryName:
	  name = Wt::WSslCertificate::CountryName; break;
	case NID_localityName:
	  name = Wt::WSslCertificate::LocalityName; break;
	case NID_stateOrProvinceName:
	  name = Wt::WSslCertificate::StateOrProvinceName; break;
	case NID_organizationName:
	  name = Wt::WSslCertificate::OrganizationName; break;
	case NID_organizationalUnitName:
	  name = Wt::WSslCertificate::OrganizationalUnitName; break;
	case NID_givenName:
	  name = Wt::WSslCertificate::GivenName; break;
	case NID_surname:
	  name = Wt::WSslCertificate::Surname; break;
	case NID_initials:
	  name = Wt::WSslCertificate::Initials; break;
	case NID_serialNumber:
	  name = Wt::WSslCertificate::SerialNumber; break;
	case NID_title:
	  name = Wt::WSslCertificate::Title; break;
	default:
	  // extra unknown attributes; ignore them
          knownAttribute = false;
          break;
	}

        if (knownAttribute) {
	  Wt::WSslCertificate::DnAttribute dna(name, value);
	  retval.push_back(dna);
        }
      }

      return retval;
    }
示例#7
0
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;
}
示例#8
0
/* cf. RFC2818 and RFC2459 */
static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
{
	STACK_OF(GENERAL_NAME) *altnames;
	X509_NAME *subjname;
	ASN1_STRING *subjasn1;
	char *subjstr = NULL;
	int addrlen = 0;
	int i, altdns = 0;
	char addrbuf[sizeof(struct in6_addr)];
	int ret;

	/* Allow GEN_IP in the certificate only if we actually connected
	   by IP address rather than by name. */
	if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
		addrlen = 4;
	else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
		addrlen = 16;
	else if (vpninfo->hostname[0] == '[' &&
		 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
		char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
		*p = 0;
		if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
			addrlen = 16;
		*p = ']';
	}

	altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
				    NULL, NULL);
	for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
		const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);

		if (this->type == GEN_DNS) {
			char *str;

			int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
			if (len < 0)
				continue;

			altdns = 1;

			/* We don't like names with embedded NUL */
			if (strlen(str) != len)
				continue;

			if (!match_hostname(vpninfo->hostname, str)) {
				vpn_progress(vpninfo, PRG_TRACE,
					     _("Matched DNS altname '%s'\n"),
					     str);
				GENERAL_NAMES_free(altnames);
				OPENSSL_free(str);
				return 0;
			} else {
				vpn_progress(vpninfo, PRG_TRACE,
					     _("No match for altname '%s'\n"),
					     str);
			}
			OPENSSL_free(str);
		} else if (this->type == GEN_IPADD && addrlen) {
			char host[80];
			int family;

			if (this->d.ip->length == 4) {
				family = AF_INET;
			} else if (this->d.ip->length == 16) {
				family = AF_INET6;
			} else {
				vpn_progress(vpninfo, PRG_ERR,
					     _("Certificate has GEN_IPADD altname with bogus length %d\n"),
					     this->d.ip->length);
				continue;
			}

			/* We only do this for the debug messages */
			inet_ntop(family, this->d.ip->data, host, sizeof(host));

			if (this->d.ip->length == addrlen &&
			    !memcmp(addrbuf, this->d.ip->data, addrlen)) {
				vpn_progress(vpninfo, PRG_TRACE,
					     _("Matched %s address '%s'\n"),
					     (family == AF_INET6) ? "IPv6" : "IPv4",
					     host);
				GENERAL_NAMES_free(altnames);
				return 0;
			} else {
				vpn_progress(vpninfo, PRG_TRACE,
					     _("No match for %s address '%s'\n"),
					     (family == AF_INET6) ? "IPv6" : "IPv4",
					     host);
			}
		} else if (this->type == GEN_URI) {
			char *str;
			char *url_proto, *url_host, *url_path, *url_host2;
			int url_port;
			int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);

			if (len < 0)
				continue;

			/* We don't like names with embedded NUL */
			if (strlen(str) != len)
				continue;

			if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
				OPENSSL_free(str);
				continue;
			}

			if (!url_proto || strcasecmp(url_proto, "https"))
				goto no_uri_match;

			if (url_port != vpninfo->port)
				goto no_uri_match;

			/* Leave url_host as it was so that it can be freed */
			url_host2 = url_host;
			if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
			    url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
				/* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
				url_host[strlen(url_host)-1] = 0;
				url_host2++;
			}

			if (strcasecmp(vpninfo->hostname, url_host2))
				goto no_uri_match;

			if (url_path) {
				vpn_progress(vpninfo, PRG_TRACE,
					     _("URI '%s' has non-empty path; ignoring\n"),
					     str);
				goto no_uri_match_silent;
			}
			vpn_progress(vpninfo, PRG_TRACE,
				     _("Matched URI '%s'\n"),
				     str);
			free(url_proto);
			free(url_host);
			free(url_path);
			OPENSSL_free(str);
			GENERAL_NAMES_free(altnames);
			return 0;

		no_uri_match:
			vpn_progress(vpninfo, PRG_TRACE,
				     _("No match for URI '%s'\n"),
				     str);
		no_uri_match_silent:
			free(url_proto);
			free(url_host);
			free(url_path);
			OPENSSL_free(str);
		}
	}
	GENERAL_NAMES_free(altnames);

	/* According to RFC2818, we don't use the legacy subject name if
	   there was an altname with DNS type. */
	if (altdns) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("No altname in peer cert matched '%s'\n"),
			     vpninfo->hostname);
		return -EINVAL;
	}

	subjname = X509_get_subject_name(peer_cert);
	if (!subjname) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("No subject name in peer cert!\n"));
		return -EINVAL;
	}

	/* Find the _last_ (most specific) commonName */
	i = -1;
	while (1) {
		int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
		if (j >= 0)
			i = j;
		else
			break;
	}

	subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));

	i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);

	if (!subjstr || strlen(subjstr) != i) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Failed to parse subject name in peer cert\n"));
		return -EINVAL;
	}
	ret = 0;

	if (match_hostname(vpninfo->hostname, subjstr)) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Peer cert subject mismatch ('%s' != '%s')\n"),
			     subjstr, vpninfo->hostname);
		ret = -EINVAL;
	} else {
		vpn_progress(vpninfo, PRG_TRACE,
			     _("Matched peer certificate subject name '%s'\n"),
			     subjstr);
	}

	OPENSSL_free(subjstr);
	return ret;
}
示例#9
0
static char *tls_text_name(X509_NAME *name, int nid, const char *label,
			        const TLS_SESS_STATE *TLScontext, int gripe)
{
    const char *myname = "tls_text_name";
    int     pos;
    X509_NAME_ENTRY *entry;
    ASN1_STRING *entry_str;
    int     asn1_type;
    int     utf8_length;
    unsigned char *utf8_value;
    int     ch;
    unsigned char *cp;

    if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
	if (gripe != DONT_GRIPE) {
	    msg_warn("%s: %s: peer certificate has no %s",
		     myname, TLScontext->namaddr, label);
	    tls_print_errors();
	}
	return (0);
    }
#if 0

    /*
     * If the match is required unambiguous, insist that that no other values
     * be present.
     */
    if (X509_NAME_get_index_by_NID(name, nid, pos) >= 0) {
	msg_warn("%s: %s: multiple %ss in peer certificate",
		 myname, TLScontext->namaddr, label);
	return (0);
    }
#endif

    if ((entry = X509_NAME_get_entry(name, pos)) == 0) {
	/* This should not happen */
	msg_warn("%s: %s: error reading peer certificate %s entry",
		 myname, TLScontext->namaddr, label);
	tls_print_errors();
	return (0);
    }
    if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) {
	/* This should not happen */
	msg_warn("%s: %s: error reading peer certificate %s data",
		 myname, TLScontext->namaddr, label);
	tls_print_errors();
	return (0);
    }

    /*
     * XXX Convert everything into UTF-8. This is a super-set of ASCII, so we
     * don't have to bother with separate code paths for ASCII-like content.
     * If the payload is ASCII then we won't waste lots of CPU cycles
     * converting it into UTF-8. It's up to OpenSSL to do something
     * reasonable when converting ASCII formats that contain non-ASCII
     * content.
     * 
     * XXX Don't bother optimizing the string length error check. It is not
     * worth the complexity.
     */
    asn1_type = ASN1_STRING_type(entry_str);
    if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
	msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d",
		 myname, TLScontext->namaddr, label, asn1_type);
	tls_print_errors();
	return (0);
    }

    /*
     * No returns without cleaning up. A good optimizer will replace multiple
     * blocks of identical code by jumps to just one such block.
     */
#define TLS_TEXT_NAME_RETURN(x) do { \
	char *__tls_text_name_temp = (x); \
	OPENSSL_free(utf8_value); \
	return (__tls_text_name_temp); \
    } while (0)

    /*
     * Remove trailing null characters. They would give false alarms with the
     * length check and with the embedded null check.
     */
#define TRIM0(s, l) do { while ((l) > 0 && (s)[(l)-1] == 0) --(l); } while (0)

    TRIM0(utf8_value, utf8_length);

    /*
     * Enforce the length limit, because the caller will copy the result into
     * a fixed-length buffer.
     */
    if (utf8_length >= CCERT_BUFSIZ) {
	msg_warn("%s: %s: peer %s too long: %d",
		 myname, TLScontext->namaddr, label, utf8_length);
	TLS_TEXT_NAME_RETURN(0);
    }

    /*
     * Reject embedded nulls in ASCII or UTF-8 names. OpenSSL is responsible
     * for producing properly-formatted UTF-8.
     */
    if (utf8_length != strlen((char *) utf8_value)) {
	msg_warn("%s: %s: NULL character in peer %s",
		 myname, TLScontext->namaddr, label);
	TLS_TEXT_NAME_RETURN(0);
    }

    /*
     * Reject non-printable ASCII characters in UTF-8 content.
     * 
     * Note: the code below does not find control characters in illegal UTF-8
     * sequences. It's OpenSSL's job to produce valid UTF-8, and reportedly,
     * it does validation.
     */
    for (cp = utf8_value; (ch = *cp) != 0; cp++) {
	if (ISASCII(ch) && !ISPRINT(ch)) {
	    msg_warn("%s: %s: non-printable content in peer %s",
		     myname, TLScontext->namaddr, label);
	    TLS_TEXT_NAME_RETURN(0);
	}
    }
    TLS_TEXT_NAME_RETURN(mystrdup((char *) utf8_value));
}
示例#10
0
文件: cert.c 项目: michals/sx
CURLcode sxi_verifyhost(sxc_client_t *sx, const char *hostname, X509 *server_cert)
{
    int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
                         means mismatch */
    STACK_OF(GENERAL_NAME) *altnames;
    CURLcode res = CURLE_OK;

    /* 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 != 1); 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 == GEN_DNS) {
                /* 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);

                /* 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"

                   Curl uses strlen(altptr) == altlen here to check for embedded \0s.
                   We use memchr() to be safer from a possible non-null terminated string.
                   */
                if(!memchr(altptr, 0, altlen) &&
                   /* if this isn't true, there was an embedded zero in the name
                      string and we cannot match it. */
                   Curl_cert_hostcheck(altptr, hostname))
                    matched = 1;
                else
                    matched = 0;
            }
        }
        GENERAL_NAMES_free(altnames);
    }

    if(matched == 1)
        /* an alternative name matched the server hostname */
        SXDEBUG("\t subjectAltName: %s matched\n", hostname);
    else if(matched == 0) {
        /* an alternative name field existed, but didn't match and then
           we MUST fail */
        sxi_seterr(sx, SXE_ECOMM, "subjectAltName does not match %s\n", hostname);
        res = CURLE_PEER_FAILED_VERIFICATION;
    }
    else {
        /* we have to look to the last occurrence 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) {
                if(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 && memchr(peer_CN, 0, j)) {
                    /* there was a terminating zero before the end of string, this
                       cannot match and we return failure! */
                    sxi_seterr(sx, SXE_ECOMM, "SSL: illegal cert name field");
                    res = CURLE_PEER_FAILED_VERIFICATION;
                }
            }
        }

        if(peer_CN == nulstr)
            peer_CN = NULL;
        /* curl would convert from UTF8 to host encoding if built with HAVE_ICONV (not default) */

        if(res)
            /* error already detected, pass through */
            ;
        else if(!peer_CN) {
            SXDEBUG("SSL: unable to obtain common name from peer certificate");
            res = CURLE_PEER_FAILED_VERIFICATION;
        }
        else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
            sxi_seterr(sx, SXE_ECOMM, "SSL: certificate subject name '%s' does not match "
                    "target host name '%s'", peer_CN, hostname);
            res = CURLE_PEER_FAILED_VERIFICATION;
        }
        else {
            SXDEBUG("\t common name: %s (matched)\n", peer_CN);
        }
        if(peer_CN)
            OPENSSL_free(peer_CN);
    }
    return res;
}
示例#11
0
文件: openssl.c 项目: giuseppe/wget
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 = _get_rfc2253_formatted (X509_get_subject_name (cert));
      char *issuer = _get_rfc2253_formatted (X509_get_issuer_name (cert));
      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)));
      xfree (subject);
      xfree (issuer);
    }

  vresult = SSL_get_verify_result (conn);
  if (vresult != X509_V_OK)
    {
      char *issuer = _get_rfc2253_formatted (X509_get_issuer_name (cert));
      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));
      xfree(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_pop_free(subjectAltNames, GENERAL_NAME_free);
      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;
        }
示例#12
0
文件: ssl.c 项目: N0NB/aprx
int ssl_validate_peer_cert_phase2(struct client_t *c)
{
	int ret = -1;
	X509 *cert;
	X509_NAME *sname, *iname;
	char *subject, *issuer;
	char *subj_cn = NULL;
	char *subj_call = NULL;
	int nid, idx;
	X509_NAME_ENTRY *entry;
	ASN1_STRING *edata;
	
	cert = SSL_get_peer_certificate(c->ssl_con->connection);
	
	if (cert == NULL) {
		/* client did not give a certificate */
		return SSL_VALIDATE_NO_CLIENT_CERT;
	}
	
	/* ok, we have a cert, find subject */
	sname = X509_get_subject_name(cert);
	if (!sname) {
		ret = SSL_VALIDATE_CERT_NO_SUBJECT;
		goto fail;
	}
	subject = X509_NAME_oneline(sname, NULL, 0);
	
	/* find tqsl callsign */
	nid = OBJ_txt2nid("AROcallsign");
	if (nid == NID_undef) {
		hlog(LOG_ERR, "OBJ_txt2nid could not find NID for AROcallsign");
		ret = SSL_VALIDATE_INTERNAL_ERROR;
		goto fail;
	}
	
	idx = X509_NAME_get_index_by_NID(sname, nid, -1);
	if (idx == -1) {
		hlog(LOG_DEBUG, "%s/%s: peer certificate has no callsign: %s", c->addr_rem, c->username, subject);
		ret = SSL_VALIDATE_CERT_NO_CALLSIGN;
		goto fail;
	}
	
	entry = X509_NAME_get_entry(sname, idx);
	if (entry != NULL) {
		edata = X509_NAME_ENTRY_get_data(entry);
		if (edata != NULL)
			ASN1_STRING_to_UTF8((unsigned char **)&subj_call, edata);
	}
	
	/* find CN of subject */
	idx = X509_NAME_get_index_by_NID(sname, NID_commonName, -1);
	if (idx == -1) {
		hlog(LOG_DEBUG, "%s/%s: peer certificate has no CN: %s", c->addr_rem, c->username, subject);
	} else {
		entry = X509_NAME_get_entry(sname, idx);
		if (entry != NULL) {
			edata = X509_NAME_ENTRY_get_data(entry);
			if (edata != NULL)
				ASN1_STRING_to_UTF8((unsigned char **)&subj_cn, edata);
		}
	}
	
	if (!subj_call) {
		hlog(LOG_DEBUG, "%s/%s: peer certificate callsign conversion failed: %s", c->addr_rem, c->username, subject);
		ret = SSL_VALIDATE_CERT_NO_CALLSIGN;
		goto fail;
	}
	
	if (!ssl_cert_callsign_match(subj_call, c->username)) {
		ret = SSL_VALIDATE_CERT_CALLSIGN_MISMATCH;
		goto fail;
	}
	
	/* find issuer */
	iname = X509_get_issuer_name(cert);
	issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
	
	ret = 0;
	hlog(LOG_INFO, "%s/%s: Peer validated using SSL certificate: subject '%s' callsign '%s' CN '%s' issuer '%s'",
		c->addr_rem, c->username, subject, subj_call, (subj_cn) ? subj_cn : "(none)", issuer);
	
	/* store copies of cert subject and issuer */
	strncpy(c->cert_subject, subject, sizeof(c->cert_subject));
	c->cert_subject[sizeof(c->cert_subject)-1] = 0;
	strncpy(c->cert_issuer, issuer, sizeof(c->cert_issuer));
	c->cert_issuer[sizeof(c->cert_issuer)-1] = 0;
	
fail:	
	/* free up whatever we allocated */
	X509_free(cert);
	
	if (subj_call)
		OPENSSL_free(subj_call);
	if (subj_cn)
		OPENSSL_free(subj_cn);
	
	return ret;
}
示例#13
0
static int
amqp_ssl_socket_verify_hostname(void *base, const char *host)
{
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
  unsigned char *utf8_value = NULL, *cp, ch;
  int pos, utf8_length, status = 0;
  ASN1_STRING *entry_string;
  X509_NAME_ENTRY *entry;
  X509_NAME *name;
  X509 *peer;
  peer = SSL_get_peer_certificate(self->ssl);
  if (!peer) {
    goto error;
  }
  name = X509_get_subject_name(peer);
  if (!name) {
    goto error;
  }
  pos = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
  if (0 > pos) {
    goto error;
  }
  entry = X509_NAME_get_entry(name, pos);
  if (!entry) {
    goto error;
  }
  entry_string = X509_NAME_ENTRY_get_data(entry);
  if (!entry_string) {
    goto error;
  }
  utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_string);
  if (0 > utf8_length) {
    goto error;
  }
  while (utf8_length > 0 && utf8_value[utf8_length - 1] == 0) {
    --utf8_length;
  }
  if (utf8_length >= 256) {
    goto error;
  }
  if ((size_t)utf8_length != strlen((char *)utf8_value)) {
    goto error;
  }
  for (cp = utf8_value; (ch = *cp) != '\0'; ++cp) {
    if (isascii(ch) && !isprint(ch)) {
      goto error;
    }
  }
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
  if (strcasecmp(host, (char *)utf8_value)) {
    goto error;
  }
#ifdef _MSC_VER
#undef strcasecmp
#endif
exit:
  OPENSSL_free(utf8_value);
  return status;
error:
  status = -1;
  goto exit;
}
示例#14
0
Handle<PkiItem> Provider_System::objectToPKIItem(Handle<std::string> uri){
	LOGGER_FN();

	Handle<PkiItem> item;

	Handle<Bio> in =  new Bio(BIO_TYPE_FILE, uri->c_str(), "rb");

	try{
		item = new PkiItem();

		X509_REQ *xreq = NULL;
		X509 *xcert = NULL;
		X509_CRL *xcrl = NULL;

		Handle<Certificate> hcert = NULL;
		Handle<CRL> hcrl = NULL;

		std::string listCertStore[] = {
			"MY",
			"OTHERS",
			"TRUST",
			"CRL"
		};

		std::string strTrust = (uri->substr(0, (uri->find_last_of(CROSSPLATFORM_SLASH))));
		strTrust = strTrust.substr(strTrust.find_last_of(CROSSPLATFORM_SLASH) + 1, strTrust.length());

		bool trueTrust = false;
		for (int i = 0, c = sizeof(listCertStore) / sizeof(*listCertStore); i < c; i++){
			if (strcmp(listCertStore[i].c_str(), strTrust.c_str()) == 0){
				trueTrust = true;
				break;
			}
		}
		if (!trueTrust){
			THROW_EXCEPTION(0, Provider_System, NULL, "Category of object is uncorrect");
		}

		int enc;
		if (itPrivateKey(uri, &enc)){
			item->type = new std::string("KEY");
			item->uri = uri;
			item->provider = new std::string("SYSTEM");
			item->category = new std::string(strTrust);
			item->keyEncrypted = enc;
			item->format = new std::string("PEM");

			Handle<std::string> keyHash = new std::string(uri->c_str());
			const size_t last_slash_idx = keyHash->find_last_of(CROSSPLATFORM_SLASH);
			if (std::string::npos != last_slash_idx){
				keyHash->erase(0, last_slash_idx + 1);
			}
			const size_t period_idx = keyHash->rfind('.');
			if (std::string::npos != period_idx){
				keyHash->erase(period_idx);
			}
			if (keyHash->length() == 40){
				item->hash = keyHash;
			}
			else{
				THROW_EXCEPTION(0, Provider_System, NULL, "Error length hash (need 40 for sha1). Hash is privatekey filename");
			}

			return item;			
		}

		in->seek(0);

		LOGGER_OPENSSL(PEM_read_bio_X509);
		xcert = PEM_read_bio_X509(in->internal(), NULL, NULL, NULL);
		if (xcert){
			hcert = new Certificate(xcert);
			item->format = new std::string("PEM");		
		}
		else{
			in->seek(0);

			LOGGER_OPENSSL(d2i_X509_bio);
			xcert = d2i_X509_bio(in->internal(), NULL);
			if (xcert){
				hcert = new Certificate(xcert);
				item->format = new std::string("DER");
			}
		}

		if (!hcert.isEmpty()){
			item->type = new std::string("CERTIFICATE");
			item->uri = uri;
			item->provider = new std::string("SYSTEM");
			item->category = new std::string(strTrust);

			char * hexHash;
			Handle<std::string> hhash = hcert->getThumbprint();
			PkiStore::bin_to_strhex((unsigned char *)hhash->c_str(), hhash->length(), &hexHash);
			item->hash = new std::string(hexHash);

			item->certSubjectName = hcert->getSubjectName();
			item->certSubjectFriendlyName = hcert->getSubjectFriendlyName();
			item->certIssuerName = hcert->getIssuerName();
			item->certIssuerFriendlyName = hcert->getIssuerFriendlyName();
			item->certSerial = hcert->getSerialNumber();
			item->certOrganizationName = hcert->getOrganizationName();
			item->certSignatureAlgorithm = hcert->getSignatureAlgorithm();

			item->certNotBefore = hcert->getNotBefore();
			item->certNotAfter = hcert->getNotAfter();
			
			item->certKey = getKey(uri);
		
			return item;
		}

		in->seek(0);

		LOGGER_OPENSSL(PEM_read_bio_X509_REQ);
		xreq = PEM_read_bio_X509_REQ(in->internal(), NULL, NULL, NULL);
		if (xreq){
			item->format = new std::string("PEM");
		}
		else{
			in->seek(0);

			LOGGER_OPENSSL(d2i_X509_REQ_bio);
			xreq = d2i_X509_REQ_bio(in->internal(), NULL);
			if (xreq){
				item->format = new std::string("DER");
			}
		}

		if (xreq){
			item->type = new std::string("REQUEST");
			item->uri = uri;
			item->provider = new std::string("SYSTEM");
			item->category = new std::string(strTrust);

			/* SHA-1 hash */
			unsigned char hash[EVP_MAX_MD_SIZE] = { 0 };
			unsigned int hashlen = 0;
			LOGGER_OPENSSL(X509_digest);
			if (!X509_REQ_digest(xreq, EVP_sha1(), hash, &hashlen)) {
				THROW_OPENSSL_EXCEPTION(0, Provider_System, NULL, "X509_REQ_digest");
			}
			Handle<std::string> hhash = new std::string((char *)hash, hashlen);

			char * hexHash;
			PkiStore::bin_to_strhex((unsigned char *)hhash->c_str(), hhash->length(), &hexHash);
			item->hash = new std::string(hexHash);

			/* Request subject name */
			LOGGER_OPENSSL(X509_REQ_get_subject_name);
			X509_NAME *name = X509_REQ_get_subject_name(xreq);
			if (!name){
				THROW_EXCEPTION(0, Provider_System, NULL, "X509_NAME is NULL");
			}				
			LOGGER_OPENSSL(X509_NAME_oneline_ex);
			std::string str_name = X509_NAME_oneline_ex(name);
			Handle<std::string> nameRes = new std::string(str_name.c_str(), str_name.length());
			item->csrSubjectName = nameRes;

			/* Request subject friendly name */
			Handle<std::string> friendlyName = new std::string("");
			int nid = NID_commonName;
			LOGGER_OPENSSL(X509_NAME_get_index_by_NID);
			int index = X509_NAME_get_index_by_NID(name, nid, -1);
			if (index >= 0) {
				LOGGER_OPENSSL(X509_NAME_get_entry);
				X509_NAME_ENTRY *issuerNameCommonName = X509_NAME_get_entry(name, index);

				if (issuerNameCommonName) {
					LOGGER_OPENSSL(X509_NAME_ENTRY_get_data);
					ASN1_STRING *issuerCNASN1 = X509_NAME_ENTRY_get_data(issuerNameCommonName);

					if (issuerCNASN1 != NULL) {
						unsigned char *utf = NULL;
						LOGGER_OPENSSL(ASN1_STRING_to_UTF8);
						ASN1_STRING_to_UTF8(&utf, issuerCNASN1);
						friendlyName = new std::string((char *)utf);
						OPENSSL_free(utf);
					}
				}
			}
			else {
				friendlyName = new std::string("No common name");
			}
			item->csrSubjectFriendlyName = friendlyName;
			item->csrKey = getKey(uri);

			return item;
		}

		in->seek(0);

		LOGGER_OPENSSL(PEM_read_bio_X509_CRL);
		xcrl = PEM_read_bio_X509_CRL(in->internal(), NULL, NULL, NULL);
		if (xcrl){
			hcrl = new CRL(xcrl);
			item->format = new std::string("PEM");
		}
		else{
			in->seek(0);

			LOGGER_OPENSSL(d2i_X509_CRL_bio);
			xcrl = d2i_X509_CRL_bio(in->internal(), NULL);
			if (xcrl){
				hcrl = new CRL(xcrl);
				item->format = new std::string("DER");
			}
		}

		if (!hcrl.isEmpty()){
			item->type = new std::string("CRL");
			item->uri = uri;
			item->provider = new std::string("SYSTEM");			
			item->category = new std::string(strTrust);
			
			char * hexHash;
			Handle<std::string> hhash = hcrl->getThumbprint();
			PkiStore::bin_to_strhex((unsigned char *)hhash->c_str(), hhash->length(), &hexHash);
			item->hash = new std::string(hexHash);

			item->crlIssuerName = hcrl->issuerName();
			item->crlIssuerFriendlyName = hcrl->issuerFriendlyName();
			item->crlLastUpdate = hcrl->getThisUpdate();
			item->crlNextUpdate = hcrl->getNextUpdate();

			return item;
		}
	}
	catch (Handle<Exception> e){
		THROW_EXCEPTION(0, Provider_System, e, "Object type not supported");
	}

	if (item->type->length() == 0){
		return NULL;
	}
}
示例#15
0
static int get_comp(str* res, int local, int issuer, int nid, sip_msg_t* msg)
{
    static char buf[1024];
    X509* cert;
    struct tcp_connection* c;
    X509_NAME* name;
    X509_NAME_ENTRY* e;
    ASN1_STRING* asn1;
    int index, text_len;
    char* elem;
    unsigned char* text_s;

    text_s = 0;

    if (get_cert(&cert, &c, msg, local) < 0) return -1;

    name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert);
    if (!name) {
        ERR("Cannot extract subject or issuer name from peer certificate\n");
        goto err;
    }

    index = X509_NAME_get_index_by_NID(name, nid, -1);
    if (index == -1) {
        switch(nid) {
        case NID_commonName:
            elem = "CommonName";
            break;
        case NID_organizationName:
            elem = "OrganizationName";
            break;
        case NID_organizationalUnitName:
            elem = "OrganizationalUnitUname";
            break;
        case NID_countryName:
            elem = "CountryName";
            break;
        case NID_stateOrProvinceName:
            elem = "StateOrProvinceName";
            break;
        case NID_localityName:
            elem = "LocalityName";
            break;
        default:
            elem = "Unknown";
            break;
        }
        DBG("Element %s not found in certificate subject/issuer\n", elem);
        goto err;
    }

    e = X509_NAME_get_entry(name, index);
    asn1 = X509_NAME_ENTRY_get_data(e);
    text_len = ASN1_STRING_to_UTF8(&text_s, asn1);
    if (text_len < 0 || text_len >= 1024) {
        ERR("Error converting ASN1 string\n");
        goto err;
    }
    memcpy(buf, text_s, text_len);
    res->s = buf;
    res->len = text_len;

    OPENSSL_free(text_s);
    if (!local) X509_free(cert);
    tcpconn_put(c);
    return 0;

err:
    if (text_s) OPENSSL_free(text_s);
    if (!local) X509_free(cert);
    tcpconn_put(c);
    return -1;
}
示例#16
0
/* 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

#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);
        OPENSSL_free(peer_CN);
        return 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);
      OPENSSL_free(peer_CN);
    }
  }
  return CURLE_OK;
}
示例#17
0
// Certificate chain verification callback: return 1 if verified,
// 0 if remote cannot be verified (fail handshake).
//
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
  if (!preverify_ok || X509_STORE_CTX_get_error_depth(ctx) != 0)
    // already failed, or not at peer cert in chain
    return preverify_ok;

  X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
  SSL *ssn = (SSL *) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
  if (!ssn) {
    pn_transport_logf(NULL, "Error: unexpected error - SSL session info not available for peer verify!");
    return 0;  // fail connection
  }

  pn_transport_t *transport = (pn_transport_t *)SSL_get_ex_data(ssn, ssl_ex_data_index);
  if (!transport) {
    pn_transport_logf(NULL, "Error: unexpected error - SSL context info not available for peer verify!");
    return 0;  // fail connection
  }

  pni_ssl_t *ssl = transport->ssl;
  if (ssl->domain->verify_mode != PN_SSL_VERIFY_PEER_NAME) return preverify_ok;
  if (!ssl->peer_hostname) {
    pn_transport_logf(transport, "Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
    return 0;  // fail connection
  }

  ssl_log(transport, "Checking identifying name in peer cert against '%s'", ssl->peer_hostname);

  bool matched = false;

  /* first check any SubjectAltName entries, as per RFC2818 */
  GENERAL_NAMES *sans = (GENERAL_NAMES *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
  if (sans) {
    int name_ct = sk_GENERAL_NAME_num( sans );
    int i;
    for (i = 0; !matched && i < name_ct; ++i) {
      GENERAL_NAME *name = sk_GENERAL_NAME_value( sans, i );
      if (name->type == GEN_DNS) {
        ASN1_STRING *asn1 = name->d.dNSName;
        if (asn1 && asn1->data && asn1->length) {
          unsigned char *str;
          int len = ASN1_STRING_to_UTF8( &str, asn1 );
          if (len >= 0) {
            ssl_log(transport, "SubjectAltName (dns) from peer cert = '%.*s'", len, str );
            matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
            OPENSSL_free( str );
          }
        }
      }
    }
    GENERAL_NAMES_free( sans );
  }

  /* if no general names match, try the CommonName from the subject */
  X509_NAME *name = X509_get_subject_name(cert);
  int i = -1;
  while (!matched && (i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) {
    X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i);
    ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne);
    if (name_asn1) {
      unsigned char *str;
      int len = ASN1_STRING_to_UTF8( &str, name_asn1);
      if (len >= 0) {
        ssl_log(transport, "commonName from peer cert = '%.*s'", len, str);
        matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
        OPENSSL_free(str);
      }
    }
  }

  if (!matched) {
    ssl_log(transport, "Error: no name matching %s found in peer cert - rejecting handshake.",
          ssl->peer_hostname);
    preverify_ok = 0;
#ifdef X509_V_ERR_APPLICATION_VERIFICATION
    X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION );
#endif
  } else {
    ssl_log(transport, "Name from peer cert matched - peer is valid.");
  }
  return preverify_ok;
}
示例#18
0
static int
sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
{
	sc_card_t *card = p15card->card;
	unsigned char buff[128];
	int r, i;
	sc_path_t tmppath;

	set_string (&p15card->tokeninfo->label, "ID-kaart");
	set_string (&p15card->tokeninfo->manufacturer_id, "AS Sertifitseerimiskeskus");

	/* Select application directory */
	sc_format_path ("3f00eeee5044", &tmppath);
	r = sc_select_file (card, &tmppath, NULL);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "select esteid PD failed");

	/* read the serial (document number) */	
	r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "read document number failed");
	buff[r] = '\0';
	set_string (&p15card->tokeninfo->serial_number, (const char *) buff);

	p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION
				  | SC_PKCS15_TOKEN_EID_COMPLIANT
				  | SC_PKCS15_TOKEN_READONLY;

	/* add certificates */
	for (i = 0; i < 2; i++) {
		static const char *esteid_cert_names[2] = {
			"Isikutuvastus",
			"Allkirjastamine"};
		static char const *esteid_cert_paths[2] = {
			"3f00eeeeaace",
			"3f00eeeeddce"};
		static int esteid_cert_ids[2] = {1, 2};
			
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object cert_obj;
		
		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj, 0, sizeof(cert_obj));

		cert_info.id.value[0] = esteid_cert_ids[i];
		cert_info.id.len = 1;
		sc_format_path(esteid_cert_paths[i], &cert_info.path);
		strlcpy(cert_obj.label, esteid_cert_names[i], sizeof(cert_obj.label));
		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
#ifdef ENABLE_OPENSSL
		if (i == 0) {
			BIO *mem = NULL;
			X509 *x509 = NULL;
			sc_pkcs15_cert_t *cert;
			char cardholder_name[64];
			unsigned char *tmp = NULL;
			r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
			if (r == SC_SUCCESS) {
				mem = BIO_new_mem_buf(cert->data.value, cert->data.len);
				if (!mem) {
					sc_pkcs15_free_certificate(cert);
					return SC_ERROR_INTERNAL;
				}
				x509 = d2i_X509_bio(mem, NULL);
				BIO_free(mem);
				sc_pkcs15_free_certificate(cert);
				if (!x509)
					return SC_ERROR_INTERNAL;
				r = X509_NAME_get_index_by_NID(X509_get_subject_name(x509), NID_commonName, -1);
				if (r >= 0) {
					X509_NAME_ENTRY *ne;
					ASN1_STRING *a_str;
					ne = X509_NAME_get_entry(X509_get_subject_name(x509), r);
					if (!ne) {
						X509_free(x509);
						return SC_ERROR_INTERNAL;
					}
					a_str = X509_NAME_ENTRY_get_data(ne);
					if (!a_str) {
						X509_free(x509);
						return SC_ERROR_INTERNAL;
					}
					r = ASN1_STRING_to_UTF8(&tmp, a_str);
					if (r > 0) {
						if ((unsigned)r > sizeof(cardholder_name) - 1)
							r = sizeof(cardholder_name) -1;
						memcpy(cardholder_name, tmp, r);
						cardholder_name[r] = '\0';
						set_string(&p15card->tokeninfo->label, cardholder_name);
						OPENSSL_free(tmp);
					}
				}
				X509_free(x509);
			}
		}
#endif
	}

	/* the file with key pin info (tries left) */
	sc_format_path ("3f000016", &tmppath);
	r = sc_select_file (card, &tmppath, NULL);
	if (r < 0)
		return SC_ERROR_INTERNAL;

	/* add pins */
	for (i = 0; i < 3; i++) {
		unsigned char tries_left;
		static const char *esteid_pin_names[3] = {
			"PIN1",
			"PIN2",
			"PUK" };
			
		static const int esteid_pin_min[3] = {4, 5, 8};
		static const int esteid_pin_ref[3] = {1, 2, 0};
		static const int esteid_pin_authid[3] = {1, 2, 3};
		static const int esteid_pin_flags[3] = {0, 0, SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN};
		
		struct sc_pkcs15_auth_info pin_info;
		struct sc_pkcs15_object pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj, 0, sizeof(pin_obj));
		
		/* read the number of tries left for the PIN */
		r = sc_read_record (card, i + 1, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
		if (r < 0)
			return SC_ERROR_INTERNAL;
		tries_left = buff[5];
		
		pin_info.auth_id.len = 1;
		pin_info.auth_id.value[0] = esteid_pin_authid[i];
		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;	
		pin_info.attrs.pin.reference = esteid_pin_ref[i];
		pin_info.attrs.pin.flags = esteid_pin_flags[i];
		pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
		pin_info.attrs.pin.min_length = esteid_pin_min[i];
		pin_info.attrs.pin.stored_length = 12;
		pin_info.attrs.pin.max_length = 12;
		pin_info.attrs.pin.pad_char = '\0';
		pin_info.tries_left = (int)tries_left;
		pin_info.max_tries = 3;

		strlcpy(pin_obj.label, esteid_pin_names[i], sizeof(pin_obj.label));
		pin_obj.flags = esteid_pin_flags[i];

		/* Link normal PINs with PUK */
		if (i < 2) {
			pin_obj.auth_id.len = 1;
			pin_obj.auth_id.value[0] = 3;
		}

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
	
	/* add private keys */
	for (i = 0; i < 2; i++) {
		static int prkey_pin[2] = {1, 2};
		static int prkey_usage[2] = {
			SC_PKCS15_PRKEY_USAGE_ENCRYPT
			| SC_PKCS15_PRKEY_USAGE_DECRYPT
			| SC_PKCS15_PRKEY_USAGE_SIGN,
			SC_PKCS15_PRKEY_USAGE_NONREPUDIATION};
			
		static const char *prkey_name[2] = {
			"Isikutuvastus",
			"Allkirjastamine"};

		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object prkey_obj;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj, 0, sizeof(prkey_obj));
		
		prkey_info.id.len = 1;
		prkey_info.id.value[0] = prkey_pin[i];
		prkey_info.usage  = prkey_usage[i];
		prkey_info.native = 1;
		prkey_info.key_reference = i + 1;
		if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30)
			prkey_info.modulus_length = 2048;
		else
			prkey_info.modulus_length = 1024;	

		strlcpy(prkey_obj.label, prkey_name[i], sizeof(prkey_obj.label));
		prkey_obj.auth_id.len = 1;
		prkey_obj.auth_id.value[0] = prkey_pin[i];
		prkey_obj.user_consent = 0;
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	return SC_SUCCESS;
}
示例#19
0
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 {
			goto cert_fail_name;
		}
	} 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;
}
示例#20
0
/* this is called after the connection on the client side by us to check
   other aspects about the connection */
int netsnmp_tlsbase_verify_server_cert (SSL * ssl, _netsnmpTLSBaseData * tlsdata)
{
    /* XXX */
    X509 *remote_cert;

    char *check_name;

    int ret;

    netsnmp_assert_or_return (ssl != NULL, SNMPERR_GENERR);
    netsnmp_assert_or_return (tlsdata != NULL, SNMPERR_GENERR);

    if (NULL == (remote_cert = SSL_get_peer_certificate (ssl)))
    {
        /* no peer cert */
        DEBUGMSGTL (("tls_x509:verify", "remote connection provided no certificate (yet)\n"));
        return SNMPERR_TLS_NO_CERTIFICATE;
    }

    /* make sure that the fingerprint matches */
    ret = _netsnmp_tlsbase_verify_remote_fingerprint (remote_cert, tlsdata, 1);
    switch (ret)
    {
        case VERIFIED_FINGERPRINT:
            return SNMPERR_SUCCESS;

        case FAILED_FINGERPRINT_VERIFY:
            return SNMPERR_GENERR;

        case NO_FINGERPRINT_AVAILABLE:
            if (tlsdata->their_hostname && tlsdata->their_hostname[0] != '\0')
            {
                GENERAL_NAMES *onames;

                const GENERAL_NAME *oname = NULL;

                int i, j;

                int count;

                char buf[SPRINT_MAX_LEN];

                int is_wildcarded = 0;

                char *compare_to;

                /* see if the requested hostname has a wildcard prefix */
                if (strncmp (tlsdata->their_hostname, "*.", 2) == 0)
                {
                    is_wildcarded = 1;
                    compare_to = tlsdata->their_hostname + 2;
                }
                else
                {
                    compare_to = tlsdata->their_hostname;
                }

                /* if the hostname we were expecting to talk to matches
                   the cert, then we can accept this connection. */

                /* check against the DNS subjectAltName */
                onames = (GENERAL_NAMES *) X509_get_ext_d2i (remote_cert, NID_subject_alt_name, NULL, NULL);
                if (NULL != onames)
                {
                    count = sk_GENERAL_NAME_num (onames);

                    for (i = 0; i < count; ++i)
                    {
                        oname = sk_GENERAL_NAME_value (onames, i);
                        if (GEN_DNS == oname->type)
                        {

                            /* get the value */
                            ASN1_STRING_to_UTF8 ((unsigned char **) &check_name, oname->d.ia5);

                            /* convert to lowercase for comparisons */
                            for (j = 0; *check_name && j < sizeof (buf) - 1; ++check_name, ++j)
                            {
                                if (isascii (*check_name))
                                    buf[j] = tolower (0xFF & *check_name);
                            }
                            if (j < sizeof (buf))
                                buf[j] = '\0';
                            check_name = buf;

                            if (is_wildcarded)
                            {
                                /* we *only* allow passing till the first '.' */
                                /* ie *.example.com can't match a.b.example.com */
                                check_name = strchr (check_name, '.') + 1;
                            }

                            DEBUGMSGTL (("tls_x509:verify", "checking subjectAltname of dns:%s\n", check_name));
                            if (strcmp (compare_to, check_name) == 0)
                            {

                                DEBUGMSGTL (("tls_x509:verify", "Successful match on a subjectAltname of dns:%s\n",
                                             check_name));
                                return SNMPERR_SUCCESS;
                            }
                        }
                    }
                }

                /* check the common name for a match */
                check_name = netsnmp_openssl_cert_get_commonName (remote_cert, NULL, NULL);

                if (is_wildcarded)
                {
                    /* we *only* allow passing till the first '.' */
                    /* ie *.example.com can't match a.b.example.com */
                    check_name = strchr (check_name, '.') + 1;
                }

                if (strcmp (compare_to, check_name) == 0)
                {
                    DEBUGMSGTL (("tls_x509:verify", "Successful match on a common name of %s\n", check_name));
                    return SNMPERR_SUCCESS;
                }

                snmp_log (LOG_ERR, "No matching names in the certificate to match the expected %s\n",
                          tlsdata->their_hostname);
                return SNMPERR_GENERR;

            }
            /* XXX: check for hostname match instead */
            snmp_log (LOG_ERR, "Can not verify a remote server identity without configuration\n");
            return SNMPERR_GENERR;
    }
    DEBUGMSGTL (("tls_x509:verify", "shouldn't get here\n"));
    return SNMPERR_GENERR;
}
示例#21
0
/** check if a provided cert matches a passed hostname
 */
bool
_mongoc_openssl_check_cert (SSL *ssl,
                            const char *host,
                            bool allow_invalid_hostname)
{
   X509 *peer;
   X509_NAME *subject_name;
   X509_NAME_ENTRY *entry;
   ASN1_STRING *entry_data;
   int length;
   int idx;
   int r = 0;
   long verify_status;

   size_t addrlen = 0;
   unsigned char addr4[sizeof (struct in_addr)];
   unsigned char addr6[sizeof (struct in6_addr)];
   int i;
   int n_sans = -1;
   int target = GEN_DNS;

   STACK_OF (GENERAL_NAME) *sans = NULL;

   ENTRY;
   BSON_ASSERT (ssl);
   BSON_ASSERT (host);

   if (allow_invalid_hostname) {
      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, &addr4)) {
      target = GEN_IPADD;
      addrlen = sizeof addr4;
   } else if (inet_pton (AF_INET6, host, &addr6)) {
      target = GEN_IPADD;
      addrlen = sizeof addr6;
   }

   peer = SSL_get_peer_certificate (ssl);

   if (!peer) {
      MONGOC_WARNING ("SSL Certification verification failed: %s",
                      ERR_error_string (ERR_get_error (), NULL));
      RETURN (false);
   }

   verify_status = SSL_get_verify_result (ssl);

   if (verify_status == X509_V_OK) {
      /* gets 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) {
               const char *check;

               check = (const char *) ASN1_STRING_get0_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_openssl_hostcheck (check, host)) {
                     r = 1;
                  }

                  break;
               case GEN_IPADD:
                  if (length == addrlen) {
                     if (length == sizeof addr6 &&
                         !memcmp (check, &addr6, length)) {
                        r = 1;
                     } else if (length == sizeof addr4 &&
                                !memcmp (check, &addr4, length)) {
                        r = 1;
                     }
                  }

                  break;
               default:
                  BSON_ASSERT (0);
                  break;
               }
            }
         }
         GENERAL_NAMES_free (sans);
      } else {
         subject_name = X509_get_subject_name (peer);

         if (subject_name) {
            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) {
                  char *check;

                  /* 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_openssl_hostcheck (check, host)) {
                        r = 1;
                     }

                     OPENSSL_free (check);
                  }
               }
            }
         }
      }
   }
示例#22
0
/*! \brief
* creates a FILE * from the fd passed by the accept thread.
* This operation is potentially expensive (certificate verification),
* so we do it in the child thread context.
*
* \note must decrement ref count before returning NULL on error
*/
static void *handle_tcptls_connection(void *data)
{
	struct ast_tcptls_session_instance *tcptls_session = data;
#ifdef DO_SSL
	int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept;
	int ret;
	char err[256];
#endif

	/*
	* open a FILE * as appropriate.
	*/
	if (!tcptls_session->parent->tls_cfg) {
		tcptls_session->f = fdopen(tcptls_session->fd, "w+");
		setvbuf(tcptls_session->f, NULL, _IONBF, 0);
	}
#ifdef DO_SSL
	else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) {
		SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
		if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) {
			ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
		} else {
#if defined(HAVE_FUNOPEN)	/* the BSD interface */
			tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close);

#elif defined(HAVE_FOPENCOOKIE)	/* the glibc/linux interface */
			static const cookie_io_functions_t cookie_funcs = {
				ssl_read, ssl_write, NULL, ssl_close
			};
			tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs);
#else
			/* could add other methods here */
			ast_debug(2, "no tcptls_session->f methods attempted!");
#endif
			if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
				|| (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
				X509 *peer;
				long res;
				peer = SSL_get_peer_certificate(tcptls_session->ssl);
				if (!peer)
					ast_log(LOG_WARNING, "No peer SSL certificate\n");
				res = SSL_get_verify_result(tcptls_session->ssl);
				if (res != X509_V_OK)
					ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res));
				if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
					ASN1_STRING *str;
					unsigned char *str2;
					X509_NAME *name = X509_get_subject_name(peer);
					int pos = -1;
					int found = 0;
				
					for (;;) {
						/* Walk the certificate to check all available "Common Name" */
						/* XXX Probably should do a gethostbyname on the hostname and compare that as well */
						pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
						if (pos < 0)
							break;
						str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
						ASN1_STRING_to_UTF8(&str2, str);
						if (str2) {
							if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2))
								found = 1;
							ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2);
							OPENSSL_free(str2);
						}
						if (found)
							break;
					}
					if (!found) {
						ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname);
						if (peer)
							X509_free(peer);
						close(tcptls_session->fd);
						fclose(tcptls_session->f);
						ao2_ref(tcptls_session, -1);
						return NULL;
					}
				}
				if (peer)
					X509_free(peer);
			}
		}
		if (!tcptls_session->f)	/* no success opening descriptor stacking */
			SSL_free(tcptls_session->ssl);
   }
#endif /* DO_SSL */

	if (!tcptls_session->f) {
		close(tcptls_session->fd);
		ast_log(LOG_WARNING, "FILE * open failed!\n");
		ao2_ref(tcptls_session, -1);
		return NULL;
	}

	if (tcptls_session && tcptls_session->parent->worker_fn)
		return tcptls_session->parent->worker_fn(tcptls_session);
	else
		return tcptls_session;
}