feat: subject alternative name policy enforcement

This commit is contained in:
Sheen Capadngan
2024-08-16 17:24:33 +08:00
parent b9bd518aa6
commit 0961d2f1c6
10 changed files with 106 additions and 46 deletions
@@ -1096,17 +1096,6 @@ export const certificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
}
if (certificateTemplate) {
validateCertificateDetailsAgainstTemplate(
{
commonName,
notBeforeDate,
notAfterDate
},
certificateTemplate
);
}
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
@@ -1136,11 +1125,13 @@ export const certificateAuthorityServiceFactory = ({
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
];
let altNamesArray: {
type: "email" | "dns";
value: string;
}[] = [];
if (altNames) {
const altNamesArray: {
type: "email" | "dns";
value: string;
}[] = altNames
altNamesArray = altNames
.split(",")
.map((name) => name.trim())
.map((altName) => {
@@ -1168,6 +1159,18 @@ export const certificateAuthorityServiceFactory = ({
extensions.push(altNamesExtension);
}
if (certificateTemplate) {
validateCertificateDetailsAgainstTemplate(
{
commonName,
notBeforeDate,
notAfterDate,
altNames: altNamesArray.map((entry) => entry.value)
},
certificateTemplate
);
}
const serialNumber = crypto.randomBytes(32).toString("hex");
const leafCert = await x509.X509CertificateGenerator.create({
serialNumber,
@@ -1345,17 +1348,6 @@ export const certificateAuthorityServiceFactory = ({
message: "A common name (CN) is required in the CSR or as a parameter to this endpoint"
});
if (certificateTemplate) {
validateCertificateDetailsAgainstTemplate(
{
commonName: cn,
notBeforeDate,
notAfterDate
},
certificateTemplate
);
}
const { caPrivateKey } = await getCaCredentials({
caId: ca.id,
certificateAuthorityDAL,
@@ -1371,11 +1363,12 @@ export const certificateAuthorityServiceFactory = ({
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
];
let altNamesArray: {
type: "email" | "dns";
value: string;
}[] = [];
if (altNames) {
const altNamesArray: {
type: "email" | "dns";
value: string;
}[] = altNames
altNamesArray = altNames
.split(",")
.map((name) => name.trim())
.map((altName) => {
@@ -1403,6 +1396,18 @@ export const certificateAuthorityServiceFactory = ({
extensions.push(altNamesExtension);
}
if (certificateTemplate) {
validateCertificateDetailsAgainstTemplate(
{
commonName: cn,
notBeforeDate,
notAfterDate,
altNames: altNamesArray.map((entry) => entry.value)
},
certificateTemplate
);
}
const serialNumber = crypto.randomBytes(32).toString("hex");
const leafCert = await x509.X509CertificateGenerator.create({
serialNumber,
@@ -1,5 +1,6 @@
import ms from "ms";
import { TCertificateTemplates } from "@app/db/schemas";
import { BadRequestError } from "@app/lib/errors";
export const validateCertificateDetailsAgainstTemplate = (
@@ -7,11 +8,9 @@ export const validateCertificateDetailsAgainstTemplate = (
commonName: string;
notBeforeDate: Date;
notAfterDate: Date;
altNames: string[];
},
template: {
commonName: string;
ttl: string;
}
template: TCertificateTemplates
) => {
const commonNameRegex = new RegExp(template.commonName);
if (!commonNameRegex.test(cert.commonName)) {
@@ -25,4 +24,13 @@ export const validateCertificateDetailsAgainstTemplate = (
message: "Invalid validity date based on template policy"
});
}
const subjectAlternativeNameRegex = new RegExp(template.subjectAlternativeName);
cert.altNames.forEach((altName) => {
if (!subjectAlternativeNameRegex.test(altName)) {
throw new BadRequestError({
message: "Invalid subject alternative name based on template policy"
});
}
});
};
@@ -30,6 +30,7 @@ export const certificateTemplateServiceFactory = ({
caId,
name,
commonName,
subjectAlternativeName,
ttl,
actorId,
actorAuthMethod,
@@ -59,6 +60,7 @@ export const certificateTemplateServiceFactory = ({
caId,
name,
commonName,
subjectAlternativeName,
ttl
});
@@ -70,6 +72,7 @@ export const certificateTemplateServiceFactory = ({
caId,
name,
commonName,
subjectAlternativeName,
ttl,
actorId,
actorAuthMethod,
@@ -108,6 +111,7 @@ export const certificateTemplateServiceFactory = ({
const updatedCertTemplate = await certificateTemplateDAL.updateById(certTemplate.id, {
caId,
commonName,
subjectAlternativeName,
name,
ttl
});
@@ -4,6 +4,7 @@ export type TCreateCertTemplateDTO = {
caId: string;
name: string;
commonName: string;
subjectAlternativeName: string;
ttl: string;
} & Omit<TProjectPermission, "projectId">;
@@ -12,6 +13,7 @@ export type TUpdateCertTemplateDTO = {
caId?: string;
name?: string;
commonName?: string;
subjectAlternativeName?: string;
ttl?: string;
} & Omit<TProjectPermission, "projectId">;