Skip to content

Commit

Permalink
Merge pull request #369 from PeculiarVentures/fix-chain-trusted-inter…
Browse files Browse the repository at this point in the history
…mediate

fix: build chain with trusted intermediate
  • Loading branch information
microshine authored Dec 8, 2022
2 parents cf9e547 + aefe145 commit 2e990f9
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 37 deletions.
107 changes: 72 additions & 35 deletions src/CertificateChainValidationEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,36 @@ const CHECK_DATE = "checkDate";
const FIND_ORIGIN = "findOrigin";
const FIND_ISSUER = "findIssuer";


export enum ChainValidationCode {
unknown = -1,
success = 0,
noRevocation = 11,
noPath = 60,
noValidPath = 97,
}

export class ChainValidationError extends Error {

public static readonly NAME = "ChainValidationError";

public code: ChainValidationCode;

constructor(code: ChainValidationCode, message: string) {
super(message);

this.name = ChainValidationError.NAME;
this.code = code;
this.message = message;
}

}

export interface CertificateChainValidationEngineVerifyResult {
result: boolean;
resultCode: number;
resultMessage: string;
error?: Error | ChainValidationError;
authConstrPolicies?: string[];
userConstrPolicies?: string[];
explicitPolicyIndicator?: boolean;
Expand Down Expand Up @@ -66,6 +92,22 @@ export interface CertificateChainValidationEngineVerifyParams {
passedWhenNotRevValues?: boolean;
}

/**
* Returns `true` if the certificate is in the trusted list, otherwise `false`
* @param cert A certificate that is expected to be in the trusted list
* @param trustedList List of trusted certificates
* @returns
*/
function isTrusted(cert: Certificate, trustedList: Certificate[]): boolean {
for (let i = 0; i < trustedList.length; i++) {
if (pvtsutils.BufferSourceConverter.isEqual(cert.tbsView, trustedList[i].tbsView)) {
return true;
}
}

return false;
}

/**
* Represents a chain-building engine for {@link Certificate} certificates.
*
Expand Down Expand Up @@ -349,6 +391,10 @@ export class CertificateChainValidationEngine {
return unique;
}

if (isTrusted(certificate, this.trustedCerts)) {
return [[certificate]];
}

const findIssuerResult = await this.findIssuer(certificate, this, crypto);
if (findIssuerResult.length === 0) {
throw new Error("No valid certificate paths found");
Expand Down Expand Up @@ -666,12 +712,7 @@ export class CertificateChainValidationEngine {
}
} else {
if (passedWhenNotRevValues === false) {
// TODO use CertificateChainValidationError
throw {
result: false,
resultCode: 11,
resultMessage: `No revocation values found for one of certificates: ${crlResult.statusMessage}`
};
throw new ChainValidationError(ChainValidationCode.noRevocation, `No revocation values found for one of certificates: ${crlResult.statusMessage}`);
}
}
} else {
Expand Down Expand Up @@ -704,11 +745,7 @@ export class CertificateChainValidationEngine {
}

if (extensionFound) {
throw {
result: false,
resultCode: 11,
resultMessage: `No revocation values found for one of certificates: ${crlResult.statusMessage}`
};
throw new ChainValidationError(ChainValidationCode.noRevocation, `No revocation values found for one of certificates: ${crlResult.statusMessage}`);
}
}
//#endregion
Expand Down Expand Up @@ -761,19 +798,17 @@ export class CertificateChainValidationEngine {
}
//#endregion

const leafCert = localCerts[localCerts.length - 1];

//#region Initial variables
let result;
const certificatePath = [localCerts[localCerts.length - 1]]; // The "end entity" certificate must be the least in CERTS array
const certificatePath = [leafCert]; // The "end entity" certificate must be the least in CERTS array
//#endregion

//#region Build path for "end entity" certificate
result = await buildPath(localCerts[localCerts.length - 1], crypto);
result = await buildPath(leafCert, crypto);
if (result.length === 0) {
throw {
result: false,
resultCode: 60,
resultMessage: "Unable to find certificate path"
};
throw new ChainValidationError(ChainValidationCode.noPath, "Unable to find certificate path");
}
//#endregion

Expand Down Expand Up @@ -802,12 +837,7 @@ export class CertificateChainValidationEngine {
}

if (result.length === 0) {
// TODO use error
throw {
result: false,
resultCode: 97,
resultMessage: "No valid certificate paths found"
};
throw new ChainValidationError(ChainValidationCode.noValidPath, "No valid certificate paths found");
}
//#endregion

Expand Down Expand Up @@ -1764,26 +1794,33 @@ export class CertificateChainValidationEngine {

return policyResult;
//#endregion
}
catch (error) {
// TODO check error
if (error instanceof Object) {
if ("resultMessage" in error)
return error;

if ("message" in error) {
} catch (error) {
if (error instanceof Error) {
if (error instanceof ChainValidationError) {
return {
result: false,
resultCode: -1,
resultMessage: (error as Error).message
resultCode: error.code,
resultMessage: error.message,
error: error,
};
}

return {
result: false,
resultCode: ChainValidationCode.unknown,
resultMessage: error.message,
error: error,
};
}

if (error && typeof error === "object" && "resultMessage" in error) {
return error as CertificateChainValidationEngineVerifyResult;
}

return {
result: false,
resultCode: -1,
resultMessage: error as string,
resultMessage: `${error}`,
};
}
}
Expand Down
30 changes: 28 additions & 2 deletions test/NISTPKITS.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1102,13 +1102,12 @@ function simpleVerification(params: {
crls
});

const result = await certChain.verify(params.verifyParameters || {});
if (params.successExpected) {
const result = await certChain.verify(params.verifyParameters || {});
if (!result.result) {
throw new Error(`Successfull verification expected, but FAILED return: ${result.resultMessage}`);
}
} else {
const result = await certChain.verify(params.verifyParameters || {});
if (result.result)
throw new Error("Fail on verification expected, but SUCCESS return");
}
Expand Down Expand Up @@ -1211,6 +1210,33 @@ context("NIST PKITS tests", () => {
],
successExpected: false
}));

it("4.1.7 Valid Signatures Trusted Intermediate", simpleVerification({
trustedCertificates: [
"GoodCACert.crt",
],
certificates: [
"ValidCertificatePathTest1EE.crt"
],
crls: [
"GoodCACRL.crl",
],
successExpected: true,
}));

it("4.1.8 Inalid Signatures Trusted Intermediate no CRL", simpleVerification({
trustedCertificates: [
"GoodCACert.crt",
],
certificates: [
"ValidCertificatePathTest1EE.crt"
],
crls: [
"TrustAnchorRootCRL.crl",
],
successExpected: false,
}));

});
//#endregion

Expand Down

0 comments on commit 2e990f9

Please sign in to comment.