예제 #1
0
/*
 * Verify the certificate validity, with profile
 */
int ttls_x509_crt_verify_with_profile(ttls_x509_crt *crt,
		 ttls_x509_crt *trust_ca,
		 ttls_x509_crl *ca_crl,
		 const ttls_x509_crt_profile *profile,
		 const char *cn, uint32_t *flags)
{
	size_t cn_len;
	int ret;
	int pathlen = 0, selfsigned = 0;
	ttls_x509_crt *parent;
	ttls_x509_name *name;
	ttls_x509_sequence *cur = NULL;
	ttls_pk_type_t pk_type;

	*flags = 0;

	if (profile == NULL)
	{
		ret = TTLS_ERR_X509_BAD_INPUT_DATA;
		goto exit;
	}

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

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

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

				if (cur->buf.len > 2
				    && !memcmp(cur->buf.p, "*.", 2)
				    && !x509_check_wildcard(cn, &cur->buf))
					break;

				cur = cur->next;
			}

			if (cur == NULL)
				*flags |= TTLS_X509_BADCERT_CN_MISMATCH;
		}
		else
		{
			while (name != NULL)
			{
				if (!TTLS_OID_CMP(TTLS_OID_AT_CN, &name->oid)) {
					if (name->val.len == cn_len
					    && !x509_memcasecmp(name->val.p, cn,
								cn_len))
						break;

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

				name = name->next;
			}

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

	/* Check the type and size of the key */
	pk_type = ttls_pk_get_type(&crt->pk);

	if (x509_profile_check_pk_alg(profile, pk_type) != 0)
		*flags |= TTLS_X509_BADCERT_BAD_PK;

	if (x509_profile_check_key(profile, pk_type, &crt->pk) != 0)
		*flags |= TTLS_X509_BADCERT_BAD_KEY;

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

	if (parent != NULL)
	{
		ret = x509_crt_verify_top(crt, parent, ca_crl, profile, pathlen,
					  selfsigned, flags);
		if (ret != 0)
			goto exit;
	}
	else
	{
		/* Look for a parent upwards the chain */
		for (parent = crt->next; parent != NULL; parent = parent->next)
			if (x509_crt_check_parent(crt, parent, 0, pathlen == 0) == 0)
				break;

		/* Are we part of the chain or at the top? */
		if (parent != NULL)
		{
			ret = x509_crt_verify_child(crt, parent, trust_ca,
						    ca_crl, profile, pathlen,
						    selfsigned, flags);
			if (ret != 0)
				goto exit;
		}
		else
		{
			ret = x509_crt_verify_top(crt, trust_ca, ca_crl,
						  profile, pathlen, selfsigned,
						  flags);
			if (ret != 0)
				goto exit;
		}
	}

exit:
	/* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
	 * the SSL module for authmode optional, but non-zero return from the
	 * callback means a fatal error so it shouldn't be ignored */
	if (ret == TTLS_ERR_X509_CERT_VERIFY_FAILED)
		ret = TTLS_ERR_X509_FATAL_ERROR;

	if (ret != 0)
	{
		*flags = (uint32_t) -1;
		return ret;
	}

	if (*flags != 0)
		return TTLS_ERR_X509_CERT_VERIFY_FAILED;

	return 0;
}
예제 #2
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 );
}
예제 #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;
}
예제 #4
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 );
}