feat: added custom key usages support for sign endpoint

This commit is contained in:
Sheen Capadngan
2024-09-11 20:26:33 +08:00
parent 4e6b289e1b
commit c1f61f2db4
4 changed files with 56 additions and 5 deletions
@@ -654,7 +654,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
.refine((val) => ms(val) > 0, "TTL must be a positive number") .refine((val) => ms(val) > 0, "TTL must be a positive number")
.describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.ttl), .describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.ttl),
notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notBefore), notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notBefore),
notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notAfter) notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notAfter),
keyUsages: z.nativeEnum(CertKeyUsage).array().optional()
}) })
.refine( .refine(
(data) => { (data) => {
@@ -178,7 +178,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
.refine((val) => ms(val) > 0, "TTL must be a positive number") .refine((val) => ms(val) > 0, "TTL must be a positive number")
.describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.ttl), .describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.ttl),
notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notBefore), notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notBefore),
notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notAfter) notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.notAfter),
keyUsages: z.nativeEnum(CertKeyUsage).array().optional()
}) })
.refine( .refine(
(data) => { (data) => {
@@ -1346,7 +1346,8 @@ export const certificateAuthorityServiceFactory = ({
altNames, altNames,
ttl, ttl,
notBefore, notBefore,
notAfter notAfter,
keyUsages
} = dto; } = dto;
let collectionId = pkiCollectionId; let collectionId = pkiCollectionId;
@@ -1466,12 +1467,57 @@ export const certificateAuthorityServiceFactory = ({
}); });
const extensions: x509.Extension[] = [ const extensions: x509.Extension[] = [
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment, true),
new x509.BasicConstraintsExtension(false), new x509.BasicConstraintsExtension(false),
await x509.AuthorityKeyIdentifierExtension.create(caCertObj, false), await x509.AuthorityKeyIdentifierExtension.create(caCertObj, false),
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey) await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
]; ];
const csrKeyUsageExtension = csrObj.getExtension("2.5.29.15") as x509.KeyUsagesExtension;
let csrKeyUsages: CertKeyUsage[] = [];
if (csrKeyUsageExtension) {
csrKeyUsages = Object.values(CertKeyUsage).filter(
(keyUsage) => (x509.KeyUsageFlags[keyUsage] & csrKeyUsageExtension.usages) !== 0
);
}
let selectedKeyUsages: CertKeyUsage[] = keyUsages ?? [];
if (keyUsages === undefined && !certificateTemplate) {
if (csrKeyUsageExtension) {
selectedKeyUsages = csrKeyUsages;
} else {
selectedKeyUsages = [CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT];
}
}
if (keyUsages === undefined && certificateTemplate) {
if (csrKeyUsageExtension) {
const validKeyUsages = certificateTemplate.keyUsages || [];
if (csrKeyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
throw new BadRequestError({
message: "Invalid key usage value for certificate"
});
}
selectedKeyUsages = csrKeyUsages;
} else {
selectedKeyUsages = (certificateTemplate.keyUsages ?? []) as CertKeyUsage[];
}
}
if (keyUsages?.length && certificateTemplate) {
const validKeyUsages = certificateTemplate.keyUsages || [];
if (keyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
throw new BadRequestError({
message: "Invalid key usage value for certificate"
});
}
selectedKeyUsages = keyUsages;
}
const keyUsagesBitValue = selectedKeyUsages.reduce((accum, keyUsage) => accum | x509.KeyUsageFlags[keyUsage], 0);
if (keyUsagesBitValue) {
extensions.push(new x509.KeyUsagesExtension(keyUsagesBitValue, true));
}
let altNamesFromCsr: string = ""; let altNamesFromCsr: string = "";
let altNamesArray: { let altNamesArray: {
type: "email" | "dns"; type: "email" | "dns";
@@ -1567,7 +1613,8 @@ export const certificateAuthorityServiceFactory = ({
altNames: altNamesFromCsr || altNames, altNames: altNamesFromCsr || altNames,
serialNumber, serialNumber,
notBefore: notBeforeDate, notBefore: notBeforeDate,
notAfter: notAfterDate notAfter: notAfterDate,
keyUsages: selectedKeyUsages
}, },
tx tx
); );
@@ -113,6 +113,7 @@ export type TSignCertFromCaDTO =
ttl?: string; ttl?: string;
notBefore?: string; notBefore?: string;
notAfter?: string; notAfter?: string;
keyUsages?: CertKeyUsage[];
} }
| ({ | ({
isInternal: false; isInternal: false;
@@ -126,6 +127,7 @@ export type TSignCertFromCaDTO =
ttl: string; ttl: string;
notBefore?: string; notBefore?: string;
notAfter?: string; notAfter?: string;
keyUsages?: CertKeyUsage[];
} & Omit<TProjectPermission, "projectId">); } & Omit<TProjectPermission, "projectId">);
export type TGetCaCertificateTemplatesDTO = { export type TGetCaCertificateTemplatesDTO = {