diff --git a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CertificateTemplatesV2Tab.tsx b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CertificateTemplatesV2Tab.tsx
index ec660b339..33f92a122 100644
--- a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CertificateTemplatesV2Tab.tsx
+++ b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CertificateTemplatesV2Tab.tsx
@@ -10,7 +10,7 @@ import {
ProjectPermissionSub
} from "@app/context/ProjectPermissionContext/types";
import { useDeleteCertificateTemplateV2WithPolicies } from "@app/hooks/api/certificateTemplates/mutations";
-import { TCertificateTemplateV2WithPolicies } from "@app/hooks/api/certificateTemplates/types";
+import { type TCertificateTemplateV2WithPolicies } from "@app/hooks/api/certificateTemplates/types";
import { CreateTemplateModal } from "./CreateTemplateModal";
import { TemplateList } from "./TemplateList";
@@ -84,7 +84,12 @@ export const CertificateTemplatesV2Tab = () => {
- setIsCreateModalOpen(false)} />
+ {
+ setIsCreateModalOpen(false);
+ }}
+ />
{selectedTemplate && (
<>
diff --git a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CreateTemplateModal.tsx b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CreateTemplateModal.tsx
index b929ce36e..d55c1b5ef 100644
--- a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CreateTemplateModal.tsx
+++ b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/CreateTemplateModal.tsx
@@ -36,13 +36,18 @@ import {
CertDurationUnit,
CertExtendedKeyUsageType,
CertKeyUsageType,
+ CertSanInclude,
CertSubjectAlternativeNameType,
+ CertSubjectAttributeInclude,
CertSubjectAttributeType,
SAN_INCLUDE_OPTIONS,
SAN_TYPE_OPTIONS,
SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS,
- SUBJECT_ATTRIBUTE_TYPE_OPTIONS
+ SUBJECT_ATTRIBUTE_TYPE_OPTIONS,
+ TEMPLATE_PRESET_IDS,
+ type TemplatePresetId
} from "./shared/certificate-constants";
+import { CERTIFICATE_TEMPLATE_PRESETS } from "./shared/template-presets";
import { KeyUsagesSection, TemplateFormData, templateSchema } from "./shared";
export type FormData = TemplateFormData;
@@ -91,7 +96,7 @@ const SIGNATURE_ALGORITHMS = [
"SHA256-ECDSA",
"SHA384-ECDSA",
"SHA512-ECDSA"
-];
+] as const;
const KEY_ALGORITHMS = [
"RSA-2048",
@@ -100,7 +105,7 @@ const KEY_ALGORITHMS = [
"ECDSA-P256",
"ECDSA-P384",
"ECDSA-P521"
-];
+] as const;
export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create" }: Props) => {
const { currentProject } = useProject();
@@ -117,7 +122,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
subj.allowed.forEach((allowedValue) => {
attributes.push({
type: subj.type as CertSubjectAttributeType,
- include: "optional",
+ include: CertSubjectAttributeInclude.OPTIONAL,
value: [allowedValue]
});
});
@@ -126,7 +131,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
subj.denied.forEach((deniedValue) => {
attributes.push({
type: subj.type as CertSubjectAttributeType,
- include: "prohibit",
+ include: CertSubjectAttributeInclude.PROHIBIT,
value: [deniedValue]
});
});
@@ -141,7 +146,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
san.required.forEach((requiredValue) => {
subjectAlternativeNames.push({
type: san.type as CertSubjectAlternativeNameType,
- include: "mandatory",
+ include: CertSanInclude.MANDATORY,
value: [requiredValue]
});
});
@@ -150,7 +155,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
san.allowed.forEach((allowedValue) => {
subjectAlternativeNames.push({
type: san.type as CertSubjectAlternativeNameType,
- include: "optional",
+ include: CertSanInclude.OPTIONAL,
value: [allowedValue]
});
});
@@ -159,7 +164,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
san.denied.forEach((deniedValue) => {
subjectAlternativeNames.push({
type: san.type as CertSubjectAlternativeNameType,
- include: "prohibit",
+ include: CertSanInclude.PROHIBIT,
value: [deniedValue]
});
});
@@ -219,6 +224,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
};
return {
+ preset: TEMPLATE_PRESET_IDS.CUSTOM,
name: templateData.name || "",
description: templateData.description || "",
attributes,
@@ -231,25 +237,30 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
};
};
- const getDefaultValues = (): FormData => ({
- name: "",
- description: "",
- attributes: [],
- keyUsages: { requiredUsages: [], optionalUsages: [] },
- extendedKeyUsages: { requiredUsages: [], optionalUsages: [] },
- subjectAlternativeNames: [],
- validity: {
- maxDuration: { value: 365, unit: CertDurationUnit.DAYS }
- },
- signatureAlgorithm: {
- allowedAlgorithms: []
- },
- keyAlgorithm: {
- allowedKeyTypes: []
- }
- });
+ const getDefaultValues = (): FormData & { preset: TemplatePresetId } => {
+ return {
+ preset: TEMPLATE_PRESET_IDS.CUSTOM,
+ name: "",
+ description: "",
+ attributes: [],
+ keyUsages: { requiredUsages: [], optionalUsages: [] },
+ extendedKeyUsages: { requiredUsages: [], optionalUsages: [] },
+ subjectAlternativeNames: [],
+ validity: {
+ maxDuration: { value: 365, unit: CertDurationUnit.DAYS }
+ },
+ signatureAlgorithm: {
+ allowedAlgorithms: []
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: []
+ }
+ };
+ };
- const { control, handleSubmit, reset, watch, setValue, formState } = useForm({
+ const { control, handleSubmit, reset, watch, setValue, formState } = useForm<
+ FormData & { preset: TemplatePresetId }
+ >({
resolver: zodResolver(templateSchema),
defaultValues: getDefaultValues(),
mode: "onChange",
@@ -260,7 +271,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
useEffect(() => {
if (isEdit && template) {
const convertedData = convertApiToUiFormat(template);
- reset(convertedData);
+ reset({ ...convertedData, preset: TEMPLATE_PRESET_IDS.CUSTOM });
} else if (!isEdit) {
reset(getDefaultValues());
}
@@ -273,6 +284,37 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
requiredUsages: [],
optionalUsages: []
};
+ const watchedPreset = watch("preset") || TEMPLATE_PRESET_IDS.CUSTOM;
+
+ const handlePresetChange = (presetId: TemplatePresetId) => {
+ setValue("preset", presetId);
+
+ if (presetId === TEMPLATE_PRESET_IDS.CUSTOM) {
+ return;
+ }
+
+ const selectedPreset = CERTIFICATE_TEMPLATE_PRESETS.find((p) => p.id === presetId);
+ if (selectedPreset) {
+ if (selectedPreset.formData.keyUsages) {
+ setValue("keyUsages", selectedPreset.formData.keyUsages);
+ }
+ if (selectedPreset.formData.extendedKeyUsages) {
+ setValue("extendedKeyUsages", selectedPreset.formData.extendedKeyUsages);
+ }
+ if (selectedPreset.formData.attributes) {
+ setValue("attributes", selectedPreset.formData.attributes);
+ }
+ if (selectedPreset.formData.subjectAlternativeNames) {
+ setValue("subjectAlternativeNames", selectedPreset.formData.subjectAlternativeNames);
+ }
+ if (selectedPreset.formData.signatureAlgorithm) {
+ setValue("signatureAlgorithm", selectedPreset.formData.signatureAlgorithm);
+ }
+ if (selectedPreset.formData.keyAlgorithm) {
+ setValue("keyAlgorithm", selectedPreset.formData.keyAlgorithm);
+ }
+ }
+ };
const consolidateByType = <
T extends { type: string; allowed?: string[]; required?: string[]; denied?: string[] }
@@ -309,9 +351,17 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
data.attributes?.map((attr) => {
const result: AttributeTransform = { type: attr.type };
- if (attr.include === "optional" && attr.value && attr.value.length > 0) {
+ if (
+ attr.include === CertSubjectAttributeInclude.OPTIONAL &&
+ attr.value &&
+ attr.value.length > 0
+ ) {
result.allowed = attr.value;
- } else if (attr.include === "prohibit" && attr.value && attr.value.length > 0) {
+ } else if (
+ attr.include === CertSubjectAttributeInclude.PROHIBIT &&
+ attr.value &&
+ attr.value.length > 0
+ ) {
result.denied = attr.value;
}
@@ -322,11 +372,11 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
data.subjectAlternativeNames?.map((san) => {
const result: SanTransform = { type: san.type };
- if (san.include === "mandatory" && san.value && san.value.length > 0) {
+ if (san.include === CertSanInclude.MANDATORY && san.value && san.value.length > 0) {
result.required = san.value;
- } else if (san.include === "optional" && san.value && san.value.length > 0) {
+ } else if (san.include === CertSanInclude.OPTIONAL && san.value && san.value.length > 0) {
result.allowed = san.value;
- } else if (san.include === "prohibit" && san.value && san.value.length > 0) {
+ } else if (san.include === CertSanInclude.PROHIBIT && san.value && san.value.length > 0) {
result.denied = san.value;
}
@@ -464,11 +514,19 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
value: ["*"]
};
setValue("attributes", [...watchedAttributes, newAttribute]);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
};
const removeAttribute = (index: number) => {
const newAttributes = watchedAttributes.filter((_, i) => i !== index);
setValue("attributes", newAttributes);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
};
const addSan = () => {
@@ -478,11 +536,19 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
value: ["*"]
};
setValue("subjectAlternativeNames", [...watchedSans, newSan]);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
};
const removeSan = (index: number) => {
const newSans = watchedSans.filter((_, i) => i !== index);
setValue("subjectAlternativeNames", newSans);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
};
const handleKeyUsagesChange = (usages: {
@@ -493,6 +559,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
requiredUsages: usages.requiredUsages,
optionalUsages: usages.optionalUsages
});
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
};
const handleExtendedKeyUsagesChange = (usages: {
@@ -503,6 +573,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
requiredUsages: usages.requiredUsages,
optionalUsages: usages.optionalUsages
});
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
};
return (
@@ -555,6 +629,33 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
)}
/>
+
+ (
+
+
+
+ )}
+ />
Subject Attributes
@@ -595,6 +696,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
type: value as CertSubjectAttributeType
};
setValue("attributes", newAttributes);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
}}
className="w-48"
>
@@ -615,6 +720,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
value as (typeof SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS)[number]
};
setValue("attributes", newAttributes);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
}}
className="w-32"
>
@@ -635,6 +744,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
value: e.target.value.trim() ? [e.target.value.trim()] : []
};
setValue("attributes", newAttributes);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
}}
className={`flex-1 ${
attr.value && attr.value.length > 0 && attr.value[0] === ""
@@ -701,6 +814,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
type: value as CertSubjectAlternativeNameType
};
setValue("subjectAlternativeNames", newSans);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
}}
className="w-36"
>
@@ -720,6 +837,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
include: value as (typeof SAN_INCLUDE_OPTIONS)[number]
};
setValue("subjectAlternativeNames", newSans);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
}}
className="w-32"
>
@@ -740,6 +861,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
value: e.target.value.trim() ? [e.target.value.trim()] : []
};
setValue("subjectAlternativeNames", newSans);
+
+ if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
+ setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
+ }
}}
className={`flex-1 ${
san.value && san.value.length > 0 && san.value[0] === ""
diff --git a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/certificate-constants.ts b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/certificate-constants.ts
index 50b69a2e2..47fdcd5a2 100644
--- a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/certificate-constants.ts
+++ b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/certificate-constants.ts
@@ -150,8 +150,19 @@ export const SUBJECT_ATTRIBUTE_TYPE_OPTIONS = Object.values(CertSubjectAttribute
export const ATTRIBUTE_RULE_OPTIONS = Object.values(CertAttributeRule);
export const SAN_EFFECT_OPTIONS = Object.values(CertSanEffect);
-export const SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS = ["optional", "prohibit"] as const;
-export const SAN_INCLUDE_OPTIONS = ["mandatory", "optional", "prohibit"] as const;
+export enum CertSubjectAttributeInclude {
+ OPTIONAL = "optional",
+ PROHIBIT = "prohibit"
+}
+
+export enum CertSanInclude {
+ MANDATORY = "mandatory",
+ OPTIONAL = "optional",
+ PROHIBIT = "prohibit"
+}
+
+export const SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS = Object.values(CertSubjectAttributeInclude);
+export const SAN_INCLUDE_OPTIONS = Object.values(CertSanInclude);
export const USAGE_STATES = {
REQUIRED: "required",
@@ -239,3 +250,27 @@ export const mapTemplateKeyAlgorithmToApi = (templateFormat: string): string =>
};
return mapping[templateFormat] || templateFormat;
};
+
+export const TEMPLATE_PRESET_IDS = {
+ CUSTOM: "custom",
+ TLS_SERVER: "tls-server",
+ TLS_CLIENT: "tls-client",
+ CODE_SIGNING: "code-signing",
+ DEVICE: "device",
+ USER: "user",
+ EMAIL_PROTECTION: "email-protection",
+ DUAL_PURPOSE_SERVER: "dual-purpose-server"
+} as const;
+
+export type TemplatePresetId = (typeof TEMPLATE_PRESET_IDS)[keyof typeof TEMPLATE_PRESET_IDS];
+
+export const ALGORITHM_FAMILIES = {
+ ECDSA: {
+ signature: ["SHA256-ECDSA", "SHA384-ECDSA", "SHA512-ECDSA"] as const,
+ key: ["ECDSA-P256", "ECDSA-P384", "ECDSA-P521"] as const
+ },
+ RSA: {
+ signature: ["SHA256-RSA", "SHA384-RSA", "SHA512-RSA"] as const,
+ key: ["RSA-2048", "RSA-3072", "RSA-4096"] as const
+ }
+} as const;
diff --git a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/schemas.ts b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/schemas.ts
index 0590c4160..137ca262c 100644
--- a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/schemas.ts
+++ b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/schemas.ts
@@ -4,21 +4,22 @@ import {
CertDurationUnit,
CertExtendedKeyUsageType,
CertKeyUsageType,
+ CertSanInclude,
CertSubjectAlternativeNameType,
+ CertSubjectAttributeInclude,
CertSubjectAttributeType,
- SAN_INCLUDE_OPTIONS,
- SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS
+ TEMPLATE_PRESET_IDS
} from "./certificate-constants";
export const uiAttributeSchema = z.object({
type: z.nativeEnum(CertSubjectAttributeType),
- include: z.enum(SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS),
+ include: z.nativeEnum(CertSubjectAttributeInclude),
value: z.array(z.string().min(1, "Value cannot be empty"))
});
export const uiSanSchema = z.object({
type: z.nativeEnum(CertSubjectAlternativeNameType),
- include: z.enum(SAN_INCLUDE_OPTIONS),
+ include: z.nativeEnum(CertSanInclude),
value: z.array(z.string().min(1, "Value cannot be empty"))
});
@@ -51,7 +52,21 @@ export const uiKeyAlgorithmSchema = z.object({
.min(1, "At least one key type must be selected")
});
+export const uiPresetSchema = z
+ .enum([
+ TEMPLATE_PRESET_IDS.CUSTOM,
+ TEMPLATE_PRESET_IDS.TLS_SERVER,
+ TEMPLATE_PRESET_IDS.TLS_CLIENT,
+ TEMPLATE_PRESET_IDS.CODE_SIGNING,
+ TEMPLATE_PRESET_IDS.DEVICE,
+ TEMPLATE_PRESET_IDS.USER,
+ TEMPLATE_PRESET_IDS.EMAIL_PROTECTION,
+ TEMPLATE_PRESET_IDS.DUAL_PURPOSE_SERVER
+ ])
+ .default(TEMPLATE_PRESET_IDS.CUSTOM);
+
export const templateSchema = z.object({
+ preset: uiPresetSchema,
name: z
.string()
.trim()
diff --git a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/template-presets.ts b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/template-presets.ts
new file mode 100644
index 000000000..9edad21ea
--- /dev/null
+++ b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/template-presets.ts
@@ -0,0 +1,385 @@
+import {
+ ALGORITHM_FAMILIES,
+ CertDurationUnit,
+ CertExtendedKeyUsageType,
+ CertKeyUsageType,
+ CertSanInclude,
+ CertSubjectAlternativeNameType,
+ CertSubjectAttributeInclude,
+ CertSubjectAttributeType,
+ TEMPLATE_PRESET_IDS,
+ type TemplatePresetId
+} from "./certificate-constants";
+import { TemplateFormData } from ".";
+
+export interface CertificateTemplatePreset {
+ readonly id: TemplatePresetId;
+ readonly name: string;
+ readonly description: string;
+ readonly useCase: string;
+ readonly formData: Omit;
+}
+
+export const CERTIFICATE_TEMPLATE_PRESETS: CertificateTemplatePreset[] = [
+ {
+ id: TEMPLATE_PRESET_IDS.TLS_SERVER,
+ name: "TLS Server Certificate",
+ description: "Standard TLS/SSL server certificate for HTTPS services and API endpoints.",
+ useCase: "Web servers, API endpoints, HTTPS services",
+ formData: {
+ name: "TLS Server Certificate",
+ description: "Standard TLS/SSL server certificate for HTTPS services and API endpoints.",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
+ optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.KEY_ENCIPHERMENT]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [CertExtendedKeyUsageType.SERVER_AUTH],
+ optionalUsages: [CertExtendedKeyUsageType.SERVER_AUTH]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.DNS_NAME,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ },
+ {
+ type: CertSubjectAlternativeNameType.IP_ADDRESS,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
+ }
+ }
+ },
+ {
+ id: TEMPLATE_PRESET_IDS.TLS_CLIENT,
+ name: "TLS Client Certificate",
+ description: "Client certificate for mutual TLS authentication and API access.",
+ useCase: "Client authentication, mTLS, API authentication",
+ formData: {
+ name: "TLS Client Certificate",
+ description: "Client certificate for mutual TLS authentication and API access.",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
+ optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.KEY_AGREEMENT]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [CertExtendedKeyUsageType.CLIENT_AUTH],
+ optionalUsages: [CertExtendedKeyUsageType.CLIENT_AUTH]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.EMAIL,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ },
+ {
+ type: CertSubjectAlternativeNameType.DNS_NAME,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
+ }
+ }
+ },
+ {
+ id: TEMPLATE_PRESET_IDS.CODE_SIGNING,
+ name: "Code Signing Certificate",
+ description:
+ "Certificate for signing software, executables, and packages. Requires hardware security modules.",
+ useCase: "Software signing, executable authentication, package validation",
+ formData: {
+ name: "Code Signing Certificate",
+ description:
+ "Certificate for signing software, executables, and packages. Requires hardware security modules.",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.NON_REPUDIATION],
+ optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.NON_REPUDIATION]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [CertExtendedKeyUsageType.CODE_SIGNING],
+ optionalUsages: [
+ CertExtendedKeyUsageType.CODE_SIGNING,
+ CertExtendedKeyUsageType.TIME_STAMPING
+ ]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.EMAIL,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.RSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.RSA.key]
+ }
+ }
+ },
+ {
+ id: TEMPLATE_PRESET_IDS.DEVICE,
+ name: "Device Certificate",
+ description:
+ "Certificate for IoT devices and embedded systems authentication. IEEE 802.1AR compliant.",
+ useCase: "Device authentication, IoT security, embedded systems",
+ formData: {
+ name: "Device Certificate",
+ description:
+ "Certificate for IoT devices and embedded systems authentication. IEEE 802.1AR compliant.",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
+ optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.KEY_AGREEMENT]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [CertExtendedKeyUsageType.CLIENT_AUTH],
+ optionalUsages: [CertExtendedKeyUsageType.CLIENT_AUTH, CertExtendedKeyUsageType.SERVER_AUTH]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.DNS_NAME,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ },
+ {
+ type: CertSubjectAlternativeNameType.IP_ADDRESS,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
+ }
+ }
+ },
+ {
+ id: TEMPLATE_PRESET_IDS.USER,
+ name: "User Certificate",
+ description:
+ "Personal certificate for user authentication and email signing. FIPS 201 PIV compliant.",
+ useCase: "Personal authentication, smart cards, email protection",
+ formData: {
+ name: "User Certificate",
+ description:
+ "Personal certificate for user authentication and email signing. FIPS 201 PIV compliant.",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
+ optionalUsages: [
+ CertKeyUsageType.DIGITAL_SIGNATURE,
+ CertKeyUsageType.KEY_ENCIPHERMENT,
+ CertKeyUsageType.KEY_AGREEMENT
+ ]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [
+ CertExtendedKeyUsageType.CLIENT_AUTH,
+ CertExtendedKeyUsageType.EMAIL_PROTECTION
+ ],
+ optionalUsages: [
+ CertExtendedKeyUsageType.CLIENT_AUTH,
+ CertExtendedKeyUsageType.EMAIL_PROTECTION
+ ]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.EMAIL,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
+ }
+ }
+ },
+ {
+ id: TEMPLATE_PRESET_IDS.EMAIL_PROTECTION,
+ name: "Email Protection Certificate",
+ description: "S/MIME certificate for email encryption and digital signing. RFC 8550 compliant.",
+ useCase: "Email encryption, digital signing, secure messaging",
+ formData: {
+ name: "Email Protection Certificate",
+ description:
+ "S/MIME certificate for email encryption and digital signing. RFC 8550 compliant.",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
+ optionalUsages: [
+ CertKeyUsageType.DIGITAL_SIGNATURE,
+ CertKeyUsageType.KEY_ENCIPHERMENT,
+ CertKeyUsageType.KEY_AGREEMENT
+ ]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [CertExtendedKeyUsageType.EMAIL_PROTECTION],
+ optionalUsages: [CertExtendedKeyUsageType.EMAIL_PROTECTION]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.EMAIL,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.RSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.RSA.key]
+ }
+ }
+ },
+ {
+ id: TEMPLATE_PRESET_IDS.DUAL_PURPOSE_SERVER,
+ name: "Dual-Purpose Server Certificate",
+ description:
+ "Certificate for services requiring both server and client authentication capabilities",
+ useCase: "Microservices, service mesh, dual authentication",
+ formData: {
+ name: "Dual-Purpose Server Certificate",
+ description:
+ "Certificate for services requiring both server and client authentication capabilities",
+ keyUsages: {
+ requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
+ optionalUsages: [
+ CertKeyUsageType.DIGITAL_SIGNATURE,
+ CertKeyUsageType.KEY_ENCIPHERMENT,
+ CertKeyUsageType.KEY_AGREEMENT
+ ]
+ },
+ extendedKeyUsages: {
+ requiredUsages: [
+ CertExtendedKeyUsageType.SERVER_AUTH,
+ CertExtendedKeyUsageType.CLIENT_AUTH
+ ],
+ optionalUsages: [CertExtendedKeyUsageType.SERVER_AUTH, CertExtendedKeyUsageType.CLIENT_AUTH]
+ },
+ validity: {
+ maxDuration: {
+ value: 365,
+ unit: CertDurationUnit.DAYS
+ }
+ },
+ attributes: [
+ {
+ type: CertSubjectAttributeType.COMMON_NAME,
+ include: CertSubjectAttributeInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ subjectAlternativeNames: [
+ {
+ type: CertSubjectAlternativeNameType.DNS_NAME,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ },
+ {
+ type: CertSubjectAlternativeNameType.IP_ADDRESS,
+ include: CertSanInclude.OPTIONAL,
+ value: ["*"]
+ }
+ ],
+ signatureAlgorithm: {
+ allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
+ },
+ keyAlgorithm: {
+ allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
+ }
+ }
+ }
+];