📄 pkixcertpathval.c
字号:
/* Copyright (C) 2002 PGP Corporation
All Rights Reserved.
Author: Michael_Elkins@nai.com
Last Edit: March 22, 1999 */
/* This file contains code implementing the "Basic Path Validitation"
algorithm described in section 6.1 of RFC2459 */
#include "cms.h"
#define TC_F_PERMIT 0x010000
/*****
*
* tc_find_crl
*
* Inputs:
* issuer
* Certificate for issuer of crl. this is a pointer to the
* certificate, and not just the DN since the cert is required
* to verify the CRL.
*
* ctx
* CMS context structure.
*
* Outputs:
* crl
* Pointer to requested CRL. NOTE: this is a pointer to the
* in-store copy of the CRL and the application SHOULD NOT free
* it.
*
* Returns:
* 0 success
* <0 failure
*/
static int
tc_find_crl (TC_CertificateList **crl, /* OUT */
TC_CERT *issuer, /* IN */
TC_CONTEXT *ctx) /* IN */
{
int status=TC_E_NOTFOUND; /*crl not found*/
TC_CertificateList *list;
TC_LIST *entry;
if(!crl||!issuer||!ctx)
return TC_E_INVARGS;
*crl=NULL;/*clear input*/
for (entry=ctx->crl; entry; entry=entry->next)
{
list = (TC_CertificateList *) entry->data;
if (tc_compare_dname (&list->tbsCertList.issuer,
&issuer->tbsCertificate->issuer,
ctx))
{
status=0;
*crl=list;
break;
}
}
return status;
} /* tc_find_crl */
/*****
*
* tc_validate_crl
*
* Performs integrity check and PKIX compliance test on specified CRL.
*
* Inputs:
* crl
* CRL to validate.
*
* issuer
* Certificate of CRL issuer.
*
* flags
* TC_F_PKIX
* Turn on pedantic checks required by RFC2459 for CRLs.
*
* ctx
* CMS context structure.
*
* Returns:
* 0 success
* <0 failure
*/
static int
tc_validate_crl (TC_CertificateList *crl,
TC_CERT *issuer,
int flags,
TC_CONTEXT *ctx)
{
unsigned char *blob;
size_t blobsize;
TC_Extension *ext;
int status=0, n;
/* verify signature algorithms are the same on the inside and outside of
signed block */
if (tc_compare_block (&crl->signatureAlgorithm.algorithm,
&crl->tbsCertList.signature.algorithm) != 1)
return TC_E_INVALIDCRL; /* signature OIDs do not match */
if (flags & TC_F_PKIX)
{
/* verify version 2 CRL */
if (!crl->tbsCertList.version ||
PKIGetIntVal (ctx->certasnctx, crl->tbsCertList.version, &status) != 1)
return TC_E_NOTV2CRL;
if (status)
return (compiler2tc_error (status));
/* TODO: RFC2459 Section 5.1.2.4 states that for times <2050A.D. CAs
MUST use UTCTime, otherwise use GeneralizedTime for >2050A.D.
CMS uses `time_t' which on most systems overflows in the year
2038. */
/* verify the existence of the `nextUpdate' field */
if(!crl->tbsCertList.nextUpdate)
return TC_E_MISSINGNEXTUPDATE;
/* ----- check for mandatory crl extensions ----- */
status=tc_find_extension(&ext,
crl->tbsCertList.crlExtensions,
PKIid_ce_authorityKeyIdentifier_OID,
PKIid_ce_authorityKeyIdentifier_OID_LEN,
ctx);
if(status)
return TC_E_MISSINGAUTHKEYIDEXT;
status=tc_find_extension(&ext,
crl->tbsCertList.crlExtensions,
PKIid_ce_cRLNumber_OID,
PKIid_ce_cRLNumber_OID_LEN,
ctx);
if(status)
return TC_E_MISSINGCRLNUMBEREXT;
}
/* verify signature */
blobsize=PKISizeofTBSCertList(ctx->certasnctx,&crl->tbsCertList,PKITRUE);
blob=TC_Alloc(ctx->memMgr,blobsize);
if(!blob)
return TC_E_NOMEMORY;
PKIPackTBSCertList(ctx->certasnctx,blob,blobsize,&crl->tbsCertList,&status);
if(!status)
{
status = ctx->verify(blob,
blobsize,
crl->signatureAlgorithm.algorithm.val,
crl->signatureAlgorithm.algorithm.len,
crl->signatureAlgorithm.parameters ? crl->signatureAlgorithm.parameters->val : NULL,
crl->signatureAlgorithm.parameters ? crl->signatureAlgorithm.parameters->len : 0,
crl->signature.val,
crl->signature.len,
issuer->tbsCertificate->subjectPublicKeyInfo.subjectPublicKey.val,
issuer->tbsCertificate->subjectPublicKeyInfo.subjectPublicKey.len,
issuer,
ctx->verfuncdata,
ctx);
}
/* process crl extensions */
if (status == 0 && crl->tbsCertList.crlExtensions)
{
status=tc_process_extensions(crl->tbsCertList.crlExtensions,
(void*) crl,
ctx);
}
/* process CRL entry extensions */
if (status == 0 && crl->tbsCertList.revokedCertificates)
{
for (n=0; n < crl->tbsCertList.revokedCertificates->n; n++)
{
status = tc_process_extensions (crl->tbsCertList.revokedCertificates->elt[n]->crlEntryExtensions,
(void *) crl,
ctx);
if (status)
break;
}
}
TC_Free(ctx->memMgr,blob);
return status;
} /* tc_validate_crl */
/*****
*
* tc_cert_not_revoked
*
* Checks CRL for presence of specified certificate. This function assumes
* the caller has already checked the CRL using tc_validate_crl().
*
* Inputs:
* cert
* certificate to validate
* crl
* revocation list to check
* when
* time at which to check for revocation
* flags
* should be 0 (none specified)
* ctx
* CMS context structure
*
* Returns:
* 0 success (certificate is not revoked)
* <0 error or certificate is revoked
*/
static int
tc_cert_not_revoked (TC_CERT *cert,
TC_CertificateList *crl,
time_t when,
int flags,
TC_CONTEXT *ctx)
{
int i,status;
time_t revoked;
(void) flags;
/* verify that the certificate specified was issued by the issuer of the
CRL */
status = tc_compare_dname (&cert->tbsCertificate->issuer,
&crl->tbsCertList.issuer,
ctx);
if (status!=1)
return TC_E_WRONGCRL;
/* search the revoked certs list for the named cert */
if (crl->tbsCertList.revokedCertificates)
{
for (i=0; i<crl->tbsCertList.revokedCertificates->n; i++)
{
status = tc_compare_serial (&cert->tbsCertificate->serialNumber,
&crl->tbsCertList.revokedCertificates->elt[i]->userCertificate);
if (status==1)
{
revoked = tc_get_choiceoftime (&crl->tbsCertList.revokedCertificates->elt[i]->revocationDate,
ctx);
return ((when>=revoked) ? TC_E_CERTREVOKED : 0);
}
}
}
return 0;
} /* tc_cert_not_revoked */
/*****
*
* tc_check_rfc822name_constraint
*
* Returns:
* 1 constraint matches
* 0 constraint does not match
*/
static int
tc_check_rfc822name_constraint (PKIIA5String *n, PKIIA5String *rfc)
{
if(n->len < rfc->len)
return 0;
return((memcmp(rfc->val,n->val + n->len - rfc->len, rfc->len) == 0));
} /* tc_check_rfc822name_constraint */
/* RFC2459: DNS name restrictions are expressed as foo.bar.com. Any subdomain
satisfies the name constraint. For example, www.foo.bar.com would satisfy
the constraint but bigfoo.bar.com would not. */
static int tc_check_dnsname_constraint (PKIIA5String *n, PKIIA5String *c)
{
if(n->len < c->len)
return 0;
if (memcmp(n->val+n->len-c->len,c->val,c->len))
return 0;
if(n->val==c->val)
return 1;/*exact match*/
/* ensure this is a valid subdomain, and doesn't match part of another
name */
return ((*(n->val+n->len-c->len-1) == '.'));
} /* tc_check_dnsname_constraint */
static int tc_check_uri_constraint (PKIIA5String *url, PKIIA5String *c)
{
unsigned char *p, *e;
size_t l;
p=url->val;
while ((size_t)(p - url->val) < url->len - 3 &&
!(*p == ':' && *(p+1)=='/' && *(p+2)=='/'))
p++;
if(*p!=':')
return TC_E_INVALIDURI;
p+=3;/*skip over the :// */
/* now find the end of the hostname */
e=p;
while((size_t)(e - url->val) < url->len && *e != '/' && *e != ':')
e++;
l=e-p;/*length of hostname */
if(l<c->len)
return 0;
if(memcmp(p+l-c->len,c->val,c->len))
return 0;
if(l==c->len)
return 1;/*exact match*/
if(*c->val!='.' && *(p+l-c->len-1)!='.')
return 0; /* not a subdomain */
return 1;/*valid subdomain */
} /* tc_check_uri_constraint */
static int
tc_check_ipaddress_constraint (PKIOCTET_STRING *ip, PKIOCTET_STRING *c)
{
size_t i;
if(ip->len * 2 != c->len)
return TC_E_INVALIDIPCONSTRAINT;
for(i=0;i<ip->len;i++)
{
if ((ip->val[i] & c->val[i+ip->len]) != (c->val[i] & c->val[i+ip->len]))
return 0;
}
return 1;
} /* tc_check_ipaddress_constraint */
static int tc_check_name_constraint (PKIGeneralName *name,
PKIGeneralSubtree *constraint,
TC_CONTEXT *ctx)
{
int status=0;
(void)ctx;
/*NOTE: otherName, ediPartyName and registeredID are not required
to be handled for PKIX compliance */
/* TODO: for rfc822Name we also need to check the DN for the EmailAddress
attribute if the subjectAltName is missing */
if(name->CHOICE_field_type != constraint->base.CHOICE_field_type)
return TC_E_WRONGNAMETYPE;
switch(constraint->base.CHOICE_field_type)
{
case 0xa1: /* rfc822Name */
status=tc_check_rfc822name_constraint(name->data,
constraint->base.data);
break;
case 0xa2: /* dNSName */
status=tc_check_dnsname_constraint(name->data,
constraint->base.data);
break;
case 0xa3: /* x400Address */
status=TC_E_NAMETYPEUNSUPPORTED;/* not supported */
break;
case 0xa4: /* directoryName */
/* TODO */
break;
case 0xa6: /* URI */
status=tc_check_uri_constraint(name->data,
constraint->base.data);
break;
case 0xa7: /* iPAddress */
status=tc_check_ipaddress_constraint(name->data,
constraint->base.data);
break;
}
return status;
} /* tc_check_name_constraint */
/*****
*
* tc_check_name_constraint
*
* Checks whether the given name matches the specified constraint pattern.
*
* Input:
* name
* name to check
* constraint
* tree of matching names
* flags
* TC_F_PERMIT
* all matched name types MUST match the constraint
* ctx
* CMS context structure
*
* Returns:
* 0 name is consistent with constraint
* <0 error
*/
static int tc_check_name_constraints (PKIGeneralName *name,
PKIGeneralSubtrees *constraint,
int flags,
TC_CONTEXT *ctx)
{
int n,status=0;
for(n=0;n<constraint->n;n++)
{
status=tc_check_name_constraint(name,constraint->elt[n],ctx);
if(status==0)
{
/* name type exists, constraint does not match */
if(flags & TC_F_PERMIT)
return TC_E_CONSTRAINTFAIL;
}
else if (status==1)
{
/* name type exists, constraint matches */
if(!(flags & TC_F_PERMIT))
return TC_E_CONSTRAINTFAIL;
}
}
return 0;
} /* tc_check_name_constraints */
static int tc_do_name_constraints (PKIGeneralName *sdn,
PKISubjectAltName *san,
PKIGeneralSubtrees *tree,
int flags,
TC_CONTEXT *ctx)
{
int j, status;
/* first check subject name */
status=tc_check_name_constraints(sdn, tree, flags, ctx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -