mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-19 00:30:56 +00:00
Addressed PR comments
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
export enum CertSubjectAlternativeNameType {
|
||||
DNS_NAME = "dns_name",
|
||||
IP_ADDRESS = "ip_address",
|
||||
EMAIL = "email",
|
||||
URI = "uri"
|
||||
}
|
||||
|
||||
export enum CertKeyUsageType {
|
||||
DIGITAL_SIGNATURE = "digital_signature",
|
||||
KEY_ENCIPHERMENT = "key_encipherment",
|
||||
NON_REPUDIATION = "non_repudiation",
|
||||
DATA_ENCIPHERMENT = "data_encipherment",
|
||||
KEY_AGREEMENT = "key_agreement",
|
||||
KEY_CERT_SIGN = "key_cert_sign",
|
||||
CRL_SIGN = "crl_sign",
|
||||
ENCIPHER_ONLY = "encipher_only",
|
||||
DECIPHER_ONLY = "decipher_only"
|
||||
}
|
||||
|
||||
export enum CertExtendedKeyUsageType {
|
||||
CLIENT_AUTH = "client_auth",
|
||||
SERVER_AUTH = "server_auth",
|
||||
CODE_SIGNING = "code_signing",
|
||||
EMAIL_PROTECTION = "email_protection",
|
||||
OCSP_SIGNING = "ocsp_signing",
|
||||
TIME_STAMPING = "time_stamping"
|
||||
}
|
||||
|
||||
export enum CertIncludeType {
|
||||
MANDATORY = "mandatory",
|
||||
OPTIONAL = "optional",
|
||||
PROHIBIT = "prohibit"
|
||||
}
|
||||
|
||||
export enum CertDurationUnit {
|
||||
DAYS = "days",
|
||||
MONTHS = "months",
|
||||
YEARS = "years"
|
||||
}
|
||||
|
||||
export enum CertSubjectAttributeType {
|
||||
COMMON_NAME = "common_name"
|
||||
}
|
||||
|
||||
export const mapSANTypeToLegacy = (type: CertSubjectAlternativeNameType): string => {
|
||||
switch (type) {
|
||||
case CertSubjectAlternativeNameType.DNS_NAME:
|
||||
return "dns";
|
||||
case CertSubjectAlternativeNameType.IP_ADDRESS:
|
||||
return "ip";
|
||||
case CertSubjectAlternativeNameType.EMAIL:
|
||||
return "email";
|
||||
case CertSubjectAlternativeNameType.URI:
|
||||
return "uri";
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
export const mapLegacySANTypeToStandard = (type: string): CertSubjectAlternativeNameType => {
|
||||
switch (type) {
|
||||
case "dns":
|
||||
case "dns_name":
|
||||
return CertSubjectAlternativeNameType.DNS_NAME;
|
||||
case "ip":
|
||||
case "ip_address":
|
||||
return CertSubjectAlternativeNameType.IP_ADDRESS;
|
||||
case "email":
|
||||
return CertSubjectAlternativeNameType.EMAIL;
|
||||
case "uri":
|
||||
case "url":
|
||||
return CertSubjectAlternativeNameType.URI;
|
||||
default:
|
||||
throw new Error(`Unknown SAN type: ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const mapKeyUsageToLegacy = (usage: CertKeyUsageType): string => {
|
||||
switch (usage) {
|
||||
case CertKeyUsageType.DIGITAL_SIGNATURE:
|
||||
return "digitalSignature";
|
||||
case CertKeyUsageType.KEY_ENCIPHERMENT:
|
||||
return "keyEncipherment";
|
||||
case CertKeyUsageType.NON_REPUDIATION:
|
||||
return "nonRepudiation";
|
||||
case CertKeyUsageType.DATA_ENCIPHERMENT:
|
||||
return "dataEncipherment";
|
||||
case CertKeyUsageType.KEY_AGREEMENT:
|
||||
return "keyAgreement";
|
||||
case CertKeyUsageType.KEY_CERT_SIGN:
|
||||
return "keyCertSign";
|
||||
case CertKeyUsageType.CRL_SIGN:
|
||||
return "cRLSign";
|
||||
case CertKeyUsageType.ENCIPHER_ONLY:
|
||||
return "encipherOnly";
|
||||
case CertKeyUsageType.DECIPHER_ONLY:
|
||||
return "decipherOnly";
|
||||
default:
|
||||
return usage;
|
||||
}
|
||||
};
|
||||
|
||||
export const mapLegacyKeyUsageToStandard = (usage: string): CertKeyUsageType => {
|
||||
switch (usage) {
|
||||
case "digitalSignature":
|
||||
case "digital_signature":
|
||||
return CertKeyUsageType.DIGITAL_SIGNATURE;
|
||||
case "keyEncipherment":
|
||||
case "key_encipherment":
|
||||
return CertKeyUsageType.KEY_ENCIPHERMENT;
|
||||
case "nonRepudiation":
|
||||
case "non_repudiation":
|
||||
return CertKeyUsageType.NON_REPUDIATION;
|
||||
case "dataEncipherment":
|
||||
case "data_encipherment":
|
||||
return CertKeyUsageType.DATA_ENCIPHERMENT;
|
||||
case "keyAgreement":
|
||||
case "key_agreement":
|
||||
return CertKeyUsageType.KEY_AGREEMENT;
|
||||
case "keyCertSign":
|
||||
case "key_cert_sign":
|
||||
return CertKeyUsageType.KEY_CERT_SIGN;
|
||||
case "cRLSign":
|
||||
case "crl_sign":
|
||||
return CertKeyUsageType.CRL_SIGN;
|
||||
case "encipherOnly":
|
||||
case "encipher_only":
|
||||
return CertKeyUsageType.ENCIPHER_ONLY;
|
||||
case "decipherOnly":
|
||||
case "decipher_only":
|
||||
return CertKeyUsageType.DECIPHER_ONLY;
|
||||
default:
|
||||
throw new Error(`Unknown key usage: ${usage}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const mapExtendedKeyUsageToLegacy = (usage: CertExtendedKeyUsageType): string => {
|
||||
switch (usage) {
|
||||
case CertExtendedKeyUsageType.CLIENT_AUTH:
|
||||
return "clientAuth";
|
||||
case CertExtendedKeyUsageType.SERVER_AUTH:
|
||||
return "serverAuth";
|
||||
case CertExtendedKeyUsageType.CODE_SIGNING:
|
||||
return "codeSigning";
|
||||
case CertExtendedKeyUsageType.EMAIL_PROTECTION:
|
||||
return "emailProtection";
|
||||
case CertExtendedKeyUsageType.OCSP_SIGNING:
|
||||
return "ocspSigning";
|
||||
case CertExtendedKeyUsageType.TIME_STAMPING:
|
||||
return "timeStamping";
|
||||
default:
|
||||
return usage;
|
||||
}
|
||||
};
|
||||
|
||||
export const mapLegacyExtendedKeyUsageToStandard = (usage: string): CertExtendedKeyUsageType => {
|
||||
switch (usage) {
|
||||
case "clientAuth":
|
||||
case "client_auth":
|
||||
return CertExtendedKeyUsageType.CLIENT_AUTH;
|
||||
case "serverAuth":
|
||||
case "server_auth":
|
||||
return CertExtendedKeyUsageType.SERVER_AUTH;
|
||||
case "codeSigning":
|
||||
case "code_signing":
|
||||
return CertExtendedKeyUsageType.CODE_SIGNING;
|
||||
case "emailProtection":
|
||||
case "email_protection":
|
||||
return CertExtendedKeyUsageType.EMAIL_PROTECTION;
|
||||
case "ocspSigning":
|
||||
case "ocsp_signing":
|
||||
return CertExtendedKeyUsageType.OCSP_SIGNING;
|
||||
case "timeStamping":
|
||||
case "time_stamping":
|
||||
return CertExtendedKeyUsageType.TIME_STAMPING;
|
||||
default:
|
||||
throw new Error(`Unknown extended key usage: ${usage}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const SAN_TYPE_OPTIONS = Object.values(CertSubjectAlternativeNameType);
|
||||
export const KEY_USAGE_OPTIONS = Object.values(CertKeyUsageType);
|
||||
export const EXTENDED_KEY_USAGE_OPTIONS = Object.values(CertExtendedKeyUsageType);
|
||||
export const INCLUDE_TYPE_OPTIONS = Object.values(CertIncludeType);
|
||||
export const DURATION_UNIT_OPTIONS = Object.values(CertDurationUnit);
|
||||
export const SUBJECT_ATTRIBUTE_TYPE_OPTIONS = Object.values(CertSubjectAttributeType);
|
||||
@@ -1,34 +1,39 @@
|
||||
import { CertExtendedKeyUsage, CertKeyUsage } from "../certificate/certificate-types";
|
||||
import {
|
||||
CertExtendedKeyUsageType,
|
||||
CertKeyUsageType,
|
||||
mapExtendedKeyUsageToLegacy,
|
||||
mapKeyUsageToLegacy,
|
||||
mapLegacyExtendedKeyUsageToStandard,
|
||||
mapLegacyKeyUsageToStandard
|
||||
} from "./certificate-constants";
|
||||
|
||||
interface CertificateRequestInput {
|
||||
keyUsages?: string[];
|
||||
extendedKeyUsages?: string[];
|
||||
}
|
||||
|
||||
export const mapEnumsForValidation = <T extends CertificateRequestInput>(request: T): T => {
|
||||
const keyUsageMapping: Record<string, string> = {
|
||||
digitalSignature: "digital_signature",
|
||||
keyEncipherment: "key_encipherment",
|
||||
nonRepudiation: "non_repudiation",
|
||||
dataEncipherment: "data_encipherment",
|
||||
keyAgreement: "key_agreement",
|
||||
keyCertSign: "key_cert_sign",
|
||||
cRLSign: "crl_sign",
|
||||
encipherOnly: "encipher_only",
|
||||
decipherOnly: "decipher_only"
|
||||
const mapKeyUsage = (usage: string): string => {
|
||||
try {
|
||||
return mapLegacyKeyUsageToStandard(usage);
|
||||
} catch {
|
||||
return usage;
|
||||
}
|
||||
};
|
||||
|
||||
const extendedKeyUsageMapping: Record<string, string> = {
|
||||
serverAuth: "server_auth",
|
||||
clientAuth: "client_auth",
|
||||
codeSigning: "code_signing",
|
||||
emailProtection: "email_protection",
|
||||
timeStamping: "time_stamping",
|
||||
ocspSigning: "ocsp_signing"
|
||||
const mapExtendedKeyUsage = (usage: string): string => {
|
||||
try {
|
||||
return mapLegacyExtendedKeyUsageToStandard(usage);
|
||||
} catch {
|
||||
return usage;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...request,
|
||||
keyUsages: request.keyUsages?.map((usage: string) => keyUsageMapping[usage] || usage),
|
||||
extendedKeyUsages: request.extendedKeyUsages?.map((usage: string) => extendedKeyUsageMapping[usage] || usage)
|
||||
keyUsages: request.keyUsages?.map(mapKeyUsage),
|
||||
extendedKeyUsages: request.extendedKeyUsages?.map(mapExtendedKeyUsage)
|
||||
} as T;
|
||||
};
|
||||
|
||||
@@ -51,27 +56,28 @@ export const buildCertificateSubjectFromTemplate = (
|
||||
): Record<string, string | undefined> => {
|
||||
const subject: Record<string, string> = {};
|
||||
const attributeMap: Record<string, string> = {
|
||||
common_name: "commonName",
|
||||
organization_name: "organization",
|
||||
organization_unit: "organizationUnit",
|
||||
locality: "locality",
|
||||
state: "state",
|
||||
country: "country",
|
||||
email: "email",
|
||||
street_address: "streetAddress",
|
||||
postal_code: "postalCode"
|
||||
common_name: "commonName"
|
||||
};
|
||||
|
||||
if (!templateAttributes || templateAttributes.length === 0) {
|
||||
Object.entries(attributeMap).forEach(([templateKey, requestKey]) => {
|
||||
const value = request[requestKey];
|
||||
if (value && typeof value === "string") {
|
||||
subject[templateKey] = value;
|
||||
}
|
||||
});
|
||||
return subject;
|
||||
throw new Error(
|
||||
"Template must define allowed certificate attributes. Cannot issue certificate without template attribute constraints."
|
||||
);
|
||||
}
|
||||
|
||||
const allowedAttributes = new Set(templateAttributes.map((attr) => attributeMap[attr.type]));
|
||||
|
||||
Object.keys(attributeMap).forEach((templateType) => {
|
||||
const requestKey = attributeMap[templateType];
|
||||
const value = request[requestKey];
|
||||
|
||||
if (value && !allowedAttributes.has(requestKey)) {
|
||||
throw new Error(
|
||||
`Certificate attribute '${requestKey}' is not allowed by the template. Template must define constraints for all requested attributes.`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
templateAttributes.forEach((attr) => {
|
||||
if (attr.include === "prohibit") {
|
||||
return;
|
||||
@@ -101,12 +107,28 @@ export const buildSubjectAlternativeNamesFromTemplate = (
|
||||
}
|
||||
|
||||
if (!templateSans || templateSans.length === 0) {
|
||||
return request.subjectAlternativeNames.map((san) => san.value).join(",");
|
||||
if (request.subjectAlternativeNames.length > 0) {
|
||||
throw new Error(
|
||||
"Template must define allowed subject alternative names. Cannot issue certificate with SANs when template has no SAN constraints."
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const allowedSans: string[] = [];
|
||||
const templateSanTypes = new Set(templateSans.map((san) => san.type));
|
||||
const prohibitedTypes = new Set(templateSans.filter((san) => san.include === "prohibit").map((san) => san.type));
|
||||
|
||||
request.subjectAlternativeNames.forEach((san) => {
|
||||
const sanType = san.type === "dns_name" ? "dns_name" : san.type;
|
||||
if (!templateSanTypes.has(sanType)) {
|
||||
throw new Error(
|
||||
`Subject Alternative Name type '${sanType}' is not allowed by the template. Template must define constraints for all requested SAN types.`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const allowedSans: string[] = [];
|
||||
|
||||
request.subjectAlternativeNames.forEach((san) => {
|
||||
const sanType = san.type === "dns_name" ? "dns_name" : san.type;
|
||||
if (!prohibitedTypes.has(sanType)) {
|
||||
@@ -116,3 +138,39 @@ export const buildSubjectAlternativeNamesFromTemplate = (
|
||||
|
||||
return allowedSans.join(",");
|
||||
};
|
||||
|
||||
export const convertLegacyKeyUsage = (usage: CertKeyUsage): CertKeyUsageType => {
|
||||
return mapLegacyKeyUsageToStandard(usage);
|
||||
};
|
||||
|
||||
export const convertToLegacyKeyUsage = (usage: CertKeyUsageType): CertKeyUsage => {
|
||||
return mapKeyUsageToLegacy(usage) as CertKeyUsage;
|
||||
};
|
||||
|
||||
export const convertLegacyExtendedKeyUsage = (usage: CertExtendedKeyUsage): CertExtendedKeyUsageType => {
|
||||
return mapLegacyExtendedKeyUsageToStandard(usage);
|
||||
};
|
||||
|
||||
export const convertToLegacyExtendedKeyUsage = (usage: CertExtendedKeyUsageType): CertExtendedKeyUsage => {
|
||||
return mapExtendedKeyUsageToLegacy(usage) as CertExtendedKeyUsage;
|
||||
};
|
||||
|
||||
export const convertKeyUsageArrayFromLegacy = (usages?: CertKeyUsage[]): CertKeyUsageType[] | undefined => {
|
||||
return usages?.map(convertLegacyKeyUsage);
|
||||
};
|
||||
|
||||
export const convertKeyUsageArrayToLegacy = (usages?: CertKeyUsageType[]): CertKeyUsage[] | undefined => {
|
||||
return usages?.map(convertToLegacyKeyUsage);
|
||||
};
|
||||
|
||||
export const convertExtendedKeyUsageArrayFromLegacy = (
|
||||
usages?: CertExtendedKeyUsage[]
|
||||
): CertExtendedKeyUsageType[] | undefined => {
|
||||
return usages?.map(convertLegacyExtendedKeyUsage);
|
||||
};
|
||||
|
||||
export const convertExtendedKeyUsageArrayToLegacy = (
|
||||
usages?: CertExtendedKeyUsageType[]
|
||||
): CertExtendedKeyUsage[] | undefined => {
|
||||
return usages?.map(convertToLegacyExtendedKeyUsage);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user