Пример #1
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;
}
Пример #2
0
static int x509_crt_verify_child(
                x509_crt *child, x509_crt *parent, x509_crt *trust_ca,
                x509_crl *ca_crl, int path_cnt, int *flags,
                int (*f_vrfy)(void *, x509_crt *, int, int *),
                void *p_vrfy )
{
    int ret;
    int parent_flags = 0;
    unsigned char hash[POLARSSL_MD_MAX_SIZE];
    x509_crt *grandparent;
    const md_info_t *md_info;

    if( x509_time_expired( &child->valid_to ) )
        *flags |= BADCERT_EXPIRED;

    md_info = md_info_from_type( child->sig_md );
    if( md_info == NULL )
    {
        /*
         * Cannot check 'unknown' hash
         */
        *flags |= BADCERT_NOT_TRUSTED;
    }
    else
    {
        md( md_info, child->tbs.p, child->tbs.len, hash );

        if( pk_can_do( &parent->pk, child->sig_pk ) == 0 ||
            pk_verify( &parent->pk, child->sig_md, hash, md_info->size,
                       child->sig.p, child->sig.len ) != 0 )
        {
            *flags |= BADCERT_NOT_TRUSTED;
        }
    }

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

    grandparent = parent->next;

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

    if( grandparent != NULL )
    {
        /*
         * Part of the chain
         */
        ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy );
        if( ret != 0 )
            return( ret );
    }
    else
    {
        ret = x509_crt_verify_top( parent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy );
        if( ret != 0 )
            return( ret );
    }

    /* child is verified to be a child of the parent, call verify callback */
    if( NULL != f_vrfy )
        if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 )
            return( ret );

    *flags |= parent_flags;

    return( 0 );
}
Пример #3
0
static int
x509_crt_verify_top(ttls_x509_crt *child, 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)
{
	uint32_t ca_flags = 0;
	int check_path_cnt;
	unsigned char hash[TTLS_MD_MAX_SIZE];
	const TlsMdInfo *md_info;
	ttls_x509_crt *future_past_ca = NULL;

	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;

	/*
	 * Child is the top of the chain. Check against the trust_ca list.
	 */
	*flags |= TTLS_X509_BADCERT_NOT_TRUSTED;

	md_info = ttls_md_info_from_type(child->sig_md);
	if (md_info == NULL)
	{
		/*
		 * Cannot check 'unknown', no need to try any CA
		 */
		trust_ca = NULL;
	}
	else
		ttls_md(md_info, child->tbs.p, child->tbs.len, hash);

	for (/* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next)
	{
		if (x509_crt_check_parent(child, trust_ca, 1, path_cnt == 0) != 0)
			continue;

		check_path_cnt = path_cnt + 1;

		/*
		 * Reduce check_path_cnt to check against if top of the chain is
		 * the same as the trusted CA
		 */
		if (child->subject_raw.len == trust_ca->subject_raw.len &&
			memcmp(child->subject_raw.p, trust_ca->subject_raw.p,
				child->issuer_raw.len) == 0)
		{
			check_path_cnt--;
		}

		/* Self signed certificates do not count towards the limit */
		if (trust_ca->max_pathlen > 0 &&
			trust_ca->max_pathlen < check_path_cnt - self_cnt)
		{
			continue;
		}

		if (ttls_pk_verify_ext(child->sig_pk, child->sig_opts, &trust_ca->pk,
			   child->sig_md, hash, ttls_md_get_size(md_info),
			   child->sig.p, child->sig.len) != 0)
		{
			continue;
		}

		if (ttls_x509_time_is_past(&trust_ca->valid_to) ||
			ttls_x509_time_is_future(&trust_ca->valid_from))
		{
			if (future_past_ca == NULL)
				future_past_ca = trust_ca;

			continue;
		}

		break;
	}

	if (trust_ca != NULL || (trust_ca = future_past_ca) != NULL)
	{
		/*
		 * Top of chain is signed by a trusted CA
		 */
		*flags &= ~TTLS_X509_BADCERT_NOT_TRUSTED;

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

	/*
	 * If top of chain is not the same as the trusted CA send a verify request
	 * to the callback for any issues with validity and CRL presence for the
	 * trusted CA certificate.
	 */
	if (trust_ca != NULL &&
		(child->subject_raw.len != trust_ca->subject_raw.len ||
		  memcmp(child->subject_raw.p, trust_ca->subject_raw.p,
				child->issuer_raw.len) != 0))
	{
#if defined(TTLS_X509_CRL_PARSE_C)
		/* Check trusted CA's CRL for the chain's top crt */
		*flags |= x509_crt_verifycrl(child, trust_ca, ca_crl, profile);
#else
		((void) ca_crl);
#endif

		if (ttls_x509_time_is_past(&trust_ca->valid_to))
			ca_flags |= TTLS_X509_BADCERT_EXPIRED;

		if (ttls_x509_time_is_future(&trust_ca->valid_from))
			ca_flags |= TTLS_X509_BADCERT_FUTURE;
	}

	*flags |= ca_flags;

	return 0;
}
Пример #4
0
static int x509_crt_verify_top(
                x509_crt *child, x509_crt *trust_ca,
                x509_crl *ca_crl, int path_cnt, int *flags,
                int (*f_vrfy)(void *, x509_crt *, int, int *),
                void *p_vrfy )
{
    int ret;
    int ca_flags = 0, check_path_cnt = path_cnt + 1;
    unsigned char hash[POLARSSL_MD_MAX_SIZE];
    const md_info_t *md_info;

    if( x509_time_expired( &child->valid_to ) )
        *flags |= BADCERT_EXPIRED;

    /*
     * Child is the top of the chain. Check against the trust_ca list.
     */
    *flags |= BADCERT_NOT_TRUSTED;

    md_info = md_info_from_type( child->sig_md );
    if( md_info == NULL )
    {
        /*
         * Cannot check 'unknown', no need to try any CA
         */
        trust_ca = NULL;
    }
    else
        md( md_info, child->tbs.p, child->tbs.len, hash );

    while( trust_ca != NULL )
    {
        if( trust_ca->version == 0 ||
            child->issuer_raw.len != trust_ca->subject_raw.len ||
            memcmp( child->issuer_raw.p, trust_ca->subject_raw.p,
                    child->issuer_raw.len ) != 0 )
        {
            trust_ca = trust_ca->next;
            continue;
        }

        /*
         * Reduce path_len to check against if top of the chain is
         * the same as the trusted CA
         */
        if( child->subject_raw.len == trust_ca->subject_raw.len &&
            memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
                            child->issuer_raw.len ) == 0 )
        {
            check_path_cnt--;
        }

        if( trust_ca->max_pathlen > 0 &&
            trust_ca->max_pathlen < check_path_cnt )
        {
            trust_ca = trust_ca->next;
            continue;
        }

        if( pk_can_do( &trust_ca->pk, child->sig_pk ) == 0 ||
            pk_verify( &trust_ca->pk, child->sig_md, hash, md_info->size,
                       child->sig.p, child->sig.len ) != 0 )
        {
            trust_ca = trust_ca->next;
            continue;
        }

        /*
         * Top of chain is signed by a trusted CA
         */
        *flags &= ~BADCERT_NOT_TRUSTED;
        break;
    }

    /*
     * If top of chain is not the same as the trusted CA send a verify request
     * to the callback for any issues with validity and CRL presence for the
     * trusted CA certificate.
     */
    if( trust_ca != NULL &&
        ( child->subject_raw.len != trust_ca->subject_raw.len ||
          memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
                            child->issuer_raw.len ) != 0 ) )
    {
#if defined(POLARSSL_X509_CRL_PARSE_C)
        /* Check trusted CA's CRL for the chain's top crt */
        *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl );
#else
        ((void) ca_crl);
#endif

        if( x509_time_expired( &trust_ca->valid_to ) )
            ca_flags |= BADCERT_EXPIRED;

        if( NULL != f_vrfy )
        {
            if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, &ca_flags ) ) != 0 )
                return( ret );
        }
    }

    /* Call callback on top cert */
    if( NULL != f_vrfy )
    {
        if( ( ret = f_vrfy(p_vrfy, child, path_cnt, flags ) ) != 0 )
            return( ret );
    }

    *flags |= ca_flags;

    return( 0 );
}