Exemplo n.º 1
0
static int x509_wildcard_verify( const char *cn, x509_buf *name )
{
    size_t i;
    size_t cn_idx = 0;

    if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
        return( 0 );

    for( i = 0; i < strlen( cn ); ++i )
    {
        if( cn[i] == '.' )
        {
            cn_idx = i;
            break;
        }
    }

    if( cn_idx == 0 )
        return( 0 );

    if( strlen( cn ) - cn_idx == name->len - 1 &&
        x509_name_cmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
    {
        return( 1 );
    }

    return( 0 );
}
Exemplo n.º 2
0
/*
 * Check if 'parent' is a suitable parent (signing CA) for 'child'.
 * Return 0 if yes, -1 if not.
 *
 * top means parent is a locally-trusted certificate
 * bottom means child is the end entity cert
 */
static int x509_crt_check_parent(const ttls_x509_crt *child,
		  const ttls_x509_crt *parent,
		  int top, int bottom)
{
	int need_ca_bit;

	/* Parent must be the issuer */
	if (x509_name_cmp(&child->issuer, &parent->subject) != 0)
		return(-1);

	/* Parent must have the basicConstraints CA bit set as a general rule */
	need_ca_bit = 1;

	/* Exception: v1/v2 certificates that are locally trusted. */
	if (top && parent->version < 3)
		need_ca_bit = 0;

	/* Exception: self-signed end-entity certs that are locally trusted. */
	if (top && bottom &&
		child->raw.len == parent->raw.len &&
		memcmp(child->raw.p, parent->raw.p, child->raw.len) == 0)
	{
		need_ca_bit = 0;
	}

	if (need_ca_bit && ! parent->ca_istrue)
		return(-1);

#if defined(TTLS_X509_CHECK_KEY_USAGE)
	if (need_ca_bit &&
		ttls_x509_crt_check_key_usage(parent, TTLS_X509_KU_KEY_CERT_SIGN) != 0)
	{
		return(-1);
	}
#endif

	return 0;
}
Exemplo n.º 3
0
static int
x509_crt_verify_child(ttls_x509_crt *child, ttls_x509_crt *parent,
		      ttls_x509_crt *trust_ca, ttls_x509_crl *ca_crl,
		      const ttls_x509_crt_profile *profile,
		      int path_cnt, int self_cnt, uint32_t *flags)
{
	int ret;
	uint32_t parent_flags = 0;
	unsigned char hash[TTLS_MD_MAX_SIZE];
	ttls_x509_crt *grandparent;
	const TlsMdInfo *md_info;

	/* Counting intermediate self signed certificates */
	if ((path_cnt != 0) && x509_name_cmp(&child->issuer, &child->subject) == 0)
		self_cnt++;

	/* path_cnt is 0 for the first intermediate CA */
	if (1 + path_cnt > TTLS_X509_MAX_INTERMEDIATE_CA)
	{
		/* return immediately as the goal is to avoid unbounded recursion */
		return(TTLS_ERR_X509_FATAL_ERROR);
	}

	if (ttls_x509_time_is_past(&child->valid_to))
		*flags |= TTLS_X509_BADCERT_EXPIRED;

	if (ttls_x509_time_is_future(&child->valid_from))
		*flags |= TTLS_X509_BADCERT_FUTURE;

	if (x509_profile_check_md_alg(profile, child->sig_md) != 0)
		*flags |= TTLS_X509_BADCERT_BAD_MD;

	if (x509_profile_check_pk_alg(profile, child->sig_pk) != 0)
		*flags |= TTLS_X509_BADCERT_BAD_PK;

	md_info = ttls_md_info_from_type(child->sig_md);
	if (md_info == NULL)
	{
		/*
		 * Cannot check 'unknown' hash
		 */
		T_WARN("certificate uses unsupported hash %d\n", child->sig_md);
		*flags |= TTLS_X509_BADCERT_NOT_TRUSTED;
	}
	else
	{
		ttls_md(md_info, child->tbs.p, child->tbs.len, hash);

		if (x509_profile_check_key(profile, child->sig_pk, &parent->pk) != 0)
			*flags |= TTLS_X509_BADCERT_BAD_KEY;

		if (ttls_pk_verify_ext(child->sig_pk, child->sig_opts, &parent->pk,
			   child->sig_md, hash, ttls_md_get_size(md_info),
			   child->sig.p, child->sig.len) != 0)
		{
			*flags |= TTLS_X509_BADCERT_NOT_TRUSTED;
		}
	}

#if defined(TTLS_X509_CRL_PARSE_C)
	/* Check trusted CA's CRL for the given crt */
	*flags |= x509_crt_verifycrl(child, parent, ca_crl, profile);
#endif

	/* Look for a grandparent in trusted CAs */
	for (grandparent = trust_ca;
		 grandparent != NULL;
		 grandparent = grandparent->next)
	{
		if (x509_crt_check_parent(parent, grandparent,
		   0, path_cnt == 0) == 0)
			break;
	}

	if (grandparent != NULL)
	{
		ret = x509_crt_verify_top(parent, grandparent, ca_crl, profile,
					  path_cnt + 1, self_cnt, &parent_flags);
		if (ret != 0)
			return ret;
	}
	else
	{
		/* Look for a grandparent upwards the chain */
		for (grandparent = parent->next;
			 grandparent != NULL;
			 grandparent = grandparent->next)
		{
			/* +2 because the current step is not yet accounted for
			 * and because max_pathlen is one higher than it should be.
			 * Also self signed certificates do not count to the limit. */
			if (grandparent->max_pathlen > 0 &&
				grandparent->max_pathlen < 2 + path_cnt - self_cnt)
			{
				continue;
			}

			if (x509_crt_check_parent(parent, grandparent,
			   0, path_cnt == 0) == 0)
				break;
		}

		/* Is our parent part of the chain or at the top? */
		if (grandparent != NULL)
		{
			ret = x509_crt_verify_child(parent, grandparent,
						    trust_ca, ca_crl, profile,
						    path_cnt + 1, self_cnt,
						    &parent_flags);
			if (ret != 0)
				return ret;
		}
		else
		{
			ret = x509_crt_verify_top(parent, trust_ca, ca_crl,
						  profile, path_cnt + 1,
						  self_cnt, &parent_flags);
			if (ret != 0)
				return ret;
		}
	}

	*flags |= parent_flags;

	return 0;
}
Exemplo n.º 4
0
/*
 * Verify the certificate validity
 */
int x509_crt_verify( x509_crt *crt,
                     x509_crt *trust_ca,
                     x509_crl *ca_crl,
                     const char *cn, int *flags,
                     int (*f_vrfy)(void *, x509_crt *, int, int *),
                     void *p_vrfy )
{
    size_t cn_len;
    int ret;
    int pathlen = 0;
    x509_crt *parent;
    x509_name *name;
    x509_sequence *cur = NULL;

    *flags = 0;

    if( cn != NULL )
    {
        name = &crt->subject;
        cn_len = strlen( cn );

        if( crt->ext_types & EXT_SUBJECT_ALT_NAME )
        {
            cur = &crt->subject_alt_names;

            while( cur != NULL )
            {
                if( cur->buf.len == cn_len &&
                    x509_name_cmp( cn, cur->buf.p, cn_len ) == 0 )
                    break;

                if( cur->buf.len > 2 &&
                    memcmp( cur->buf.p, "*.", 2 ) == 0 &&
                            x509_wildcard_verify( cn, &cur->buf ) )
                    break;

                cur = cur->next;
            }

            if( cur == NULL )
                *flags |= BADCERT_CN_MISMATCH;
        }
        else
        {
            while( name != NULL )
            {
                if( OID_CMP( OID_AT_CN, &name->oid ) )
                {
                    if( name->val.len == cn_len &&
                        x509_name_cmp( name->val.p, cn, cn_len ) == 0 )
                        break;

                    if( name->val.len > 2 &&
                        memcmp( name->val.p, "*.", 2 ) == 0 &&
                                x509_wildcard_verify( cn, &name->val ) )
                        break;
                }

                name = name->next;
            }

            if( name == NULL )
                *flags |= BADCERT_CN_MISMATCH;
        }
    }

    /*
     * Iterate upwards in the given cert chain, to find our crt parent.
     * Ignore any upper cert with CA != TRUE.
     */
    parent = crt->next;

    while( parent != NULL && parent->version != 0 )
    {
        if( parent->ca_istrue == 0 ||
            crt->issuer_raw.len != parent->subject_raw.len ||
            memcmp( crt->issuer_raw.p, parent->subject_raw.p,
                    crt->issuer_raw.len ) != 0 )
        {
            parent = parent->next;
            continue;
        }
        break;
    }

    if( parent != NULL )
    {
        /*
         * Part of the chain
         */
        ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy );
        if( ret != 0 )
            return( ret );
    }
    else
    {
        ret = x509_crt_verify_top( crt, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy );
        if( ret != 0 )
            return( ret );
    }

    if( *flags != 0 )
        return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );

    return( 0 );
}