mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-19 11:42:52 +00:00
Minor improvements on self signed certificates
This commit is contained in:
@@ -7,11 +7,7 @@ import { EnrollmentType, IssuerType } from "./certificate-profile-types";
|
||||
export const createCertificateProfileSchema = z
|
||||
.object({
|
||||
projectId: z.string().uuid("Project ID must be valid"),
|
||||
caId: z
|
||||
.union([z.string().uuid(), z.literal("")])
|
||||
.optional()
|
||||
.nullable()
|
||||
.transform((val) => (val === "" ? null : val)),
|
||||
caId: z.string().uuid().nullable().optional(),
|
||||
certificateTemplateId: z.string().uuid(),
|
||||
slug: z
|
||||
.string()
|
||||
@@ -38,60 +34,101 @@ export const createCertificateProfileSchema = z
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
// Validate enrollment type configurations
|
||||
if (data.enrollmentType === EnrollmentType.EST) {
|
||||
if (!data.estConfig) {
|
||||
return false;
|
||||
}
|
||||
if (data.apiConfig) {
|
||||
return false;
|
||||
}
|
||||
if (data.acmeConfig) {
|
||||
return false;
|
||||
}
|
||||
return !!data.estConfig;
|
||||
}
|
||||
if (data.enrollmentType === EnrollmentType.API) {
|
||||
if (!data.apiConfig) {
|
||||
return false;
|
||||
}
|
||||
if (data.estConfig) {
|
||||
return false;
|
||||
}
|
||||
if (data.acmeConfig) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (data.enrollmentType === EnrollmentType.ACME) {
|
||||
if (!data.acmeConfig) {
|
||||
return false;
|
||||
}
|
||||
if (data.estConfig) {
|
||||
return false;
|
||||
}
|
||||
if (data.apiConfig) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.issuerType === IssuerType.CA) {
|
||||
if (!data.caId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (data.issuerType === IssuerType.SELF_SIGNED) {
|
||||
if (data.caId) {
|
||||
return false;
|
||||
}
|
||||
if (data.enrollmentType !== EnrollmentType.API) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message:
|
||||
"EST enrollment type requires EST configuration and cannot have API configuration. API enrollment type requires API configuration and cannot have EST configuration. CA issuer type requires a CA ID. Self-signed issuer type cannot have a CA ID and only supports API enrollment."
|
||||
message: "EST enrollment type requires EST configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.API) {
|
||||
return !!data.apiConfig;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "API enrollment type requires API configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.ACME) {
|
||||
return !!data.acmeConfig;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "ACME enrollment type requires ACME configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.EST) {
|
||||
return !data.apiConfig && !data.acmeConfig;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "EST enrollment type cannot have API or ACME configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.API) {
|
||||
return !data.estConfig && !data.acmeConfig;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "API enrollment type cannot have EST or ACME configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.ACME) {
|
||||
return !data.estConfig && !data.apiConfig;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "ACME enrollment type cannot have EST or API configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.issuerType === IssuerType.CA) {
|
||||
return !!data.caId;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "CA issuer type requires a CA ID"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.issuerType === IssuerType.SELF_SIGNED) {
|
||||
return !data.caId;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "Self-signed issuer type cannot have a CA ID"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.issuerType === IssuerType.SELF_SIGNED) {
|
||||
return data.enrollmentType === EnrollmentType.API;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "Self-signed issuer type only supports API enrollment"
|
||||
}
|
||||
);
|
||||
|
||||
@@ -123,27 +160,34 @@ export const updateCertificateProfileSchema = z
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.EST) {
|
||||
if (data.apiConfig) {
|
||||
return false;
|
||||
}
|
||||
return !data.apiConfig;
|
||||
}
|
||||
if (data.enrollmentType === EnrollmentType.API) {
|
||||
if (data.estConfig) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.issuerType === IssuerType.SELF_SIGNED) {
|
||||
if (data.enrollmentType && data.enrollmentType !== EnrollmentType.API) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Cannot have EST config with API enrollment type or API config with EST enrollment type. Self-signed issuer type only supports API enrollment."
|
||||
message: "EST enrollment type cannot have API configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.enrollmentType === EnrollmentType.API) {
|
||||
return !data.estConfig;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "API enrollment type cannot have EST configuration"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.issuerType === IssuerType.SELF_SIGNED) {
|
||||
return !data.enrollmentType || data.enrollmentType === EnrollmentType.API;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "Self-signed issuer type only supports API enrollment"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -407,11 +407,16 @@ const generateSelfSignedCertificate = async ({
|
||||
const signatureAlgorithmConfig = signatureAlgorithmToAlgCfg(effectiveSignatureAlgorithm, effectiveKeyAlgorithm);
|
||||
|
||||
const notBeforeDate = certificateRequest.notBefore ? new Date(certificateRequest.notBefore) : new Date();
|
||||
let notAfterDate = new Date(new Date().setFullYear(new Date().getFullYear() + 1));
|
||||
|
||||
let notAfterDate: Date;
|
||||
if (certificateRequest.notAfter) {
|
||||
notAfterDate = new Date(certificateRequest.notAfter);
|
||||
} else if (certificateRequest.validity.ttl) {
|
||||
notAfterDate = new Date(new Date().getTime() + ms(certificateRequest.validity.ttl));
|
||||
} else {
|
||||
throw new BadRequestError({
|
||||
message: "Either notAfter date or TTL must be provided for certificate validity"
|
||||
});
|
||||
}
|
||||
|
||||
const serialNumber = createSerialNumber();
|
||||
@@ -458,10 +463,22 @@ const generateSelfSignedCertificate = async ({
|
||||
...(subjectAlternativeNames
|
||||
? [
|
||||
new x509.SubjectAlternativeNameExtension(
|
||||
certificateRequest.altNames?.map((san) => ({
|
||||
type: san.type === CertSubjectAlternativeNameType.DNS_NAME ? "dns" : "ip",
|
||||
value: san.value
|
||||
})) || [],
|
||||
certificateRequest.altNames?.map((san) => {
|
||||
switch (san.type) {
|
||||
case CertSubjectAlternativeNameType.DNS_NAME:
|
||||
return { type: "dns" as const, value: san.value };
|
||||
case CertSubjectAlternativeNameType.IP_ADDRESS:
|
||||
return { type: "ip" as const, value: san.value };
|
||||
case CertSubjectAlternativeNameType.EMAIL:
|
||||
return { type: "email" as const, value: san.value };
|
||||
case CertSubjectAlternativeNameType.URI:
|
||||
return { type: "url" as const, value: san.value };
|
||||
default:
|
||||
throw new BadRequestError({
|
||||
message: `Unsupported Subject Alternative Name type: ${san.type as string}`
|
||||
});
|
||||
}
|
||||
}) || [],
|
||||
false
|
||||
)
|
||||
]
|
||||
@@ -545,7 +562,7 @@ const createSelfSignedCertificateRecord = async ({
|
||||
(selfSignedResult.certificateSubject.common_name as string) ||
|
||||
certificateRequest.commonName ||
|
||||
originalCert?.commonName ||
|
||||
(isRenewal ? "Renewed Self-signed Certificate" : "Self-signed Certificate");
|
||||
"";
|
||||
|
||||
const altNamesList = selfSignedResult.subjectAlternativeNames.map((san) => san.value).join(",");
|
||||
|
||||
@@ -726,8 +743,8 @@ const processSelfSignedCertificate = async ({
|
||||
|
||||
await createEncryptedCertificateData({
|
||||
certificateId: certificateData.id,
|
||||
certificate: Buffer.from(selfSignedResult.certificate),
|
||||
privateKey: Buffer.from(selfSignedResult.privateKey),
|
||||
certificate: selfSignedResult.certificate,
|
||||
privateKey: selfSignedResult.privateKey,
|
||||
projectId,
|
||||
certificateBodyDAL,
|
||||
certificateSecretDAL,
|
||||
@@ -1100,10 +1117,25 @@ export const certificateV3ServiceFactory = ({
|
||||
commonName: certificateOrder.commonName,
|
||||
keyUsages: certificateOrder.keyUsages,
|
||||
extendedKeyUsages: certificateOrder.extendedKeyUsages,
|
||||
subjectAlternativeNames: certificateOrder.altNames.map((san) => ({
|
||||
type: san.type === "dns" ? CertSubjectAlternativeNameType.DNS_NAME : CertSubjectAlternativeNameType.IP_ADDRESS,
|
||||
value: san.value
|
||||
})),
|
||||
subjectAlternativeNames: certificateOrder.altNames.map((san) => {
|
||||
let certType: CertSubjectAlternativeNameType;
|
||||
switch (san.type) {
|
||||
case "dns":
|
||||
certType = CertSubjectAlternativeNameType.DNS_NAME;
|
||||
break;
|
||||
case "ip":
|
||||
certType = CertSubjectAlternativeNameType.IP_ADDRESS;
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestError({
|
||||
message: `Unsupported Subject Alternative Name type: ${san.type as string}`
|
||||
});
|
||||
}
|
||||
return {
|
||||
type: certType,
|
||||
value: san.value
|
||||
};
|
||||
}),
|
||||
validity: certificateOrder.validity,
|
||||
notBefore: certificateOrder.notBefore,
|
||||
notAfter: certificateOrder.notAfter,
|
||||
@@ -1216,7 +1248,8 @@ export const certificateV3ServiceFactory = ({
|
||||
|
||||
if (profile.enrollmentType !== EnrollmentType.API) {
|
||||
throw new ForbiddenRequestError({
|
||||
message: "Certificate is not eligible for renewal: EST certificates cannot be renewed through this endpoint"
|
||||
message:
|
||||
"Certificate is not eligible for renewal: Only certificates issued from an API enrollment profile can be renewed through this endpoint"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user