mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 19:28:33 +00:00
feat: added support for custom extended key usages
This commit is contained in:
@@ -7,7 +7,7 @@ import { CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
|
|||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
||||||
import { CaRenewalType, CaStatus, CaType } from "@app/services/certificate-authority/certificate-authority-types";
|
import { CaRenewalType, CaStatus, CaType } from "@app/services/certificate-authority/certificate-authority-types";
|
||||||
import {
|
import {
|
||||||
validateAltNamesField,
|
validateAltNamesField,
|
||||||
@@ -574,7 +574,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.ttl),
|
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.ttl),
|
||||||
notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notBefore),
|
notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notBefore),
|
||||||
notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notAfter),
|
notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notAfter),
|
||||||
keyUsages: z.nativeEnum(CertKeyUsage).array().optional()
|
keyUsages: z.nativeEnum(CertKeyUsage).array().optional(),
|
||||||
|
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional()
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
@@ -655,7 +656,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
.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()
|
keyUsages: z.nativeEnum(CertKeyUsage).array().optional(),
|
||||||
|
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional()
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { CERTIFICATE_AUTHORITIES, CERTIFICATES } from "@app/lib/api-docs";
|
|||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { CertKeyUsage, CrlReason } from "@app/services/certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyUsage, CrlReason } from "@app/services/certificate/certificate-types";
|
||||||
import {
|
import {
|
||||||
validateAltNamesField,
|
validateAltNamesField,
|
||||||
validateCaDateField
|
validateCaDateField
|
||||||
@@ -87,7 +87,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.ttl),
|
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.ttl),
|
||||||
notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notBefore),
|
notBefore: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notBefore),
|
||||||
notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notAfter),
|
notAfter: validateCaDateField.optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.notAfter),
|
||||||
keyUsages: z.nativeEnum(CertKeyUsage).array().optional()
|
keyUsages: z.nativeEnum(CertKeyUsage).array().optional(),
|
||||||
|
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional()
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
@@ -179,7 +180,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
.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()
|
keyUsages: z.nativeEnum(CertKeyUsage).array().optional(),
|
||||||
|
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional()
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { CERTIFICATE_TEMPLATES } from "@app/lib/api-docs";
|
|||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { CertKeyUsage } from "@app/services/certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
||||||
import { sanitizedCertificateTemplate } from "@app/services/certificate-template/certificate-template-schema";
|
import { sanitizedCertificateTemplate } from "@app/services/certificate-template/certificate-template-schema";
|
||||||
import { validateTemplateRegexField } from "@app/services/certificate-template/certificate-template-validators";
|
import { validateTemplateRegexField } from "@app/services/certificate-template/certificate-template-validators";
|
||||||
|
|
||||||
@@ -80,7 +80,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid
|
|||||||
.nativeEnum(CertKeyUsage)
|
.nativeEnum(CertKeyUsage)
|
||||||
.array()
|
.array()
|
||||||
.optional()
|
.optional()
|
||||||
.default([CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT])
|
.default([CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT]),
|
||||||
|
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional().default([])
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: sanitizedCertificateTemplate
|
200: sanitizedCertificateTemplate
|
||||||
@@ -137,7 +138,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid
|
|||||||
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
||||||
.optional()
|
.optional()
|
||||||
.describe(CERTIFICATE_TEMPLATES.UPDATE.ttl),
|
.describe(CERTIFICATE_TEMPLATES.UPDATE.ttl),
|
||||||
keyUsages: z.nativeEnum(CertKeyUsage).array().optional()
|
keyUsages: z.nativeEnum(CertKeyUsage).array().optional(),
|
||||||
|
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional()
|
||||||
}),
|
}),
|
||||||
params: z.object({
|
params: z.object({
|
||||||
certificateTemplateId: z.string().describe(CERTIFICATE_TEMPLATES.UPDATE.certificateTemplateId)
|
certificateTemplateId: z.string().describe(CERTIFICATE_TEMPLATES.UPDATE.certificateTemplateId)
|
||||||
|
|||||||
@@ -19,7 +19,13 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
|
|||||||
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||||
|
|
||||||
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
||||||
import { CertKeyAlgorithm, CertKeyUsage, CertStatus } from "../certificate/certificate-types";
|
import {
|
||||||
|
CertExtendedKeyUsage,
|
||||||
|
CertExtendedKeyUsageOIDToName,
|
||||||
|
CertKeyAlgorithm,
|
||||||
|
CertKeyUsage,
|
||||||
|
CertStatus
|
||||||
|
} from "../certificate/certificate-types";
|
||||||
import { TCertificateTemplateDALFactory } from "../certificate-template/certificate-template-dal";
|
import { TCertificateTemplateDALFactory } from "../certificate-template/certificate-template-dal";
|
||||||
import { validateCertificateDetailsAgainstTemplate } from "../certificate-template/certificate-template-fns";
|
import { validateCertificateDetailsAgainstTemplate } from "../certificate-template/certificate-template-fns";
|
||||||
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
|
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
|
||||||
@@ -1053,7 +1059,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
}: TIssueCertFromCaDTO) => {
|
}: TIssueCertFromCaDTO) => {
|
||||||
let ca: TCertificateAuthorities | undefined;
|
let ca: TCertificateAuthorities | undefined;
|
||||||
let certificateTemplate: TCertificateTemplates | undefined;
|
let certificateTemplate: TCertificateTemplates | undefined;
|
||||||
@@ -1170,7 +1177,14 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const distributionPointUrl = `${appCfg.SITE_URL}/api/v1/pki/crl/${caCrl.id}`;
|
const distributionPointUrl = `${appCfg.SITE_URL}/api/v1/pki/crl/${caCrl.id}`;
|
||||||
|
const extensions: x509.Extension[] = [
|
||||||
|
new x509.BasicConstraintsExtension(false),
|
||||||
|
new x509.CRLDistributionPointsExtension([distributionPointUrl]),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(caCertObj, false),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
|
||||||
|
];
|
||||||
|
|
||||||
|
// handle key usages
|
||||||
let selectedKeyUsages: CertKeyUsage[] = keyUsages ?? [];
|
let selectedKeyUsages: CertKeyUsage[] = keyUsages ?? [];
|
||||||
if (keyUsages === undefined && !certificateTemplate) {
|
if (keyUsages === undefined && !certificateTemplate) {
|
||||||
selectedKeyUsages = [CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT];
|
selectedKeyUsages = [CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT];
|
||||||
@@ -1184,24 +1198,42 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const validKeyUsages = certificateTemplate.keyUsages || [];
|
const validKeyUsages = certificateTemplate.keyUsages || [];
|
||||||
if (keyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
|
if (keyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Invalid key usage value for certificate"
|
message: "Invalid key usage value based on template policy"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
selectedKeyUsages = keyUsages;
|
selectedKeyUsages = keyUsages;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extensions: x509.Extension[] = [
|
|
||||||
new x509.BasicConstraintsExtension(false),
|
|
||||||
new x509.CRLDistributionPointsExtension([distributionPointUrl]),
|
|
||||||
await x509.AuthorityKeyIdentifierExtension.create(caCertObj, false),
|
|
||||||
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
|
|
||||||
];
|
|
||||||
|
|
||||||
const keyUsagesBitValue = selectedKeyUsages.reduce((accum, keyUsage) => accum | x509.KeyUsageFlags[keyUsage], 0);
|
const keyUsagesBitValue = selectedKeyUsages.reduce((accum, keyUsage) => accum | x509.KeyUsageFlags[keyUsage], 0);
|
||||||
if (keyUsagesBitValue) {
|
if (keyUsagesBitValue) {
|
||||||
extensions.push(new x509.KeyUsagesExtension(keyUsagesBitValue, true));
|
extensions.push(new x509.KeyUsagesExtension(keyUsagesBitValue, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle extended key usages
|
||||||
|
let selectedExtendedKeyUsages: CertExtendedKeyUsage[] = extendedKeyUsages ?? [];
|
||||||
|
if (extendedKeyUsages === undefined && certificateTemplate) {
|
||||||
|
selectedExtendedKeyUsages = (certificateTemplate.extendedKeyUsages ?? []) as CertExtendedKeyUsage[];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extendedKeyUsages?.length && certificateTemplate) {
|
||||||
|
const validExtendedKeyUsages = certificateTemplate.extendedKeyUsages || [];
|
||||||
|
if (extendedKeyUsages.some((eku) => !validExtendedKeyUsages.includes(eku))) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Invalid extended key usage value based on template policy"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
selectedExtendedKeyUsages = extendedKeyUsages;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedExtendedKeyUsages.length) {
|
||||||
|
extensions.push(
|
||||||
|
new x509.ExtendedKeyUsageExtension(
|
||||||
|
selectedExtendedKeyUsages.map((eku) => x509.ExtendedKeyUsage[eku]),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let altNamesArray: {
|
let altNamesArray: {
|
||||||
type: "email" | "dns";
|
type: "email" | "dns";
|
||||||
value: string;
|
value: string;
|
||||||
@@ -1284,7 +1316,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
serialNumber,
|
serialNumber,
|
||||||
notBefore: notBeforeDate,
|
notBefore: notBeforeDate,
|
||||||
notAfter: notAfterDate,
|
notAfter: notAfterDate,
|
||||||
keyUsages: selectedKeyUsages
|
keyUsages: selectedKeyUsages,
|
||||||
|
extendedKeyUsages: selectedExtendedKeyUsages
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -1347,7 +1380,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
ttl,
|
ttl,
|
||||||
notBefore,
|
notBefore,
|
||||||
notAfter,
|
notAfter,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
} = dto;
|
} = dto;
|
||||||
|
|
||||||
let collectionId = pkiCollectionId;
|
let collectionId = pkiCollectionId;
|
||||||
@@ -1472,6 +1506,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
|
await x509.SubjectKeyIdentifierExtension.create(csrObj.publicKey)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// handle key usages
|
||||||
const csrKeyUsageExtension = csrObj.getExtension("2.5.29.15") as x509.KeyUsagesExtension;
|
const csrKeyUsageExtension = csrObj.getExtension("2.5.29.15") as x509.KeyUsagesExtension;
|
||||||
let csrKeyUsages: CertKeyUsage[] = [];
|
let csrKeyUsages: CertKeyUsage[] = [];
|
||||||
if (csrKeyUsageExtension) {
|
if (csrKeyUsageExtension) {
|
||||||
@@ -1494,7 +1529,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const validKeyUsages = certificateTemplate.keyUsages || [];
|
const validKeyUsages = certificateTemplate.keyUsages || [];
|
||||||
if (csrKeyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
|
if (csrKeyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Invalid key usage value for certificate"
|
message: "Invalid key usage value based on template policy"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
selectedKeyUsages = csrKeyUsages;
|
selectedKeyUsages = csrKeyUsages;
|
||||||
@@ -1507,7 +1542,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const validKeyUsages = certificateTemplate.keyUsages || [];
|
const validKeyUsages = certificateTemplate.keyUsages || [];
|
||||||
if (keyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
|
if (keyUsages.some((keyUsage) => !validKeyUsages.includes(keyUsage))) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Invalid key usage value for certificate"
|
message: "Invalid key usage value based on template policy"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
selectedKeyUsages = keyUsages;
|
selectedKeyUsages = keyUsages;
|
||||||
@@ -1518,6 +1553,53 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
extensions.push(new x509.KeyUsagesExtension(keyUsagesBitValue, true));
|
extensions.push(new x509.KeyUsagesExtension(keyUsagesBitValue, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle extended key usages
|
||||||
|
const csrExtendedKeyUsageExtension = csrObj.getExtension("2.5.29.37") as x509.ExtendedKeyUsageExtension;
|
||||||
|
let csrExtendedKeyUsages: CertExtendedKeyUsage[] = [];
|
||||||
|
if (csrExtendedKeyUsageExtension) {
|
||||||
|
csrExtendedKeyUsages = csrExtendedKeyUsageExtension.usages.map(
|
||||||
|
(ekuOid) => CertExtendedKeyUsageOIDToName[ekuOid as string]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectedExtendedKeyUsages: CertExtendedKeyUsage[] = extendedKeyUsages ?? [];
|
||||||
|
if (extendedKeyUsages === undefined && !certificateTemplate && csrExtendedKeyUsageExtension) {
|
||||||
|
selectedExtendedKeyUsages = csrExtendedKeyUsages;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extendedKeyUsages === undefined && certificateTemplate) {
|
||||||
|
if (csrExtendedKeyUsageExtension) {
|
||||||
|
const validExtendedKeyUsages = certificateTemplate.extendedKeyUsages || [];
|
||||||
|
if (csrExtendedKeyUsages.some((eku) => !validExtendedKeyUsages.includes(eku))) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Invalid extended key usage value based on template policy"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
selectedExtendedKeyUsages = csrExtendedKeyUsages;
|
||||||
|
} else {
|
||||||
|
selectedExtendedKeyUsages = (certificateTemplate.extendedKeyUsages ?? []) as CertExtendedKeyUsage[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extendedKeyUsages?.length && certificateTemplate) {
|
||||||
|
const validExtendedKeyUsages = certificateTemplate.extendedKeyUsages || [];
|
||||||
|
if (extendedKeyUsages.some((keyUsage) => !validExtendedKeyUsages.includes(keyUsage))) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Invalid extended key usage value based on template policy"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
selectedExtendedKeyUsages = extendedKeyUsages;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedExtendedKeyUsages.length) {
|
||||||
|
extensions.push(
|
||||||
|
new x509.ExtendedKeyUsageExtension(
|
||||||
|
selectedExtendedKeyUsages.map((eku) => x509.ExtendedKeyUsage[eku]),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let altNamesFromCsr: string = "";
|
let altNamesFromCsr: string = "";
|
||||||
let altNamesArray: {
|
let altNamesArray: {
|
||||||
type: "email" | "dns";
|
type: "email" | "dns";
|
||||||
@@ -1614,7 +1696,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
serialNumber,
|
serialNumber,
|
||||||
notBefore: notBeforeDate,
|
notBefore: notBeforeDate,
|
||||||
notAfter: notAfterDate,
|
notAfter: notAfterDate,
|
||||||
keyUsages: selectedKeyUsages
|
keyUsages: selectedKeyUsages,
|
||||||
|
extendedKeyUsages: selectedExtendedKeyUsages
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
|||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
||||||
import { CertKeyAlgorithm, CertKeyUsage } from "../certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "../certificate/certificate-types";
|
||||||
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
|
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
|
||||||
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
||||||
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";
|
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";
|
||||||
@@ -98,6 +98,7 @@ export type TIssueCertFromCaDTO = {
|
|||||||
notBefore?: string;
|
notBefore?: string;
|
||||||
notAfter?: string;
|
notAfter?: string;
|
||||||
keyUsages?: CertKeyUsage[];
|
keyUsages?: CertKeyUsage[];
|
||||||
|
extendedKeyUsages?: CertExtendedKeyUsage[];
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TSignCertFromCaDTO =
|
export type TSignCertFromCaDTO =
|
||||||
@@ -114,6 +115,7 @@ export type TSignCertFromCaDTO =
|
|||||||
notBefore?: string;
|
notBefore?: string;
|
||||||
notAfter?: string;
|
notAfter?: string;
|
||||||
keyUsages?: CertKeyUsage[];
|
keyUsages?: CertKeyUsage[];
|
||||||
|
extendedKeyUsages?: CertExtendedKeyUsage[];
|
||||||
}
|
}
|
||||||
| ({
|
| ({
|
||||||
isInternal: false;
|
isInternal: false;
|
||||||
@@ -128,6 +130,7 @@ export type TSignCertFromCaDTO =
|
|||||||
notBefore?: string;
|
notBefore?: string;
|
||||||
notAfter?: string;
|
notAfter?: string;
|
||||||
keyUsages?: CertKeyUsage[];
|
keyUsages?: CertKeyUsage[];
|
||||||
|
extendedKeyUsages?: CertExtendedKeyUsage[];
|
||||||
} & Omit<TProjectPermission, "projectId">);
|
} & Omit<TProjectPermission, "projectId">);
|
||||||
|
|
||||||
export type TGetCaCertificateTemplatesDTO = {
|
export type TGetCaCertificateTemplatesDTO = {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ export const sanitizedCertificateTemplate = CertificateTemplatesSchema.pick({
|
|||||||
subjectAlternativeName: true,
|
subjectAlternativeName: true,
|
||||||
pkiCollectionId: true,
|
pkiCollectionId: true,
|
||||||
ttl: true,
|
ttl: true,
|
||||||
keyUsages: true
|
keyUsages: true,
|
||||||
|
extendedKeyUsages: true
|
||||||
}).merge(
|
}).merge(
|
||||||
z.object({
|
z.object({
|
||||||
projectId: z.string(),
|
projectId: z.string(),
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
}: TCreateCertTemplateDTO) => {
|
}: TCreateCertTemplateDTO) => {
|
||||||
const ca = await certificateAuthorityDAL.findById(caId);
|
const ca = await certificateAuthorityDAL.findById(caId);
|
||||||
if (!ca) {
|
if (!ca) {
|
||||||
@@ -88,7 +89,8 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
ttl,
|
ttl,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -116,7 +118,8 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
}: TUpdateCertTemplateDTO) => {
|
}: TUpdateCertTemplateDTO) => {
|
||||||
const certTemplate = await certificateTemplateDAL.getById(id);
|
const certTemplate = await certificateTemplateDAL.getById(id);
|
||||||
if (!certTemplate) {
|
if (!certTemplate) {
|
||||||
@@ -157,7 +160,8 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
name,
|
name,
|
||||||
ttl,
|
ttl,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
import { CertKeyUsage } from "@app/services/certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
||||||
|
|
||||||
export type TCreateCertTemplateDTO = {
|
export type TCreateCertTemplateDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
@@ -9,6 +9,7 @@ export type TCreateCertTemplateDTO = {
|
|||||||
subjectAlternativeName: string;
|
subjectAlternativeName: string;
|
||||||
ttl: string;
|
ttl: string;
|
||||||
keyUsages: CertKeyUsage[];
|
keyUsages: CertKeyUsage[];
|
||||||
|
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TUpdateCertTemplateDTO = {
|
export type TUpdateCertTemplateDTO = {
|
||||||
@@ -20,6 +21,7 @@ export type TUpdateCertTemplateDTO = {
|
|||||||
subjectAlternativeName?: string;
|
subjectAlternativeName?: string;
|
||||||
ttl?: string;
|
ttl?: string;
|
||||||
keyUsages?: CertKeyUsage[];
|
keyUsages?: CertKeyUsage[];
|
||||||
|
extendedKeyUsages?: CertExtendedKeyUsage[];
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TGetCertTemplateDTO = {
|
export type TGetCertTemplateDTO = {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export enum CertStatus {
|
export enum CertStatus {
|
||||||
@@ -24,6 +26,24 @@ export enum CertKeyUsage {
|
|||||||
DECIPHER_ONLY = "decipherOnly"
|
DECIPHER_ONLY = "decipherOnly"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CertExtendedKeyUsage {
|
||||||
|
CLIENT_AUTH = "clientAuth",
|
||||||
|
SERVER_AUTH = "serverAuth",
|
||||||
|
CODE_SIGNING = "codeSigning",
|
||||||
|
EMAIL_PROTECTION = "emailProtection",
|
||||||
|
TIMESTAMPING = "timeStamping",
|
||||||
|
OCSP_SIGNING = "ocspSigning"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CertExtendedKeyUsageOIDToName: Record<string, CertExtendedKeyUsage> = {
|
||||||
|
[x509.ExtendedKeyUsage.clientAuth]: CertExtendedKeyUsage.CLIENT_AUTH,
|
||||||
|
[x509.ExtendedKeyUsage.serverAuth]: CertExtendedKeyUsage.SERVER_AUTH,
|
||||||
|
[x509.ExtendedKeyUsage.codeSigning]: CertExtendedKeyUsage.CODE_SIGNING,
|
||||||
|
[x509.ExtendedKeyUsage.emailProtection]: CertExtendedKeyUsage.EMAIL_PROTECTION,
|
||||||
|
[x509.ExtendedKeyUsage.ocspSigning]: CertExtendedKeyUsage.OCSP_SIGNING,
|
||||||
|
[x509.ExtendedKeyUsage.timeStamping]: CertExtendedKeyUsage.TIMESTAMPING
|
||||||
|
};
|
||||||
|
|
||||||
export enum CrlReason {
|
export enum CrlReason {
|
||||||
UNSPECIFIED = "UNSPECIFIED",
|
UNSPECIFIED = "UNSPECIFIED",
|
||||||
KEY_COMPROMISE = "KEY_COMPROMISE",
|
KEY_COMPROMISE = "KEY_COMPROMISE",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CertKeyAlgorithm } from "../certificates/enums";
|
import { CertKeyAlgorithm } from "../certificates/enums";
|
||||||
import { CertKeyUsage } from "../certificates/types";
|
import { CertExtendedKeyUsage, CertKeyUsage } from "../certificates/types";
|
||||||
import { CaRenewalType, CaStatus, CaType } from "./enums";
|
import { CaRenewalType, CaStatus, CaType } from "./enums";
|
||||||
|
|
||||||
export type TCertificateAuthority = {
|
export type TCertificateAuthority = {
|
||||||
@@ -93,6 +93,7 @@ export type TCreateCertificateDTO = {
|
|||||||
notBefore?: string;
|
notBefore?: string;
|
||||||
notAfter?: string;
|
notAfter?: string;
|
||||||
keyUsages: CertKeyUsage[];
|
keyUsages: CertKeyUsage[];
|
||||||
|
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCreateCertificateResponse = {
|
export type TCreateCertificateResponse = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CertKeyUsage } from "../certificates/types";
|
import { CertExtendedKeyUsage, CertKeyUsage } from "../certificates/types";
|
||||||
|
|
||||||
export type TCertificateTemplate = {
|
export type TCertificateTemplate = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -11,6 +11,7 @@ export type TCertificateTemplate = {
|
|||||||
subjectAlternativeName: string;
|
subjectAlternativeName: string;
|
||||||
ttl: string;
|
ttl: string;
|
||||||
keyUsages: CertKeyUsage[];
|
keyUsages: CertKeyUsage[];
|
||||||
|
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCreateCertificateTemplateDTO = {
|
export type TCreateCertificateTemplateDTO = {
|
||||||
@@ -22,6 +23,7 @@ export type TCreateCertificateTemplateDTO = {
|
|||||||
ttl: string;
|
ttl: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
keyUsages: CertKeyUsage[];
|
keyUsages: CertKeyUsage[];
|
||||||
|
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUpdateCertificateTemplateDTO = {
|
export type TUpdateCertificateTemplateDTO = {
|
||||||
@@ -34,6 +36,7 @@ export type TUpdateCertificateTemplateDTO = {
|
|||||||
ttl?: string;
|
ttl?: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
keyUsages?: CertKeyUsage[];
|
keyUsages?: CertKeyUsage[];
|
||||||
|
extendedKeyUsages?: CertExtendedKeyUsage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TDeleteCertificateTemplateDTO = {
|
export type TDeleteCertificateTemplateDTO = {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export type TCertificate = {
|
|||||||
notBefore: string;
|
notBefore: string;
|
||||||
notAfter: string;
|
notAfter: string;
|
||||||
keyUsages: CertKeyUsage[];
|
keyUsages: CertKeyUsage[];
|
||||||
|
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TDeleteCertDTO = {
|
export type TDeleteCertDTO = {
|
||||||
@@ -48,3 +49,21 @@ export const KEY_USAGES_OPTIONS = [
|
|||||||
{ value: CertKeyUsage.ENCIPHER_ONLY, label: "Encipher Only" },
|
{ value: CertKeyUsage.ENCIPHER_ONLY, label: "Encipher Only" },
|
||||||
{ value: CertKeyUsage.DECIPHER_ONLY, label: "Decipher Only" }
|
{ value: CertKeyUsage.DECIPHER_ONLY, label: "Decipher Only" }
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
export enum CertExtendedKeyUsage {
|
||||||
|
CLIENT_AUTH = "clientAuth",
|
||||||
|
SERVER_AUTH = "serverAuth",
|
||||||
|
CODE_SIGNING = "codeSigning",
|
||||||
|
EMAIL_PROTECTION = "emailProtection",
|
||||||
|
TIMESTAMPING = "timeStamping",
|
||||||
|
OCSP_SIGNING = "ocspSigning"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EXTENDED_KEY_USAGES_OPTIONS = [
|
||||||
|
{ value: CertExtendedKeyUsage.CLIENT_AUTH, label: "Client Auth" },
|
||||||
|
{ value: CertExtendedKeyUsage.SERVER_AUTH, label: "Server Auth" },
|
||||||
|
{ value: CertExtendedKeyUsage.EMAIL_PROTECTION, label: "Email Protection" },
|
||||||
|
{ value: CertExtendedKeyUsage.OCSP_SIGNING, label: "OCSP Signing" },
|
||||||
|
{ value: CertExtendedKeyUsage.CODE_SIGNING, label: "Code Signing" },
|
||||||
|
{ value: CertExtendedKeyUsage.TIMESTAMPING, label: "Timestamping" }
|
||||||
|
] as const;
|
||||||
|
|||||||
+67
-6
@@ -33,7 +33,12 @@ import {
|
|||||||
useListWorkspacePkiCollections
|
useListWorkspacePkiCollections
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||||
import { CertKeyUsage, KEY_USAGES_OPTIONS } from "@app/hooks/api/certificates/types";
|
import {
|
||||||
|
CertExtendedKeyUsage,
|
||||||
|
CertKeyUsage,
|
||||||
|
EXTENDED_KEY_USAGES_OPTIONS,
|
||||||
|
KEY_USAGES_OPTIONS
|
||||||
|
} from "@app/hooks/api/certificates/types";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { CertificateContent } from "./CertificateContent";
|
import { CertificateContent } from "./CertificateContent";
|
||||||
@@ -56,6 +61,14 @@ const schema = z.object({
|
|||||||
[CertKeyUsage.CRL_SIGN]: z.boolean().optional(),
|
[CertKeyUsage.CRL_SIGN]: z.boolean().optional(),
|
||||||
[CertKeyUsage.ENCIPHER_ONLY]: z.boolean().optional(),
|
[CertKeyUsage.ENCIPHER_ONLY]: z.boolean().optional(),
|
||||||
[CertKeyUsage.DECIPHER_ONLY]: z.boolean().optional()
|
[CertKeyUsage.DECIPHER_ONLY]: z.boolean().optional()
|
||||||
|
}),
|
||||||
|
extendedKeyUsages: z.object({
|
||||||
|
[CertExtendedKeyUsage.CLIENT_AUTH]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.CODE_SIGNING]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.EMAIL_PROTECTION]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.OCSP_SIGNING]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.SERVER_AUTH]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.TIMESTAMPING]: z.boolean().optional()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -110,7 +123,8 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
keyUsages: {
|
keyUsages: {
|
||||||
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
||||||
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
||||||
}
|
},
|
||||||
|
extendedKeyUsages: {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -131,7 +145,10 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
altNames: cert.altNames,
|
altNames: cert.altNames,
|
||||||
certificateTemplateId: cert.certificateTemplateId ?? CERT_TEMPLATE_NONE_VALUE,
|
certificateTemplateId: cert.certificateTemplateId ?? CERT_TEMPLATE_NONE_VALUE,
|
||||||
ttl: "",
|
ttl: "",
|
||||||
keyUsages: Object.fromEntries(cert.keyUsages.map((name) => [name, true]))
|
keyUsages: Object.fromEntries((cert.keyUsages || []).map((name) => [name, true])),
|
||||||
|
extendedKeyUsages: Object.fromEntries(
|
||||||
|
(cert.extendedKeyUsages || []).map((name) => [name, true])
|
||||||
|
)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
reset({
|
reset({
|
||||||
@@ -144,7 +161,8 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
keyUsages: {
|
keyUsages: {
|
||||||
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
||||||
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
||||||
}
|
},
|
||||||
|
extendedKeyUsages: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [cert]);
|
}, [cert]);
|
||||||
@@ -156,6 +174,10 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
"keyUsages",
|
"keyUsages",
|
||||||
Object.fromEntries(selectedCertTemplate.keyUsages.map((name) => [name, true]))
|
Object.fromEntries(selectedCertTemplate.keyUsages.map((name) => [name, true]))
|
||||||
);
|
);
|
||||||
|
setValue(
|
||||||
|
"extendedKeyUsages",
|
||||||
|
Object.fromEntries(selectedCertTemplate.extendedKeyUsages.map((name) => [name, true]))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [selectedCertTemplate, cert]);
|
}, [selectedCertTemplate, cert]);
|
||||||
|
|
||||||
@@ -166,7 +188,8 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
commonName,
|
commonName,
|
||||||
altNames,
|
altNames,
|
||||||
ttl,
|
ttl,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
}: FormData) => {
|
}: FormData) => {
|
||||||
try {
|
try {
|
||||||
if (!currentWorkspace?.slug) return;
|
if (!currentWorkspace?.slug) return;
|
||||||
@@ -182,7 +205,10 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
ttl,
|
ttl,
|
||||||
keyUsages: Object.entries(keyUsages)
|
keyUsages: Object.entries(keyUsages)
|
||||||
.filter(([, value]) => value)
|
.filter(([, value]) => value)
|
||||||
.map(([key]) => key as CertKeyUsage)
|
.map(([key]) => key as CertKeyUsage),
|
||||||
|
extendedKeyUsages: Object.entries(extendedKeyUsages)
|
||||||
|
.filter(([, value]) => value)
|
||||||
|
.map(([key]) => key as CertExtendedKeyUsage)
|
||||||
});
|
});
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
@@ -440,6 +466,41 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="extendedKeyUsages"
|
||||||
|
render={({ field: { onChange, value }, fieldState: { error } }) => {
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
label="Extended Key Usages"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
>
|
||||||
|
<div className="mt-2 mb-7 grid grid-cols-2 gap-2">
|
||||||
|
{EXTENDED_KEY_USAGES_OPTIONS.map(({ label, value: optionValue }) => {
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
id={optionValue}
|
||||||
|
key={optionValue}
|
||||||
|
className="data-[state=checked]:bg-primary"
|
||||||
|
isDisabled={Boolean(cert)}
|
||||||
|
isChecked={value[optionValue]}
|
||||||
|
onCheckedChange={(state) => {
|
||||||
|
onChange({
|
||||||
|
...value,
|
||||||
|
[optionValue]: state
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Checkbox>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|||||||
+64
-6
@@ -33,7 +33,12 @@ import {
|
|||||||
useUpdateCertTemplate
|
useUpdateCertTemplate
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||||
import { CertKeyUsage, KEY_USAGES_OPTIONS } from "@app/hooks/api/certificates/types";
|
import {
|
||||||
|
CertExtendedKeyUsage,
|
||||||
|
CertKeyUsage,
|
||||||
|
EXTENDED_KEY_USAGES_OPTIONS,
|
||||||
|
KEY_USAGES_OPTIONS
|
||||||
|
} from "@app/hooks/api/certificates/types";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
const validateTemplateRegexField = z
|
const validateTemplateRegexField = z
|
||||||
@@ -63,6 +68,14 @@ const schema = z.object({
|
|||||||
[CertKeyUsage.CRL_SIGN]: z.boolean().optional(),
|
[CertKeyUsage.CRL_SIGN]: z.boolean().optional(),
|
||||||
[CertKeyUsage.ENCIPHER_ONLY]: z.boolean().optional(),
|
[CertKeyUsage.ENCIPHER_ONLY]: z.boolean().optional(),
|
||||||
[CertKeyUsage.DECIPHER_ONLY]: z.boolean().optional()
|
[CertKeyUsage.DECIPHER_ONLY]: z.boolean().optional()
|
||||||
|
}),
|
||||||
|
extendedKeyUsages: z.object({
|
||||||
|
[CertExtendedKeyUsage.CLIENT_AUTH]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.CODE_SIGNING]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.EMAIL_PROTECTION]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.OCSP_SIGNING]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.SERVER_AUTH]: z.boolean().optional(),
|
||||||
|
[CertExtendedKeyUsage.TIMESTAMPING]: z.boolean().optional()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,7 +135,10 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
|
|||||||
subjectAlternativeName: certTemplate.subjectAlternativeName,
|
subjectAlternativeName: certTemplate.subjectAlternativeName,
|
||||||
collectionId: certTemplate.pkiCollectionId ?? undefined,
|
collectionId: certTemplate.pkiCollectionId ?? undefined,
|
||||||
ttl: certTemplate.ttl,
|
ttl: certTemplate.ttl,
|
||||||
keyUsages: Object.fromEntries(certTemplate.keyUsages.map((name) => [name, true]))
|
keyUsages: Object.fromEntries(certTemplate.keyUsages.map((name) => [name, true]) ?? []),
|
||||||
|
extendedKeyUsages: Object.fromEntries(
|
||||||
|
certTemplate.extendedKeyUsages.map((name) => [name, true]) ?? []
|
||||||
|
)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
reset({
|
reset({
|
||||||
@@ -133,7 +149,8 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
|
|||||||
keyUsages: {
|
keyUsages: {
|
||||||
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
||||||
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
||||||
}
|
},
|
||||||
|
extendedKeyUsages: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [certTemplate, ca]);
|
}, [certTemplate, ca]);
|
||||||
@@ -144,7 +161,8 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
|
|||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
ttl,
|
ttl,
|
||||||
keyUsages
|
keyUsages,
|
||||||
|
extendedKeyUsages
|
||||||
}: FormData) => {
|
}: FormData) => {
|
||||||
if (!currentWorkspace?.id) {
|
if (!currentWorkspace?.id) {
|
||||||
return;
|
return;
|
||||||
@@ -163,7 +181,10 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
|
|||||||
ttl,
|
ttl,
|
||||||
keyUsages: Object.entries(keyUsages)
|
keyUsages: Object.entries(keyUsages)
|
||||||
.filter(([, value]) => value)
|
.filter(([, value]) => value)
|
||||||
.map(([key]) => key as CertKeyUsage)
|
.map(([key]) => key as CertKeyUsage),
|
||||||
|
extendedKeyUsages: Object.entries(extendedKeyUsages)
|
||||||
|
.filter(([, value]) => value)
|
||||||
|
.map(([key]) => key as CertExtendedKeyUsage)
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -181,7 +202,10 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
|
|||||||
ttl,
|
ttl,
|
||||||
keyUsages: Object.entries(keyUsages)
|
keyUsages: Object.entries(keyUsages)
|
||||||
.filter(([, value]) => value)
|
.filter(([, value]) => value)
|
||||||
.map(([key]) => key as CertKeyUsage)
|
.map(([key]) => key as CertKeyUsage),
|
||||||
|
extendedKeyUsages: Object.entries(extendedKeyUsages)
|
||||||
|
.filter(([, value]) => value)
|
||||||
|
.map(([key]) => key as CertExtendedKeyUsage)
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -408,6 +432,40 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="extendedKeyUsages"
|
||||||
|
render={({ field: { onChange, value }, fieldState: { error } }) => {
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
label="Extended Key Usages"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
>
|
||||||
|
<div className="mt-2 mb-7 grid grid-cols-2 gap-2">
|
||||||
|
{EXTENDED_KEY_USAGES_OPTIONS.map(({ label, value: optionValue }) => {
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
id={optionValue}
|
||||||
|
key={optionValue}
|
||||||
|
className="data-[state=checked]:bg-primary"
|
||||||
|
isChecked={value[optionValue]}
|
||||||
|
onCheckedChange={(state) => {
|
||||||
|
onChange({
|
||||||
|
...value,
|
||||||
|
[optionValue]: state
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Checkbox>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|||||||
Reference in New Issue
Block a user