Beispiel #1
0
/* check whether cert contains extended key usage with a SGC tag */
BOOL SSL_X509_isSGC(X509 *cert)
{
    X509_EXTENSION *ext;
    int ext_nid;
    STACK *sk;
    BOOL is_sgc;
    int idx;
    int i;
    
    is_sgc = FALSE;
    idx = X509_get_ext_by_NID(cert, NID_ext_key_usage, -1);
    if (idx >= 0) {
        ext = X509_get_ext(cert, idx);
        if ((sk = (STACK *)X509V3_EXT_d2i(ext)) != NULL) {
            for (i = 0; i < sk_num(sk); i++) {
                ext_nid = OBJ_obj2nid((ASN1_OBJECT *)sk_value(sk, i));
                if (ext_nid == NID_ms_sgc || ext_nid == NID_ns_sgc) {
                    is_sgc = TRUE;
                    break;
                }
            }
        }
    }
    return is_sgc;
}
Beispiel #2
0
/* retrieve basic constraints ingredients */
BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen)
{
    X509_EXTENSION *ext;
    BASIC_CONSTRAINTS *bc;
    int idx;
    BIGNUM *bn = NULL;
    char *cp;
    
    if ((idx = X509_get_ext_by_NID(cert, NID_basic_constraints, -1)) < 0)
        return FALSE;
    ext = X509_get_ext(cert, idx);
    if (ext == NULL)
        return FALSE;
    if ((bc = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ext)) == NULL)
        return FALSE;
    *ca = bc->ca;
    *pathlen = -1 /* unlimited */;
    if (bc->pathlen != NULL) {
        if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL)
            return FALSE;
        if ((cp = BN_bn2dec(bn)) == NULL)
            return FALSE;
        *pathlen = atoi(cp);
        OPENSSL_free(cp);
        BN_free(bn);
    }
    BASIC_CONSTRAINTS_free(bc);
    return TRUE;
}
AuthorityKeyIdentifierExtension::AuthorityKeyIdentifierExtension(X509_EXTENSION *ext)
throw (CertificationException) : Extension(ext)
{
    AUTHORITY_KEYID *authKeyId;
    if (this->objectIdentifier.getNid() != NID_authority_key_identifier)
    {
        throw CertificationException(CertificationException::INVALID_TYPE, "AuthorityKeyIdentifierExtension::AuthorityKeyIdentifierExtension");
    }
    authKeyId = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext);
    if (authKeyId->keyid)
    {
        this->keyIdentifier = ByteArray(authKeyId->keyid->data, authKeyId->keyid->length);
    }
    if (authKeyId->issuer)
    {
        this->authorityCertIssuer = GeneralNames(authKeyId->issuer);
    }
    if (authKeyId->serial)
    {
        this->serialNumber = ASN1_INTEGER_get(authKeyId->serial);
    }
    else
    {
        this->serialNumber = -1;
    }
    AUTHORITY_KEYID_free(authKeyId);
}
Beispiel #4
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;
}
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());
			}
		}
	}
}
SubjectKeyIdentifierExtension::SubjectKeyIdentifierExtension(X509_EXTENSION *ext)
		throw (CertificationException) : Extension(ext)
{
	ASN1_OCTET_STRING *octetString;
	if (OBJ_obj2nid(ext->object) != NID_subject_key_identifier)
	{
		throw CertificationException(CertificationException::INVALID_TYPE, "SubjectKeyIdentifierExtension::SubjectKeyIdentifierExtension");
	}
	octetString = (ASN1_OCTET_STRING *)X509V3_EXT_d2i(ext);
	keyIdentifier = ByteArray(octetString->data, octetString->length);
	ASN1_OCTET_STRING_free(octetString);
}
Beispiel #7
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;
}
// must be called between _commitmentExt_start and _commitmentExt_end
static BIGNUM* _commitmentExt2BN(X509_EXTENSION *ext) {

	// get the extension data as a string
	ASN1_IA5STRING *ia5 = (ASN1_IA5STRING *) X509V3_EXT_d2i(ext);
	char *str = ASN1_STRING_data(ia5);

	// convert the string into a BIGNUM
	BIGNUM *toret = BN_new();
	BN_hex2bn(&toret, str);
	free(str);

	return toret;
}
Beispiel #9
0
// verify if prefix is part of the resources listed in cert
// CA and untrusted are needed, because the resources in cert could be inherited
// prefix_as_ext is the text-representation of an ip-address block like you would specify in an extension file
// when creating a certificate, e.g. IPv6:2001:0638::/32
int verify_prefix_with_cert(
    int CA_der_count,
    int CA_der_length,
    const char* CAs_der, 
    int untrusted_der_count,
    int untrusted_der_length,
    const char* untrusted_der,
    int cert_der_length,
    const char* cert_der,
    char* prefix_as_ext
) 
{
    X509_EXTENSION *prefix_ext;
    IPAddrBlocks *prefix_blocks = NULL;
    STACK_OF(X509) *chain = NULL;

    int allow_inheritance = 0; // router prefix cannot inherit
    int ret = 0;
    if ((prefix_ext = X509V3_EXT_conf_nid(NULL, NULL, NID_sbgp_ipAddrBlock, prefix_as_ext)) == NULL){
        ret = -1;
        goto end;
    }
    prefix_blocks = (IPAddrBlocks *) X509V3_EXT_d2i(prefix_ext);
    X509_EXTENSION_free(prefix_ext);

    chain = get_verified_chain(
        CA_der_count,
        CA_der_length,
        CAs_der,
        untrusted_der_count,
        untrusted_der_length,
        untrusted_der,
        cert_der_length,
        cert_der
    );

    if (chain == NULL) {
        ret = 0;
    } else {
        ret = v3_addr_validate_resource_set(chain, prefix_blocks, allow_inheritance);
    }
end:
    if (prefix_blocks != NULL) sk_IPAddressFamily_pop_free(prefix_blocks, IPAddressFamily_free);
    if (chain != NULL) sk_X509_pop_free(chain, X509_free);

    return ret;
}
DeltaCRLIndicatorExtension::DeltaCRLIndicatorExtension(X509_EXTENSION* ext) throw (CertificationException) : Extension(ext)
{
	ASN1_INTEGER* serialAsn1 = NULL;
	
	if (OBJ_obj2nid(ext->object) != NID_delta_crl)
	{
		X509_EXTENSION_free(ext);
		throw CertificationException(CertificationException::INVALID_TYPE, "DeltaCRLIndicatorExtension::DeltaCRLIndicatorExtension");
	}
	serialAsn1 = (ASN1_INTEGER *)X509V3_EXT_d2i(ext);
	
	if(!serialAsn1)
	{	
		throw CertificationException(CertificationException::INTERNAL_ERROR, "DeltaCRLIndicatorExtension::DeltaCRLIndicatorExtension");
	}
	
	this->baseCrlNumber = ASN1_INTEGER_get(serialAsn1);
	ASN1_INTEGER_free(serialAsn1);
}
Beispiel #11
0
PKI_X509_EXTENSION_STACK *PKI_X509_CERT_get_extensions(const PKI_X509_CERT *x) {

  PKI_X509_EXTENSION_STACK *ret = NULL;

  int i = 0;
  int ext_count = 0;

  if (!x) return NULL;

  if ((ext_count = X509_get_ext_count (x->value)) <= 0 ) return NULL;

  for ( i=0; i < ext_count; i++ ) {
    LIBPKI_X509_EXTENSION *ext = NULL;
    // PKI_X509_EXTENSION_VALUE *ext = NULL;
    PKI_X509_EXTENSION *pki_ext = NULL;
    
    if((ext = X509_get_ext ( x->value, i )) == NULL ) {
      continue;
    }

    if((pki_ext = PKI_X509_EXTENSION_new()) == NULL ) {
      PKI_log_err ( "Memory Allocation");
      continue;
    }

    if( ext->object == NULL ) {
      PKI_X509_EXTENSION_free ( pki_ext );
      continue;
    }

    pki_ext->oid = PKI_OID_dup ( ext->object );
    pki_ext->critical = ext->critical;

    if((pki_ext->value = X509V3_EXT_d2i ( ext )) == NULL ) {
      PKI_log_debug( "Extension %d -- not parsable", i);
      PKI_X509_EXTENSION_free ( pki_ext );
      continue;
    }
  }

  return ret;
}
Beispiel #12
0
PKI_X509_EXTENSION_STACK *PKI_X509_EXTENSION_get_list ( void *x, 
						PKI_X509_DATA type ) {

	PKI_X509_EXTENSION_STACK *ret = NULL;

	int i = 0;
	int ext_count = 0;

	if (!x) return NULL;

	if ((ext_count = X509_get_ext_count (x)) <= 0 ) return NULL;

	if(( ret = PKI_STACK_X509_EXTENSION_new()) == NULL ) return NULL;

	for ( i=0; i < ext_count; i++ ) {
		PKI_X509_EXTENSION_VALUE *ext = NULL;
		PKI_X509_EXTENSION *pki_ext = NULL;
		
		if((ext = X509_get_ext ( x, i )) == NULL ) {
			continue;
		}

		if((pki_ext = PKI_X509_EXTENSION_new()) == NULL ) {
			PKI_log_err ( "Memory Allocation");
			continue;
		}

		pki_ext->oid = ext->object;
		pki_ext->critical = ext->critical;

		if((pki_ext->value = X509V3_EXT_d2i ( ext )) == NULL ) {
			PKI_log_debug( "Extension %d -- not parsable", i);
			PKI_X509_EXTENSION_free ( pki_ext );
			continue;
		}

		PKI_STACK_X509_EXTENSION_push ( ret, pki_ext );
	}

	return ret;
}
Beispiel #13
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;
};
Beispiel #14
0
static int
tlso_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in )
{
	tlso_session *s = (tlso_session *)sess;
	int i, ret = LDAP_LOCAL_ERROR;
	X509 *x;
	const char *name;
	char *ptr;
	int ntype = IS_DNS, nlen;
#ifdef LDAP_PF_INET6
	struct in6_addr addr;
#else
	struct in_addr addr;
#endif

	if( ldap_int_hostname &&
		( !name_in || !strcasecmp( name_in, "localhost" ) ) )
	{
		name = ldap_int_hostname;
	} else {
		name = name_in;
	}
	nlen = strlen(name);

	x = tlso_get_cert(s);
	if (!x) {
		Debug( LDAP_DEBUG_ANY,
			"TLS: unable to get peer certificate.\n",
			0, 0, 0 );
		/* If this was a fatal condition, things would have
		 * aborted long before now.
		 */
		return LDAP_SUCCESS;
	}

#ifdef LDAP_PF_INET6
	if (inet_pton(AF_INET6, name, &addr)) {
		ntype = IS_IP6;
	} else 
#endif
	if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
		if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
	}
	
	i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1);
	if (i >= 0) {
		X509_EXTENSION *ex;
		STACK_OF(GENERAL_NAME) *alt;

		ex = X509_get_ext(x, i);
		alt = X509V3_EXT_d2i(ex);
		if (alt) {
			int n, len2 = 0;
			char *domain = NULL;
			GENERAL_NAME *gn;

			if (ntype == IS_DNS) {
				domain = strchr(name, '.');
				if (domain) {
					len2 = nlen - (domain-name);
				}
			}
			n = sk_GENERAL_NAME_num(alt);
			for (i=0; i<n; i++) {
				char *sn;
				int sl;
				gn = sk_GENERAL_NAME_value(alt, i);
				if (gn->type == GEN_DNS) {
					if (ntype != IS_DNS) continue;

					sn = (char *) ASN1_STRING_data(gn->d.ia5);
					sl = ASN1_STRING_length(gn->d.ia5);

					/* ignore empty */
					if (sl == 0) continue;

					/* Is this an exact match? */
					if ((nlen == sl) && !strncasecmp(name, sn, nlen)) {
						break;
					}

					/* Is this a wildcard match? */
					if (domain && (sn[0] == '*') && (sn[1] == '.') &&
						(len2 == sl-1) && !strncasecmp(domain, &sn[1], len2))
					{
						break;
					}

				} else if (gn->type == GEN_IPADD) {
					if (ntype == IS_DNS) continue;

					sn = (char *) ASN1_STRING_data(gn->d.ia5);
					sl = ASN1_STRING_length(gn->d.ia5);

#ifdef LDAP_PF_INET6
					if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) {
						continue;
					} else
#endif
					if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) {
						continue;
					}
					if (!memcmp(sn, &addr, sl)) {
						break;
					}
				}
			}

			GENERAL_NAMES_free(alt);
			if (i < n) {	/* Found a match */
				ret = LDAP_SUCCESS;
			}
		}
	}

	if (ret != LDAP_SUCCESS) {
		X509_NAME *xn;
		X509_NAME_ENTRY *ne;
		ASN1_OBJECT *obj;
		ASN1_STRING *cn = NULL;
		int navas;

		/* find the last CN */
		obj = OBJ_nid2obj( NID_commonName );
		if ( !obj ) goto no_cn;	/* should never happen */

		xn = X509_get_subject_name(x);
		navas = X509_NAME_entry_count( xn );
		for ( i=navas-1; i>=0; i-- ) {
			ne = X509_NAME_get_entry( xn, i );
			if ( !OBJ_cmp( X509_NAME_ENTRY_get_object(ne), obj )) {
				cn = X509_NAME_ENTRY_get_data( ne );
				break;
			}
		}

		if( !cn )
		{
no_cn:
			Debug( LDAP_DEBUG_ANY,
				"TLS: unable to get common name from peer certificate.\n",
				0, 0, 0 );
			ret = LDAP_CONNECT_ERROR;
			if ( ld->ld_error ) {
				LDAP_FREE( ld->ld_error );
			}
			ld->ld_error = LDAP_STRDUP(
				_("TLS: unable to get CN from peer certificate"));

		} else if ( cn->length == nlen &&
			strncasecmp( name, (char *) cn->data, nlen ) == 0 ) {
			ret = LDAP_SUCCESS;

		} else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) {
			char *domain = strchr(name, '.');
			if( domain ) {
				int dlen;

				dlen = nlen - (domain-name);

				/* Is this a wildcard match? */
				if ((dlen == cn->length-1) &&
					!strncasecmp(domain, (char *) &cn->data[1], dlen)) {
					ret = LDAP_SUCCESS;
				}
			}
		}

		if( ret == LDAP_LOCAL_ERROR ) {
			Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
				"common name in certificate (%.*s).\n", 
				name, cn->length, cn->data );
			ret = LDAP_CONNECT_ERROR;
			if ( ld->ld_error ) {
				LDAP_FREE( ld->ld_error );
			}
			ld->ld_error = LDAP_STRDUP(
				_("TLS: hostname does not match CN in peer certificate"));
		}
	}
	X509_free(x);
	return ret;
}
Beispiel #15
0
static Str
ssl_check_cert_ident(X509 * x, char *hostname)
{
    int i;
    Str ret = NULL;
    int match_ident = FALSE;
    /*
     * All we need to do here is check that the CN matches.
     *
     * From RFC2818 3.1 Server Identity:
     * If a subjectAltName extension of type dNSName is present, that MUST
     * be used as the identity. Otherwise, the (most specific) Common Name
     * field in the Subject field of the certificate MUST be used. Although
     * the use of the Common Name is existing practice, it is deprecated and
     * Certification Authorities are encouraged to use the dNSName instead.
     */
    i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1);
    if (i >= 0) {
	X509_EXTENSION *ex;
	STACK_OF(GENERAL_NAME) * alt;

	ex = X509_get_ext(x, i);
	alt = X509V3_EXT_d2i(ex);
	if (alt) {
	    int n;
	    GENERAL_NAME *gn;
	    X509V3_EXT_METHOD *method;
	    Str seen_dnsname = NULL;

	    n = sk_GENERAL_NAME_num(alt);
	    for (i = 0; i < n; i++) {
		gn = sk_GENERAL_NAME_value(alt, i);
		if (gn->type == GEN_DNS) {
		    char *sn = ASN1_STRING_data(gn->d.ia5);
		    int sl = ASN1_STRING_length(gn->d.ia5);

		    if (!seen_dnsname)
			seen_dnsname = Strnew();
		    /* replace \0 to make full string visible to user */
		    if (sl != strlen(sn)) {
			int i;
			for (i = 0; i < sl; ++i) {
			    if (!sn[i])
				sn[i] = '!';
			}
		    }
		    Strcat_m_charp(seen_dnsname, sn, " ", NULL);
		    if (sl == strlen(sn) /* catch \0 in SAN */
			&& ssl_match_cert_ident(sn, sl, hostname))
			break;
		}
	    }
	    method = X509V3_EXT_get(ex);
	    sk_GENERAL_NAME_free(alt);
	    if (i < n)		/* Found a match */
		match_ident = TRUE;
	    else if (seen_dnsname)
		/* FIXME: gettextize? */
		ret = Sprintf("Bad cert ident from %s: dNSName=%s", hostname,
			      seen_dnsname->ptr);
	}
    }

    if (match_ident == FALSE && ret == NULL) {
	X509_NAME *xn;
	char buf[2048];
	int slen;

	xn = X509_get_subject_name(x);

	slen = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf));
	if ( slen == -1)
	    /* FIXME: gettextize? */
	    ret = Strnew_charp("Unable to get common name from peer cert");
	else if (slen != strlen(buf)
		|| !ssl_match_cert_ident(buf, strlen(buf), hostname)) {
	    /* replace \0 to make full string visible to user */
	    if (slen != strlen(buf)) {
		int i;
		for (i = 0; i < slen; ++i) {
		    if (!buf[i])
			buf[i] = '!';
		}
	    }
	    /* FIXME: gettextize? */
	    ret = Sprintf("Bad cert ident %s from %s", buf, hostname);
	}
	else
	    match_ident = TRUE;
    }
    return ret;
}
Beispiel #16
0
su_inline
int tls_post_connection_check(tport_t *self, tls_t *tls)
{
  X509 *cert;
  int extcount;
  int i, j, error;

  if (!tls) return -1;

  cert = SSL_get_peer_certificate(tls->con);
  if (!cert) {
    SU_DEBUG_7(("%s(%p): Peer did not provide X.509 Certificate.\n", 
				__func__, (void *) self));
    if (self->tp_accepted && tls->verify_incoming)
      return X509_V_ERR_CERT_UNTRUSTED;
    else if (!self->tp_accepted && tls->verify_outgoing)
      return X509_V_ERR_CERT_UNTRUSTED;
    else 
      return X509_V_OK;
  }

  tls->subjects = su_strlst_create(tls->home);
  if (!tls->subjects)
    return X509_V_ERR_OUT_OF_MEM;

  extcount = X509_get_ext_count(cert);

  /* Find matching subjectAltName.DNS */
  for (i = 0; i < extcount; i++) {
    X509_EXTENSION *ext;
    char const *name;
#if OPENSSL_VERSION_NUMBER >  0x10000000L
    const X509V3_EXT_METHOD *vp;
#else
    X509V3_EXT_METHOD *vp;
#endif
    STACK_OF(CONF_VALUE) *values;
    CONF_VALUE *value;
    void *d2i;

    ext = X509_get_ext(cert, i);
    name = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));

    if (strcmp(name, "subjectAltName") != 0)
      continue;

    vp = X509V3_EXT_get(ext); if (!vp) continue;
    d2i = X509V3_EXT_d2i(ext);
    values = vp->i2v(vp, d2i, NULL);

    for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
      value = sk_CONF_VALUE_value(values, j);
      if (strcmp(value->name, "DNS") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
      if (strcmp(value->name, "IP") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
      else if (strcmp(value->name, "URI") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
    }
  }

  {
    X509_NAME *subject;
    char name[256];

    subject = X509_get_subject_name(cert);

    if (subject) {
      if (X509_NAME_get_text_by_NID(subject, NID_commonName,
				    name, sizeof name) > 0) {
	usize_t k, N = su_strlst_len(tls->subjects);
	name[(sizeof name) - 1] = '\0';

	for (k = 0; k < N; k++)
	  if (su_casematch(su_strlst_item(tls->subjects, k), name) == 0)
	    break;

	if (k >= N)
	  su_strlst_dup_append(tls->subjects, name);
      }
    }
  }

  X509_free(cert);

  error = SSL_get_verify_result(tls->con);

  if (cert && error == X509_V_OK)
    tls->x509_verified = 1;

  if (tport_log->log_level >= 7) {
    int i, len = su_strlst_len(tls->subjects);
    for (i=0; i < len; i++)
      SU_DEBUG_7(("%s(%p): Peer Certificate Subject %i: %s\n", \
				  __func__, (void *)self, i, su_strlst_item(tls->subjects, i)));
    if (i == 0)
      SU_DEBUG_7(("%s(%p): Peer Certificate provided no usable subjects.\n",
				  __func__, (void *)self));
  }

  /* Verify incoming connections */
  if (self->tp_accepted) {
    if (!tls->verify_incoming)
      return X509_V_OK;

    if (!tls->x509_verified)
      return error;

    if (tls->verify_subj_in) {
      su_strlst_t const *subjects = self->tp_pri->pri_primary->tp_subjects;
      int i, items;

      items = subjects ? su_strlst_len(subjects) : 0;
      if (items == 0)
        return X509_V_OK;

      for (i=0; i < items; i++) {
	if (tport_subject_search(su_strlst_item(subjects, i), tls->subjects))
	  return X509_V_OK;
      }
      SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (incoming connection)\n", \
				  __func__, (void *)self));

      return X509_V_ERR_CERT_UNTRUSTED;
    }
  }
  /* Verify outgoing connections */
  else {
    char const *subject = self->tp_canon;
    if (!tls->verify_outgoing)
      return X509_V_OK;

    if (!tls->x509_verified || !subject)
      return error;

    if (tls->verify_subj_out) {
      if (tport_subject_search(subject, tls->subjects))
        return X509_V_OK; /* Subject match found in verified certificate chain */
      SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (%s)\n", \
				  __func__, (void *)self, subject));

      return X509_V_ERR_CERT_UNTRUSTED;
    }
  }

  return error;
}
Beispiel #17
0
int openssl_xext_totable(lua_State* L, X509_EXTENSION *x, int utf8)
{
  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);
        switch (general_name->type) {
        case GEN_OTHERNAME:
          {
          OTHERNAME *otherName = general_name->d.otherName;

          lua_newtable(L);
          openssl_push_asn1object(L, otherName->type_id);
          PUSH_ASN1_STRING(L, otherName->value->value.asn1_string, utf8);
          lua_settable(L, -3);
          lua_setfield(L, -2, "otherName");

          lua_pushstring(L, "otherName");
          lua_rawseti(L, -2, i+1);
          break;
          }
        case GEN_EMAIL:
          lua_newtable(L);
          PUSH_ASN1_STRING(L, general_name->d.rfc822Name, utf8);
          lua_pushstring(L, "rfc822Name");
          lua_settable(L, -3);

          lua_pushstring(L, "rfc822Name");
          lua_rawseti(L, -2, i+1);
          break;
        case GEN_DNS:
          lua_newtable(L);
          PUSH_ASN1_STRING(L, general_name->d.dNSName, utf8);
          lua_setfield(L, -2, "dNSName");
          lua_pushstring(L, "dNSName");
          lua_rawseti(L, -2, i+1);
          break;
        case GEN_X400:
          lua_newtable(L);
          openssl_push_asn1type(L, general_name->d.x400Address);
          lua_setfield(L, -2, "x400Address");
          lua_pushstring(L, "x400Address");
          lua_rawseti(L, -2, i+1);
          break;
        case GEN_DIRNAME:
          {
            X509_NAME* xn = general_name->d.directoryName;
            lua_newtable(L);
            PUSH_OBJECT(X509_NAME_dup(xn), "openssl.x509_name");
            lua_setfield(L, -2, "directoryName");
            lua_pushstring(L, "directoryName");
            lua_rawseti(L, -2, i+1);
          }
          break;
        case GEN_URI:
          lua_newtable(L);
          PUSH_ASN1_STRING(L, general_name->d.uniformResourceIdentifier, utf8);
          lua_setfield(L, -2, "uniformResourceIdentifier");
          lua_pushstring(L, "uniformResourceIdentifier");
          lua_rawseti(L, -2, i+1);
          break;
        case GEN_IPADD:
          lua_newtable(L);
          PUSH_ASN1_OCTET_STRING(L, general_name->d.iPAddress);
          lua_setfield(L, -2, "iPAddress");
          lua_pushstring(L, "iPAddress");
          lua_rawseti(L, -2, i+1);
          break;
        case GEN_EDIPARTY:
          lua_newtable(L);
          lua_newtable(L);
          PUSH_ASN1_STRING(L, general_name->d.ediPartyName->nameAssigner,utf8);
          lua_setfield(L, -2, "nameAssigner");
          PUSH_ASN1_STRING(L, general_name->d.ediPartyName->partyName,utf8);
          lua_setfield(L, -2, "partyName");
          lua_setfield(L, -2, "ediPartyName");

          lua_pushstring(L, "ediPartyName");
          lua_rawseti(L, -2, i+1);
          break;
        case GEN_RID:
          lua_newtable(L);
          openssl_push_asn1object(L, general_name->d.registeredID);
          lua_setfield(L, -2, "registeredID");
          lua_pushstring(L, "registeredID");
          lua_rawseti(L, -2, i+1);
          break;
        }
       }
      lua_settable(L, -3);
    }
  default:
    break;
  }
  return 1;
};
Beispiel #18
0
gboolean
tls_verify_certificate_name(X509 *cert, const gchar *host_name)
{
  gchar pattern_buf[256];
  gint ext_ndx;
  gboolean found = FALSE, result = FALSE;

  ext_ndx = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
  if (ext_ndx >= 0)
    {
      /* ok, there's a subjectAltName extension, check that */
      X509_EXTENSION *ext;
      STACK_OF(GENERAL_NAME) *alt_names;
      GENERAL_NAME *gen_name;

      ext = X509_get_ext(cert, ext_ndx);
      alt_names = X509V3_EXT_d2i(ext);
      if (alt_names)
        {
          gint num, i;

          num = sk_GENERAL_NAME_num(alt_names);

          for (i = 0; !result && i < num; i++)
            {
              gen_name = sk_GENERAL_NAME_value(alt_names, i);
              if (gen_name->type == GEN_DNS)
                {
                  guchar *dnsname = ASN1_STRING_data(gen_name->d.dNSName);
                  guint dnsname_len = ASN1_STRING_length(gen_name->d.dNSName);

                  if (dnsname_len > sizeof(pattern_buf) - 1)
                    {
                      found = TRUE;
                      result = FALSE;
                      break;
                    }

                  memcpy(pattern_buf, dnsname, dnsname_len);
                  pattern_buf[dnsname_len] = 0;
                  /* we have found a DNS name as alternative subject name */
                  found = TRUE;
                  result = tls_wildcard_match(host_name, pattern_buf);
                }
              else if (gen_name->type == GEN_IPADD)
                {
                  char *dotted_ip = inet_ntoa(*(struct in_addr *) gen_name->d.iPAddress->data);

                  g_strlcpy(pattern_buf, dotted_ip, sizeof(pattern_buf));
                  found = TRUE;
                  result = strcasecmp(host_name, pattern_buf) == 0;
                }
            }
          sk_GENERAL_NAME_free(alt_names);
        }
    }
  if (!found)
    {
      /* hmm. there was no subjectAltName (this is deprecated, but still
       * widely used), look up the Subject, most specific CN */
      X509_NAME *name;

      name = X509_get_subject_name(cert);
      if (X509_NAME_get_text_by_NID(name, NID_commonName, pattern_buf, sizeof(pattern_buf)) != -1)
        {
          result = tls_wildcard_match(host_name, pattern_buf);
        }
    }
  if (!result)
    {
      msg_error("Certificate subject does not match configured hostname",
                evt_tag_str("hostname", host_name),
                evt_tag_str("certificate", pattern_buf),
                NULL);
    }
  else
    {
      msg_verbose("Certificate subject matches configured hostname",
                evt_tag_str("hostname", host_name),
                evt_tag_str("certificate", pattern_buf),
                NULL);
    }

  return result;
}
Beispiel #19
0
gboolean
z_proxy_ssl_host_iface_check_name_method(ZProxyHostIface *s,
                                         const gchar *host_name,
                                         gchar *reason_buf, gsize reason_len)
{
  ZProxySslHostIface *self = Z_CAST(s, ZProxySslHostIface);
  gint ext_ndx;
  gboolean found = FALSE, result = FALSE;
  gchar pattern_buf[256];

  if (self->hostname_checked)
    return self->hostname_check_result;

  pattern_buf[0] = 0;
  ext_ndx = X509_get_ext_by_NID(self->server_cert, NID_subject_alt_name, -1);
  if (ext_ndx >= 0)
    {
      /* ok, there's a subjectAltName extension, check that */
      X509_EXTENSION *ext;
      STACK_OF(GENERAL_NAME) *alt_names;
      GENERAL_NAME *gen_name;

      ext = X509_get_ext(self->server_cert, ext_ndx);
      alt_names = X509V3_EXT_d2i(ext);
      if (alt_names)
        {
          gint num, i;

          num = sk_GENERAL_NAME_num(alt_names);

          for (i = 0; i < num; i++)
            {
              gen_name = sk_GENERAL_NAME_value(alt_names, i);
              if (gen_name->type == GEN_DNS)
                {
                  guchar *dnsname = ASN1_STRING_data(gen_name->d.dNSName);
                  guint dnsname_len = ASN1_STRING_length(gen_name->d.dNSName);

                  if (dnsname_len > sizeof(pattern_buf) - 1)
                    {
                      found = TRUE;
                      result = FALSE;
                      break;
                    }

                  memcpy(pattern_buf, dnsname, dnsname_len);
                  pattern_buf[dnsname_len] = 0;
                  /* we have found a DNS name as alternative subject name */
                  found = TRUE;
                  result = z_proxy_ssl_host_iface_check_wildcard(s->owner, host_name, pattern_buf);
                  break;
                }
              else if (gen_name->type == GEN_IPADD)
                {
                  z_inet_ntoa(pattern_buf, sizeof(pattern_buf), *(struct in_addr *) gen_name->d.iPAddress->data);

                  found = TRUE;
                  result = strcmp(host_name, pattern_buf) == 0;
                  break;
                }
            }
          sk_GENERAL_NAME_free(alt_names);
        }
    }

  if (!found)
    {
      /* hmm. there was no subjectAltName (this is deprecated, but still
       * widely used), look up the Subject, most specific CN */
      X509_NAME *name;

      name = X509_get_subject_name(self->server_cert);
      if (X509_NAME_get_text_by_NID(name, NID_commonName, pattern_buf, sizeof(pattern_buf)) != -1)
        {
          result = z_proxy_ssl_host_iface_check_wildcard(s->owner, host_name, pattern_buf);
        }
    }

  if (!result && reason_buf)
    {
      g_snprintf(reason_buf, reason_len, "Certificate does not belong to target host (certificate: %s, host %s)",
                 pattern_buf, host_name);
    }
  self->hostname_checked = TRUE;
  self->hostname_check_result = result;
  return result;

}
Beispiel #20
0
/** Extract attributes from an X509 certificate
 *
 * @param cursor	to copy attributes to.
 * @param ctx		to allocate attributes in.
 * @param session	current TLS session.
 * @param cert		to validate.
 * @param depth		the certificate is in the certificate chain (0 == leaf).
 * @return
 *	- 0 on success.
 *	- < 0 on failure.
 */
int tls_session_pairs_from_x509_cert(fr_cursor_t *cursor, TALLOC_CTX *ctx,
				     tls_session_t *session, X509 *cert, int depth)
{
	char		buffer[1024];
	char		attribute[256];
	char		**identity;
	int		attr_index, loc;

#if OPENSSL_VERSION_NUMBER >= 0x10100000L
	STACK_OF(X509_EXTENSION) const *ext_list = NULL;
#else
	STACK_OF(X509_EXTENSION) *ext_list = NULL;
#endif

	ASN1_INTEGER	*sn = NULL;
	ASN1_TIME	*asn_time = NULL;

	VALUE_PAIR	*vp = NULL;

	REQUEST		*request;

#define CERT_ATTR_ADD(_attr, _attr_index, _value) tls_session_cert_attr_add(ctx, request, cursor, _attr, _attr_index, _value)

	attr_index = depth;
	if (attr_index > 1) attr_index = 1;

	request = (REQUEST *)SSL_get_ex_data(session->ssl, FR_TLS_EX_INDEX_REQUEST);
	rad_assert(request != NULL);

	identity = (char **)SSL_get_ex_data(session->ssl, FR_TLS_EX_INDEX_IDENTITY);

	if (RDEBUG_ENABLED3) {
		buffer[0] = '\0';
		X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
		buffer[sizeof(buffer) - 1] = '\0';
		RDEBUG3("Creating attributes for \"%s\":", buffer[0] ? buffer : "Cert missing subject OID");
	}

	/*
	 *	Get the Serial Number
	 */
	sn = X509_get_serialNumber(cert);
	if (sn && ((size_t) sn->length < (sizeof(buffer) / 2))) {
		char *p = buffer;
		int i;

		for (i = 0; i < sn->length; i++) {
			sprintf(p, "%02x", (unsigned int)sn->data[i]);
			p += 2;
		}

		CERT_ATTR_ADD(IDX_SERIAL, attr_index, buffer);
	}

	/*
	 *	Get the Expiration Date
	 */
	buffer[0] = '\0';
	asn_time = X509_get_notAfter(cert);
	if (identity && asn_time && (asn_time->length < (int)sizeof(buffer))) {
		time_t expires;

		/*
		 *	Add expiration as a time since the epoch
		 */
		if (tls_utils_asn1time_to_epoch(&expires, asn_time) < 0) {
			RPWDEBUG("Failed parsing certificate expiry time");
		} else {
			vp = CERT_ATTR_ADD(IDX_EXPIRATION, attr_index, NULL);
			vp->vp_date = expires;
		}
	}

	/*
	 *	Get the Subject & Issuer
	 */
	buffer[0] = '\0';
	X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
	buffer[sizeof(buffer) - 1] = '\0';
	if (identity && buffer[0]) {
		CERT_ATTR_ADD(IDX_SUBJECT, attr_index, buffer);

		/*
		 *	Get the Common Name, if there is a subject.
		 */
		X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
					  NID_commonName, buffer, sizeof(buffer));
		buffer[sizeof(buffer) - 1] = '\0';

		if (buffer[0]) {
			CERT_ATTR_ADD(IDX_COMMON_NAME, attr_index, buffer);
		}
	}

	X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer));
	buffer[sizeof(buffer) - 1] = '\0';
	if (identity && buffer[0]) {
		CERT_ATTR_ADD(IDX_ISSUER, attr_index, buffer);
	}

	/*
	 *	Get the RFC822 Subject Alternative Name
	 */
	loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, 0);
	if (loc >= 0) {
		X509_EXTENSION	*ext = NULL;
		GENERAL_NAMES	*names = NULL;
		int		i;

		ext = X509_get_ext(cert, loc);
		if (ext && (names = X509V3_EXT_d2i(ext))) {
			for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
				GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);

				switch (name->type) {
#ifdef GEN_EMAIL
				case GEN_EMAIL: {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
					char const *rfc822Name = (char const *)ASN1_STRING_get0_data(name->d.rfc822Name);
#else
					char *rfc822Name = (char *)ASN1_STRING_data(name->d.rfc822Name);
#endif

					CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_EMAIL, attr_index, rfc822Name);
					break;
				}
#endif	/* GEN_EMAIL */
#ifdef GEN_DNS
				case GEN_DNS: {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
					char const *dNSName = (char const *)ASN1_STRING_get0_data(name->d.dNSName);
#else
					char *dNSName = (char *)ASN1_STRING_data(name->d.dNSName);
#endif
					CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_DNS, attr_index, dNSName);
					break;
				}
#endif	/* GEN_DNS */
#ifdef GEN_OTHERNAME
				case GEN_OTHERNAME:
					/* look for a MS UPN */
					if (NID_ms_upn != OBJ_obj2nid(name->d.otherName->type_id)) break;

					/* we've got a UPN - Must be ASN1-encoded UTF8 string */
					if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
						CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_UPN, attr_index,
								  (char *)name->d.otherName->value->value.utf8string);
						break;
					}

					RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)");
					break;
#endif	/* GEN_OTHERNAME */
				default:
					/* XXX TODO handle other SAN types */
					break;
				}
			}
		}
		if (names != NULL) GENERAL_NAMES_free(names);
	}

	/*
	 *	Only add extensions for the actual client certificate
	 */
	if (attr_index == 0) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
		ext_list = X509_get0_extensions(cert);
#else
		ext_list = cert->cert_info->extensions;
#endif

		/*
		 *	Grab the X509 extensions, and create attributes out of them.
		 *	For laziness, we re-use the OpenSSL names
		 */
		if (sk_X509_EXTENSION_num(ext_list) > 0) {
			int i, len;
			char *p;
			BIO *out;

			out = BIO_new(BIO_s_mem());
			strlcpy(attribute, "TLS-Client-Cert-", sizeof(attribute));

			for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
				char			value[1024];
				ASN1_OBJECT		*obj;
				X509_EXTENSION		*ext;
				fr_dict_attr_t const	*da;

				ext = sk_X509_EXTENSION_value(ext_list, i);

				obj = X509_EXTENSION_get_object(ext);
				i2a_ASN1_OBJECT(out, obj);

				len = BIO_read(out, attribute + 16 , sizeof(attribute) - 16 - 1);
				if (len <= 0) continue;

				attribute[16 + len] = '\0';

				for (p = attribute + 16; *p != '\0'; p++) if (*p == ' ') *p = '-';

				X509V3_EXT_print(out, ext, 0, 0);
				len = BIO_read(out, value , sizeof(value) - 1);
				if (len <= 0) continue;

				value[len] = '\0';

				da = fr_dict_attr_by_name(dict_freeradius, attribute);
				if (!da) {
					RWDEBUG3("Skipping attribute %s: "
						 "Add dictionary definition if you want to access it", attribute);
					continue;
				}

				MEM(vp = fr_pair_afrom_da(request, da));
				if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
					RPWDEBUG3("Skipping: %s += '%s'", attribute, value);
					talloc_free(vp);
					continue;
				}

				fr_cursor_append(cursor, vp);
			}
			BIO_free_all(out);
		}
	}

	return 0;
}
Beispiel #21
0
    int
tls_client_start( SNET *sn, char *host, int authlevel )
{
    X509            	*peer;
    char             	buf[ 1024 ];
    struct timeval  	tv;
    char            	*line;
    int             	ntype;
    struct in_addr  	addr;
    int 		alt_ext;

    if ( inet_aton( host, &addr )) {
	ntype = IS_IP4;
    } else {
	/* Assume the host argument is a DNS name */
	ntype = IS_DNS;
    }

    if( snet_writef( sn, "STARTTLS\r\n" ) < 0 ) {
	perror( "snet_writef" );
	return( -1 );
    }
    if ( verbose ) printf( ">>> STARTTLS\n" );

    /* Check to see if command succeeded */
    tv = timeout;      
    if (( line = snet_getline_multi( sn, logger, &tv )) == NULL ) {
	perror( "snet_getline_multi" );
	return( -1 );
    }
    if ( *line != '2' ) {
	fprintf( stderr, "%s\n",  line );
	return( -1 );
    }

    /*
     * Begin TLS
     */
    /* This is where the TLS start */
    /* At this point the server is also staring TLS */

    if ( snet_starttls( sn, ctx, 0 ) != 1 ) {
	fprintf( stderr, "snet_starttls: %s\n",
		ERR_error_string( ERR_get_error(), NULL ) );
	return( -1 );
    }
    if (( peer = SSL_get_peer_certificate( sn->sn_ssl ))
	    == NULL ) {
	fprintf( stderr, "no certificate\n" );
	return( -1 );
    }

    /* This code gratiously borrowed from openldap-2.2.17,
     * it allows the use of aliases in the certificate.
     */
    alt_ext = X509_get_ext_by_NID( peer, NID_subject_alt_name, -1 );

    if ( alt_ext >= 0 ) {
	X509_EXTENSION			*ex;
	STACK_OF( GENERAL_NAME )		*alt;

	ex = X509_get_ext( peer, alt_ext );
	alt = X509V3_EXT_d2i( ex );

	if ( alt ) {
	    int			i, n, len1 = 0, len2 = 0;
	    char	 	*domain = NULL;
	    GENERAL_NAME	*gn;

	    if ( ntype == IS_DNS ) {
		len1 = strlen( host );
		domain = strchr( host, '.' );
		if ( domain ) {
		    len2 = len1 - ( domain-host );
		}
	    }

	    n = sk_GENERAL_NAME_num( alt );
	    for ( i = 0; i < n; i++ ) {
		char	*sn;
		int	 sl;

		gn = sk_GENERAL_NAME_value( alt, i );
		if ( gn->type == GEN_DNS ) {
		    if ( ntype != IS_DNS ) {
			continue;
		    };
		    sn = (char *) ASN1_STRING_data( gn->d.ia5 );
		    sl = ASN1_STRING_length( gn->d.ia5 );

		    /* ignore empty */
		    if ( sl == 0 ) {
			continue;
		    }

		    /* Is this an exact match? */
		    if (( len1 == sl ) && !strncasecmp( host, sn, len1 )) {
			/* Found! */
			if ( verbose ) {
			    printf( ">>> Certificate accepted: "
				"subjectAltName exact match %s\n", sn );
			}
			break;
		    }

		    /* Is this a wildcard match? */
		    if ( domain && ( sn[0] == '*' ) && ( sn[1] == '.' ) &&
			    ( len2 == sl-1 ) && 
			    strncasecmp( domain, &sn[1], len2 )) {
			/* Found! */
			if ( verbose ) {
			    printf( ">>> Certificate accepted: subjectAltName "
			    "wildcard %s host %s\n", sn, host );
			}
			break;
		    }

		} else if ( gn->type == GEN_IPADD ) {
		    if ( ntype == IS_DNS ) {
			continue;
		    }

		    sn = (char *) ASN1_STRING_data( gn->d.ia5 );
		    sl = ASN1_STRING_length( gn->d.ia5 );

		    if ( ntype == IS_IP4 && sl != sizeof( struct in_addr )) {
			continue;
		    }

		    if ( !memcmp( sn, &addr, sl )) {
			/* Found! */
			if ( verbose ) {
			    printf( ">>> Certificate accepted: subjectAltName "
			    "address %s\n", host );
			}
			break;
		    }

		}
	    }

	    GENERAL_NAMES_free( alt );

	    if ( i < n ) {
		/* Found a match */
		X509_free( peer );
		return 0;
	    }
	}
    }

    X509_NAME_get_text_by_NID( X509_get_subject_name( peer ),
	    NID_commonName, buf, sizeof( buf ));
    X509_free( peer );

    if ( strcmp( buf, host )) {
	fprintf( stderr, "Server's name doesn't match supplied hostname\n"
	    "%s != %s\n", buf, host );
	return( -1 );
    }

    return( 0 );
}
Beispiel #22
0
/**
  Determines if the specified EKU represented in ASN1 form is present
  in a given certificate.

  @param[in]  Cert                  The certificate to check.

  @param[in]  Asn1ToFind            The EKU to look for.

  @retval EFI_SUCCESS               We successfully identified the signing type.
  @retval EFI_INVALID_PARAMETER     A parameter was invalid.
  @retval EFI_NOT_FOUND             One or more EKU's were not found in the signature.

**/
EFI_STATUS
IsEkuInCertificate (
  IN CONST X509  *Cert,
  IN ASN1_OBJECT *Asn1ToFind
  )
{
  EFI_STATUS          Status;
  X509                *ClonedCert;
  X509_EXTENSION      *Extension;
  EXTENDED_KEY_USAGE  *Eku;
  INT32               ExtensionIndex;
  INTN                NumExtensions;
  ASN1_OBJECT         *Asn1InCert;
  INTN                Index;

  Status            = EFI_NOT_FOUND;
  ClonedCert        = NULL;
  Extension         = NULL;
  Eku               = NULL;
  ExtensionIndex    = -1;
  NumExtensions     = 0;
  Asn1InCert        = NULL;

  if (Cert == NULL || Asn1ToFind == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto Exit;
  }

  //
  // Clone the certificate.  This is required because the Extension API's
  // only work once per instance of an X509 object.
  //
  ClonedCert = X509_dup ((X509*)Cert);
  if (ClonedCert == NULL) {
    //
    // Fail to duplicate cert.
    //
    Status = EFI_INVALID_PARAMETER;
    goto Exit;
  }

  //
  // Look for the extended key usage.
  //
  ExtensionIndex = X509_get_ext_by_NID (ClonedCert, NID_ext_key_usage, -1);

  if (ExtensionIndex < 0) {
    //
    // Fail to find 'NID_ext_key_usage' in Cert.
    //
    goto Exit;
  }

  Extension = X509_get_ext (ClonedCert, ExtensionIndex);
  if (Extension == NULL) {
    //
    // Fail to get Extension form cert.
    //
    goto Exit;
  }

  Eku = (EXTENDED_KEY_USAGE*)X509V3_EXT_d2i (Extension);
  if (Eku == NULL) {
    //
    // Fail to get Eku from extension.
    //
    goto Exit;
  }

  NumExtensions = sk_ASN1_OBJECT_num (Eku);

  //
  // Now loop through the extensions, looking for the specified Eku.
  //
  for (Index = 0; Index < NumExtensions; Index++) {
    Asn1InCert = sk_ASN1_OBJECT_value (Eku, (INT32)Index);
    if (Asn1InCert == NULL) {
      //
      // Fail to get ASN object from Eku.
      //
      goto Exit;
    }

    if (Asn1InCert->length == Asn1ToFind->length &&
        CompareMem (Asn1InCert->data, Asn1ToFind->data, Asn1InCert->length) == 0) {
      //
      // Found Eku in certificate.
      //
      Status = EFI_SUCCESS;
      goto Exit;
    }
  }

Exit:

  //
  // Release Resources
  //
  if (ClonedCert) {
    X509_free (ClonedCert);
  }

  if (Eku) {
    sk_ASN1_OBJECT_pop_free (Eku, ASN1_OBJECT_free);
  }

  return Status;
}
Beispiel #23
0
/**
 * Retrieve the extensions from the certificate.
 */
int meth_extensions(lua_State* L)
{
  int j;
  int i = -1;
  int n_general_names;
  OTHERNAME *otherName;
  X509_EXTENSION *extension;
  GENERAL_NAME *general_name;
  STACK_OF(GENERAL_NAME) *values;
  X509 *peer = lsec_checkx509(L, 1);

  /* Return (ret) */
  lua_newtable(L);

  while ((i = X509_get_ext_by_NID(peer, NID_subject_alt_name, i)) != -1) {
    extension = X509_get_ext(peer, i);
    if (extension == NULL)
      break;
    values = X509V3_EXT_d2i(extension);
    if (values == NULL)
      break;

    /* Push ret[oid] */
    push_asn1_objname(L, extension->object, 1);
    push_subtable(L, -2);

    /* Set ret[oid].name = name */
    push_asn1_objname(L, extension->object, 0);
    lua_setfield(L, -2, "name");

    n_general_names = sk_GENERAL_NAME_num(values);
    for (j = 0; j < n_general_names; j++) {
      general_name = sk_GENERAL_NAME_value(values, j);
      switch (general_name->type) {
      case GEN_OTHERNAME:
        otherName = general_name->d.otherName;
        push_asn1_objname(L, otherName->type_id, 1);
        if (push_subtable(L, -2)) {
          push_asn1_objname(L, otherName->type_id, 0);
          lua_setfield(L, -2, "name");
        }
        push_asn1_string(L, otherName->value->value.asn1_string);
        lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
        lua_pop(L, 1);
        break;
      case GEN_DNS:
        lua_pushstring(L, "dNSName");
	push_subtable(L, -2);
        push_asn1_string(L, general_name->d.dNSName);
        lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
        lua_pop(L, 1);
        break;
      case GEN_EMAIL:
        lua_pushstring(L, "rfc822Name");
        push_subtable(L, -2);
        push_asn1_string(L, general_name->d.rfc822Name);
        lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
        lua_pop(L, 1);
        break;
      case GEN_URI:
        lua_pushstring(L, "uniformResourceIdentifier");
        push_subtable(L, -2);
        push_asn1_string(L, general_name->d.uniformResourceIdentifier);
        lua_rawseti(L, -2, lua_rawlen(L, -2)+1);
        lua_pop(L, 1);
        break;
      case GEN_IPADD:
        lua_pushstring(L, "iPAddress");
        push_subtable(L, -2);
        push_asn1_string(L, general_name->d.iPAddress);
        lua_rawseti(L, -2, lua_rawlen(L, -2)+1);
        lua_pop(L, 1);
        break;
      case GEN_X400:
        /* x400Address   */
        /* not supported */
        break;
      case GEN_DIRNAME:
        /* directoryName */
        /* not supported */
        break;
      case GEN_EDIPARTY:
        /* ediPartyName */
        /* not supported */
        break;
      case GEN_RID:
        /* registeredID  */
        /* not supported */
        break;
      }
    }
    lua_pop(L, 1); /* ret[oid] */
    i++;           /* Next extension */
  }
  return 1;
}
Beispiel #24
0
static int execute_cert_test(CT_TEST_FIXTURE fixture)
{
    int test_failed = 0;
    X509 *cert = NULL, *issuer = NULL;
    STACK_OF(SCT) *scts = NULL;
    SCT *sct = NULL;
    char expected_sct_text[CT_TEST_MAX_FILE_SIZE];
    int sct_text_len = 0;
    unsigned char *tls_sct = NULL;
    size_t tls_sct_len = 0;
    CT_POLICY_EVAL_CTX *ct_policy_ctx = CT_POLICY_EVAL_CTX_new();

    if (fixture.sct_text_file_path != NULL) {
        sct_text_len = read_text_file(
            fixture.sct_text_file_path,
            expected_sct_text,
            CT_TEST_MAX_FILE_SIZE - 1);

        if (sct_text_len < 0) {
            test_failed = 1;
            fprintf(stderr, "Test data file not found: %s\n",
                fixture.sct_text_file_path);
            goto end;
        }

        expected_sct_text[sct_text_len] = '\0';
    }

    CT_POLICY_EVAL_CTX_set0_log_store(ct_policy_ctx, fixture.ctlog_store);

    if (fixture.certificate_file_path != NULL) {
        int sct_extension_index;
        X509_EXTENSION *sct_extension = NULL;
        cert = load_pem_cert(fixture.certificate_file_path);

        if (cert == NULL) {
            test_failed = 1;
            fprintf(stderr, "Unable to load certificate: %s\n",
                fixture.certificate_file_path);
            goto end;
        }

        CT_POLICY_EVAL_CTX_set0_cert(ct_policy_ctx, cert);

        if (fixture.issuer_file_path != NULL) {
            issuer = load_pem_cert(fixture.issuer_file_path);

            if (issuer == NULL) {
                test_failed = 1;
                fprintf(stderr, "Unable to load issuer certificate: %s\n",
                        fixture.issuer_file_path);
                goto end;
            }

            CT_POLICY_EVAL_CTX_set0_issuer(ct_policy_ctx, issuer);
        }

        sct_extension_index =
                X509_get_ext_by_NID(cert, NID_ct_precert_scts, -1);
        sct_extension = X509_get_ext(cert, sct_extension_index);
        if (fixture.expected_sct_count > 0) {
            if (sct_extension == NULL) {
                test_failed = 1;
                fprintf(stderr, "SCT extension not found in: %s\n",
                    fixture.certificate_file_path);
                goto end;
            }

            if (fixture.sct_text_file_path) {
                test_failed = compare_extension_printout(sct_extension,
                                                    expected_sct_text);
                if (test_failed != 0)
                    goto end;
            }

            if (fixture.test_validity) {
                int are_scts_validated = 0;
                scts = X509V3_EXT_d2i(sct_extension);
                SCT_LIST_set_source(scts, SCT_SOURCE_X509V3_EXTENSION);

                are_scts_validated = SCT_LIST_validate(scts, ct_policy_ctx);
                if (are_scts_validated < 0) {
                    fprintf(stderr, "Error verifying SCTs\n");
                    test_failed = 1;
                } else if (!are_scts_validated) {
                    int invalid_sct_count = 0;
                    int valid_sct_count = 0;
                    int i;

                    for (i = 0; i < sk_SCT_num(scts); ++i) {
                        SCT *sct_i = sk_SCT_value(scts, i);
                        switch (SCT_get_validation_status(sct_i)) {
                        case SCT_VALIDATION_STATUS_VALID:
                            ++valid_sct_count;
                            break;
                        case SCT_VALIDATION_STATUS_INVALID:
                            ++invalid_sct_count;
                            break;
                        default:
                            /* Ignore other validation statuses. */
                            break;
                        }
                    }

                    if (valid_sct_count != fixture.expected_sct_count) {
                        int unverified_sct_count = sk_SCT_num(scts) -
                                invalid_sct_count - valid_sct_count;

                        fprintf(stderr,
                                "%d SCTs failed verification\n"
                                "%d SCTs passed verification (%d expected)\n"
                                "%d SCTs were unverified\n",
                                invalid_sct_count,
                                valid_sct_count,
                                fixture.expected_sct_count,
                                unverified_sct_count);
                    }
                    test_failed = 1;
                }

                if (test_failed != 0)
                    goto end;
            }
        } else if (sct_extension != NULL) {
            test_failed = 1;
            fprintf(stderr,
                    "Expected no SCTs, but found SCT extension in: %s\n",
                    fixture.certificate_file_path);
            goto end;
        }
    }

    if (fixture.tls_sct != NULL) {
        const unsigned char *p = fixture.tls_sct;
        if (o2i_SCT(&sct, &p, fixture.tls_sct_len) == NULL) {
            test_failed = 1;
            fprintf(stderr, "Failed to decode SCT from TLS format\n");
            goto end;
        }

        if (fixture.sct_text_file_path) {
            test_failed = compare_sct_printout(sct, expected_sct_text);
            if (test_failed != 0)
                goto end;
        }

        tls_sct_len = i2o_SCT(sct, &tls_sct);
        if (tls_sct_len != fixture.tls_sct_len ||
            memcmp(fixture.tls_sct, tls_sct, tls_sct_len) != 0) {
            test_failed = 1;
            fprintf(stderr, "Failed to encode SCT into TLS format correctly\n");
            goto end;
        }

        if (fixture.test_validity && cert != NULL) {
            int is_sct_validated = SCT_validate(sct, ct_policy_ctx);
            if (is_sct_validated < 0) {
                test_failed = 1;
                fprintf(stderr, "Error validating SCT\n");
                goto end;
            } else if (!is_sct_validated) {
                test_failed = 1;
                fprintf(stderr, "SCT failed verification\n");
                goto end;
            }
        }
    }

end:
    X509_free(cert);
    X509_free(issuer);
    SCT_LIST_free(scts);
    SCT_free(sct);
    CT_POLICY_EVAL_CTX_free(ct_policy_ctx);
    OPENSSL_free(tls_sct);
    return test_failed;
}
Beispiel #25
0
/**
 * Returns type of proxy certificate.
 * Valid values are:
 *	  NONE
 *	  CA
 *	  EEC
 *	  GT2_PROXY
 *	  RFC_PROXY
 *	  GT2_LIMITED_PROXY
 *	  RFC_LIMITED_PROXY
 *	  GT3_PROXY
 *	  GT3_LIMITED_PROXY
 */
proxy_type_t verify_type_of_proxy(X509 * cert) {
#ifdef __func__
    const char *logstr=__func__;
#else
    const char *logstr="verify_type_of_proxy";
#endif
    proxy_type_t pt = NONE;
    char * cert_subjectdn = NULL;
    char * cert_issuerdn = NULL;
    char * tail_str = NULL;
    size_t len_subject_dn;
    size_t len_issuer_dn;

    X509_EXTENSION *                    pci_ext = NULL;
    PROXYCERTINFO *                     pci = NULL;
    PROXYPOLICY *                       policy = NULL;
    ASN1_OBJECT *                       policy_lang = NULL;
    int                                 policy_nid;
    int                                 myindex = -1;

    int  i;
    char s[EXT_TEXT_LEN];

    X509_EXTENSION *ex;

    /* Is it a CA certificate */
    if (verify_x509IsCA(cert)) {
        /* verify_log (L_DEBUG, "%s: Detected CA certificate", logstr); */
        pt = CA;
        goto finalize;
    }

    /* Check by OID */
    for (i = 0; i < X509_get_ext_count(cert); ++i) {
        ex = X509_get_ext(cert, i);

        if (X509_EXTENSION_get_object(ex)) {
            OBJ_obj2txt(s, EXT_TEXT_LEN, X509_EXTENSION_get_object(ex), 1);

            if (strcmp(s, OID_RFC_PROXY) == 0) {
                pt = RFC_PROXY;

                /* Find index of OID_RFC_PROXY */
                if((myindex = X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_RFC_PROXY), -1)) != -1  &&
                    (pci_ext = X509_get_ext(cert,myindex)) && X509_EXTENSION_get_critical(pci_ext)) {
                    if((pci = X509V3_EXT_d2i(pci_ext)) == NULL) {
                        verify_error(logstr, "Can't convert DER encoded PROXYCERTINFO extension to internal form");
                        goto failure;
                    }

                    /* Pull a certificate policy from the extension, note:
		     * pci!=NULL since we've checked that */
                    if( (policy = pci->policy) == NULL) {
                        verify_error(logstr, "Can't get policy from PROXYCERTINFO extension");
                        goto failure;
                    }

                    /* Get policy language */
                    if( (policy_lang = policy->policy_language) == NULL) {
                        verify_error(logstr, "Can't get policy language from PROXYCERTINFO extension");
                        goto failure;
                    }

                    /* Lang to NID, lang's NID holds RFC Proxy type, like limited. Impersonation is the default */
                    policy_nid = OBJ_obj2nid(policy_lang);

                    if(policy_nid == OBJ_txt2nid(IMPERSONATION_PROXY_OID)) {
                        pt = RFC_PROXY;
                    } else if(policy_nid == OBJ_txt2nid(INDEPENDENT_PROXY_OID)) {
                        pt = RFC_PROXY;
                    } else if(policy_nid == OBJ_txt2nid(LIMITED_PROXY_OID)) {
                        pt = RFC_LIMITED_PROXY;
                    } else {
                        /* RFC_RESTRICTED_PROXY */
                        pt = RFC_PROXY;
                    }

                    if(X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_RFC_PROXY), myindex) != -1) {
                        verify_error(logstr, "Found more than one PCI extension");
                        goto failure;
                    }
                }
                goto finalize;
            }
            if (strcmp(s, OID_GLOBUS_PROXY_V3) == 0) {
                pt = GT3_PROXY;

                /* Find index of OID_GT3_PROXY - Don't make it search for critical extentions... VOMS doesn't set those. */
                if((myindex = X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_GLOBUS_PROXY_V3), -1)) != -1  &&
                    (pci_ext = X509_get_ext(cert,myindex))) {
                    if((pci = X509V3_EXT_d2i(pci_ext)) == NULL) {
                        verify_error(logstr, "Can't convert DER encoded PROXYCERTINFO extension to internal form");
                        goto failure;
                    }

                    /* Pull a certificate policy from the extension. Note: pci
		     * != NULL since we've checked that */
                    if( (policy = pci->policy) == NULL) {
                        verify_error(logstr, "Can't get policy from PROXYCERTINFO extension");
                        goto failure;
                    }

                    /* Get policy language */
                    if( (policy_lang = policy->policy_language) == NULL) {
                        verify_error(logstr, "Can't get policy language from PROXYCERTINFO extension");
                        goto failure;
                    }

                    /* Lang to NID, lang's NID holds RFC Proxy type, like limited. Impersonation is the default */
                    policy_nid = OBJ_obj2nid(policy_lang);

                    if(policy_nid == OBJ_txt2nid(IMPERSONATION_PROXY_OID)) {
                        pt = GT3_PROXY;
                    } else if(policy_nid == OBJ_txt2nid(INDEPENDENT_PROXY_OID)) {
                        pt = GT3_PROXY;
                    } else if(policy_nid == OBJ_txt2nid(LIMITED_PROXY_OID)) {
                        pt = GT3_LIMITED_PROXY;
                    } else {
                        /* GT3_RESTRICTED_PROXY */
                        pt = GT3_PROXY;
                    }

                    if(X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_GLOBUS_PROXY_V3), myindex) != -1) {
                        verify_error(logstr, "Found more than one PCI extension");
                        goto failure;
                    }
                }

                goto finalize;
            }
            if (strcmp(s, OID_GLOBUS_PROXY_V2) == 0) {
                pt = GT3_PROXY;

                /* Check for GT2_PROXY tail */
                if (cert_subjectdn
                    && (strlen(cert_subjectdn) > strlen("/cn=proxy"))
                    && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=proxy")])
                    && (strcasecmp(tail_str, "/cn=proxy") == 0)
                   ) {
                    /* verify_log (L_DEBUG, "%s: Detected GT2 proxy certificate", logstr); */

                    pt = GT2_PROXY;
                    goto finalize;
                }

                /* Check for GT2_LIMITED_PROXY tail */
                if (cert_subjectdn
                    && (strlen(cert_subjectdn) > strlen("/cn=limited proxy"))
                    && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=limited proxy")])
                    && (strcasecmp(tail_str, "/cn=limited proxy") == 0)
                   ) {
                    /* verify_log (L_DEBUG, "%s: Detected GT2 limited proxy certificate", logstr); */

                    pt = GT2_LIMITED_PROXY;
                    goto finalize;
                }

                verify_error(logstr, "Detected the Globus GT2 OID in the certificate, "
                                "but seems to have a malformed Subject DN: \"%s\"", cert_subjectdn);
                goto failure;
            }
        }
    }

    /* Options left: GT2_PROXY, GT2_LIMITED_PROXY, EEC */
    /* Extract Subject DN - Needs free */
    if (!(cert_subjectdn = X509_NAME_oneline (X509_get_subject_name (cert), NULL, 0))) {
        verify_error (logstr, "Error in %s: Couldn't get the subject DN from the certificate.", logstr);
        goto failure;
    }
    if (!(cert_issuerdn = X509_NAME_oneline (X509_get_issuer_name (cert), NULL, 0))) {
        verify_error (logstr, "Error in %s: Couldn't get the issuer DN from the certificate.", logstr);
        goto failure;
    }

    /* Check length of the DNs */
    len_subject_dn = strlen(cert_subjectdn);
    len_issuer_dn  = strlen(cert_issuerdn);


    /* Lower case the Subject DN */
    /* for (j = 0; j < strlen(cert_subjectdn); j++) { cert_subjectdn[j] = tolower(cert_subjectdn[j]); } */

    /* Proxies always has a longer subject_dn then a issuer_dn and
     * the issuer_dn is a substring of the subject_dn
     */
    if (   (len_issuer_dn < len_subject_dn)
        && (strncmp(cert_subjectdn, cert_issuerdn, len_issuer_dn) == 0)
       ) {
        /* Check for GT2_PROXY tail */
        if (cert_subjectdn
            && (strlen(cert_subjectdn) > strlen("/cn=proxy"))
            && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=proxy")])
            && (strcasecmp(tail_str, "/cn=proxy") == 0)
           ) {
            /* verify_log (L_DEBUG, "%s: Detected GT2 proxy certificate", logstr); */
            pt = GT2_PROXY;
            goto finalize;
        }

        /* Check for GT2_LIMITED_PROXY tail */
        if (cert_subjectdn
            && (strlen(cert_subjectdn) > strlen("/cn=limited proxy"))
            && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=limited proxy")])
            && (strcasecmp(tail_str, "/cn=limited proxy") == 0)
           ) {
            /* verify_log (L_DEBUG, "%s: Detected GT2 limited proxy certificate", logstr); */
            pt = GT2_LIMITED_PROXY;
            goto finalize;
        }

        /* Check for RFC_PROXY, without the need for OpenSSL proxy support */
        /* Method: Check if the subject_dn is long enough, grab its tail and
         * snip of the 10 characters. Then check if the 10 characters are
         * numbers. */
        if (cert_subjectdn
            && (strlen(cert_subjectdn) > strlen("/cn=0123456789"))
            && (tail_str = strrchr(cert_subjectdn, '='))
            && (tail_str = &tail_str[1])
            && (strtol(tail_str, NULL, 10))
            && (errno != ERANGE)
           ) {
            /* verify_log (L_DEBUG, "%s: Detected RFC proxy certificate", logstr); */
            pt = RFC_PROXY;
            goto finalize;
        }

        /* Don't know the type of proxy, could be an RFC proxy with
         * improper/incomplete implementation in the active OpenSSL version or
         * a mistake in the client software */
        goto failure;
    }


    /* I have no idea what else it is, so I conclude that it's an EEC */
    pt = EEC;
    goto finalize;

failure:
    /* On failure, or non-distinct selections of the certificate, indicate NONE */
    pt = NONE;
finalize:
    if (cert_subjectdn)
        free(cert_subjectdn);
    if (cert_issuerdn)
        free(cert_issuerdn);

    return pt;
}