📄 pkixcheck.c
字号:
/****
*
* tc_CertCheckPKIXCompliance
*
* Check the provided certificate for PKIX part 1 compliance. The paragraph
* numbers from the spec. where the requirements are located are included
* in the comments. This routine checks what it can, but it can't check
* everything since it only has the certificate information in isolation. For
* instance, it can't check that the serial number is unique for the issuing
* CA.
*
* The routine will return the first error found. It goes through all the
* checks it can and if you would like all the possible errors, you can provide
* pointers for numErrors and errorList to receive an array of all the errors
* found. You are responsible for deallocating the memory in errorList in
* this case.
*
* If there is a problem in the processing itself (eg., memory allocation
* problem, then the routine will set errorList and numErrors to NULL
* and return an error appropriate to the problem (eg., TC_E_NOMEMORY).
*
* Note: this call does not assume the cert was created with tc_create_cert()
* since the caller could have changed some values on their own. It does
* assume that a newly created certificate structure is being checked so
* it will return errors for items related to newly created certs (eg.,
* issuer unique identifier should not be present )
*
*****/
int tc_CertCheckPKIXCompliance(
const TC_CERT *cert,
TC_CertType certType,
int **errorList,
int *numErrors,
TC_CONTEXT *ctx)
{
int localErrors[300];
int localNumErrors;
PKIAlgorithmIdentifier *sigAlg;
TC_TBSCertificate *tbsCert;
PKIRDNSequence *rdnSeq;
PKIAlgorithmIdentifier *keyAlg;
int ver;
int error = 0;
int i;
if (cert == NULL || ctx == NULL)
return TC_E_INVARGS;
if (errorList != NULL)
*errorList = NULL;
if (numErrors != NULL)
*numErrors = 0;
localErrors[0] = 0;
localNumErrors = 0;
tbsCert = cert->tbsCertificate;
/* sigAlg field same as signature field in tbsCert; 4.1.1.2 & 4.1.2.3 */
sigAlg = &cert->cert->signatureAlgorithm;
if (tbsCert->signature.algorithm.len != sigAlg->algorithm.len ||
memcmp(tbsCert->signature.algorithm.val,
sigAlg->algorithm.val, sigAlg->algorithm.len) != 0)
{
localErrors[localNumErrors] = TC_E_SigAlgSignatureMismatch;
localNumErrors++;
}
/* version value omitted when its v1, version value is v2 when
UniqueIdentifier is present, version is v3 when extensions
present; 4.1.2.1 */
if (tbsCert->version != NULL)
{
ver = PKIGetIntVal(ctx->certasnctx, tbsCert->version, &error);
if (tbsCert->extensions != NULL &&
ver != TC_X509_VERSION_3)
{
localErrors[localNumErrors] = TC_E_VersionShouldBe3;
localNumErrors++;
}
else if ( (tbsCert->issuerUniqueID != NULL ||
tbsCert->subjectUniqueID != NULL) &&
ver != TC_X509_VERSION_2)
{
localErrors[localNumErrors] = TC_E_VersionShouldBe2;
localNumErrors++;
}
else
{
localErrors[localNumErrors] = TC_E_VersionShouldBeNULL;
localNumErrors++;
}
}
else /* NULL version, so its v1 */
{
if (tbsCert->extensions != NULL)
{
localErrors[localNumErrors] = TC_E_VersionShouldBe3;
localNumErrors++;
}
else if (tbsCert->issuerUniqueID != NULL ||
tbsCert->subjectUniqueID != NULL )
{
localErrors[localNumErrors] = TC_E_VersionShouldBe2;
localNumErrors++;
}
}
/* issuer field is not empty, this assumes the Name CHOICE is
the RDNSequence type; 4.1.2.4 */
rdnSeq = (PKIRDNSequence *)tbsCert->issuer.data;
if (rdnSeq->n <= 0)
{
localErrors[localNumErrors] = TC_E_EmptyIssuerName;
localNumErrors++;
}
/* Dname checks */
/* call CheckDname() with subject */
/* validity is UTCTime until 2049, assuming current size of time_t
is 4 bytes, we can reliably check for date until 2038, so fail
then with different error. Hopefully this will cause a look
at the code so it can be updated as needed. See comments in
tc_encode_utctime() for more details like where the numbers
below came from. 4.1.2.5 */
if (time(NULL) > (2147483647L - (31536000/2)) )
{
localErrors[localNumErrors] = TC_E_CantHandleCurrentTimeValue;
localNumErrors++;
}
else
{
if (tbsCert->validity.notBefore.CHOICE_field_type !=
PKIID_UTCTime ||
tbsCert->validity.notAfter.CHOICE_field_type !=
PKIID_UTCTime )
{
localErrors[localNumErrors] = TC_E_ValidityNotUTCTime;
localNumErrors++;
}
}
/* CA cert has non-empty subject field; 4.1.2.6 */
if (certType == TC_RootCertAuthority ||
certType == TC_CertificateAuthority)
{
rdnSeq = (PKIRDNSequence *)tbsCert->subject.data;
if (rdnSeq->n <= 0)
{
localErrors[localNumErrors] = TC_E_EmptyIssuerName;
localNumErrors++;
}
}
/* root cert has same issuer/subject fields; 4.1.2.6 */
if (certType == TC_RootCertAuthority)
{
if (tc_compare_dname(&tbsCert->issuer, &tbsCert->subject,
ctx) != 1)
{
localErrors[localNumErrors] = TC_E_IssuerSubjectNotSameInRootCert;
localNumErrors++;
}
}
/* new certs should not have subject/issuer unique identifier; 4.1.2.7 */
if (tbsCert->issuerUniqueID != NULL)
{
localErrors[localNumErrors] = TC_E_IssuerUniqueIDPresent;
localNumErrors++;
}
if (tbsCert->subjectUniqueID != NULL)
{
localErrors[localNumErrors] = TC_E_SubjectUniqueIDPresent;
localNumErrors++;
}
/* Extension checks */
CheckExtensions(tbsCert, certType, localErrors, &localNumErrors, ctx);
/* if its RSA, parameters must be present and NULL in the
AlgorithmIdentifier field, need to check each field; 7.2.1 */
/* the signature field in TBSCertificate */
sigAlg = &tbsCert->signature;
if ( GetAlgorithm(sigAlg->algorithm) == ALG_RSA)
{
if (sigAlg->parameters == NULL)
{
localErrors[localNumErrors] = TC_E_RSAParametersMissing;
localNumErrors++;
}
else if (sigAlg->parameters->len < 2 ||
sigAlg->parameters->val[0] != 0x50)
{
localErrors[localNumErrors] = TC_E_RSAParametersNotASN1NULL;
localNumErrors++;
}
}
/* the subjectPublicKeyInfo field in TBSCertificate */
keyAlg = &tbsCert->subjectPublicKeyInfo.algorithm;
if ( GetAlgorithm(keyAlg->algorithm) == ALG_RSA)
{
if (keyAlg->parameters == NULL)
{
localErrors[localNumErrors] = TC_E_RSAParametersMissing;
localNumErrors++;
}
else if (keyAlg->parameters->len < 2 ||
keyAlg->parameters->val[0] != 0x50)
{
localErrors[localNumErrors] = TC_E_RSAParametersNotASN1NULL;
localNumErrors++;
}
}
/* the signatureAlgorithm field in Certificate */
sigAlg = &cert->cert->signatureAlgorithm;
if ( GetAlgorithm(sigAlg->algorithm) == ALG_RSA)
{
if (sigAlg->parameters == NULL)
{
localErrors[localNumErrors] = TC_E_RSAParametersMissing;
localNumErrors++;
}
else if (sigAlg->parameters->len < 2 ||
sigAlg->parameters->val[0] != 0x50)
{
localErrors[localNumErrors] = TC_E_RSAParametersNotASN1NULL;
localNumErrors++;
}
}
/* if its DSA, parameters field absent in AlgorithmIdentifier field
for the signature field in TBSCertificate and the signatureAlgorithm
field in Certificate; 7.2.2 */
sigAlg = &tbsCert->signature;
if ( GetAlgorithm(sigAlg->algorithm) == ALG_DSA)
{
if (sigAlg->parameters != NULL)
{
localErrors[localNumErrors] = TC_E_DSAParametersArePresent;
localNumErrors++;
}
}
sigAlg = &cert->cert->signatureAlgorithm;
if ( GetAlgorithm(sigAlg->algorithm) == ALG_DSA)
{
if (sigAlg->parameters != NULL)
{
localErrors[localNumErrors] = TC_E_DSAParametersArePresent;
localNumErrors++;
}
}
/* create the error list to return if requested */
if (errorList != NULL && numErrors != NULL)
{
*errorList = (int *)TC_Alloc(ctx->memMgr, sizeof(int) * localNumErrors);
if (errorList == NULL)
return TC_E_NOMEMORY;
for (i = 0; i < localNumErrors; i++)
(*errorList)[i] = localErrors[i];
*numErrors = localNumErrors;
}
return localErrors[0]; /* return the first error found */
} /* tc_CertCheckPKIXCompliance */
/****
*
* tc_CRLCheckPKIXCompliance
*
*****/
int tc_CRLCheckPKIXCompliance(
const TC_CertificateList *crl,
TC_CRLType crlType,
TC_CONTEXT *ctx)
{
int status = 0;
if (crl == NULL || ctx == NULL)
return TC_E_INVARGS;
/* version is v2 */
/* issuer field is not empty, this assumes the Name CHOICE is
the RDNSequence type; 5.1.3.2 */
/* include nextUpdate field */
/* include CRL number extension */
/* include authority key identifier field */
/* signatureAlgorithm field same as signature field in tbsCertList */
/* issuer name is present */
/* thisUpdate and nextUpdate are UTCTime until 2049 */
/* nextUpdate later than thisUpdate */
/* issuing distribution point ext is critical if there */
/* reason code ext is not critical */
/* don't use 'unspecified' in reason code ext. */
/* hold instruction code is not critical */
/* hold instruction codes recognized are (see para 5.3.2) */
/* invalidity data ext is not critical */
/* cert issuer CRL entry ext. is critical */
/* if its RSA, parameters must be present and NULL */
/* if its DSA, parameters field abscent in AlgorithmIdentifier field */
return status;
} /* tc_CRLCheckPKIXCompliance */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -