mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: finished up EST cacerts
This commit is contained in:
@@ -2,7 +2,7 @@ import bcrypt from "bcrypt";
|
||||
import { z } from "zod";
|
||||
|
||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||
|
||||
export const registerCertificateEstRouter = async (server: FastifyZodProvider) => {
|
||||
// add support for CSR bodies
|
||||
@@ -18,6 +18,13 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
||||
// Authenticate EST client using Passphrase
|
||||
server.addHook("onRequest", async (req, res) => {
|
||||
const { authorization } = req.headers;
|
||||
const urlFragments = req.url.split("/");
|
||||
|
||||
// cacerts endpoint should not have any authentication
|
||||
if (urlFragments[urlFragments.length - 1] === "cacerts") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!authorization) {
|
||||
const wwwAuthenticateHeader = "WWW-Authenticate";
|
||||
const errAuthRequired = "Authentication required";
|
||||
@@ -36,7 +43,6 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
||||
return;
|
||||
}
|
||||
|
||||
const urlFragments = req.url.split("/");
|
||||
const certificateTemplateId = urlFragments.slice(-2)[0];
|
||||
const estConfig = await server.services.certificateTemplate.getEstConfiguration({
|
||||
isInternal: true,
|
||||
@@ -124,4 +130,28 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/:certificateTemplateId/cacerts",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
params: z.object({
|
||||
certificateTemplateId: z.string().min(1)
|
||||
}),
|
||||
response: {
|
||||
200: z.string()
|
||||
}
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
||||
void res.header("Content-Transfer-Encoding", "base64");
|
||||
|
||||
return server.services.certificateEst.getCaCerts({
|
||||
certificateTemplateId: req.params.certificateTemplateId
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { X509Certificate } from "@peculiar/x509";
|
||||
import { Certificate, ContentInfo, EncapsulatedContentInfo, SignedData } from "pkijs";
|
||||
|
||||
export const convertRawCertToPkcs7 = (rawCertificate: ArrayBuffer) => {
|
||||
const cert = Certificate.fromBER(rawCertificate);
|
||||
export const convertRawCertsToPkcs7 = (rawCertificate: ArrayBuffer[]) => {
|
||||
const certs = rawCertificate.map((rawCert) => Certificate.fromBER(rawCert));
|
||||
const cmsSigned = new SignedData({
|
||||
encapContentInfo: new EncapsulatedContentInfo({
|
||||
eContentType: "1.2.840.113549.1.7.1" // not encrypted and not compressed data
|
||||
}),
|
||||
certificates: [cert]
|
||||
certificates: certs
|
||||
});
|
||||
|
||||
const cmsContent = new ContentInfo({
|
||||
@@ -21,22 +20,3 @@ export const convertRawCertToPkcs7 = (rawCertificate: ArrayBuffer) => {
|
||||
|
||||
return base64Pkcs7;
|
||||
};
|
||||
|
||||
export const checkCertValidityAgainstChain = async (cert: X509Certificate, chainCerts: X509Certificate[]) => {
|
||||
let isSslClientCertValid = true;
|
||||
let certToVerify = cert;
|
||||
|
||||
for await (const issuerCert of chainCerts) {
|
||||
if (
|
||||
await certToVerify.verify({
|
||||
publicKey: issuerCert.publicKey
|
||||
})
|
||||
) {
|
||||
certToVerify = issuerCert; // Move to the next certificate in the chain
|
||||
} else {
|
||||
isSslClientCertValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return isSslClientCertValid;
|
||||
};
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import * as x509 from "@peculiar/x509";
|
||||
|
||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||
import { BadRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
|
||||
|
||||
import { checkCertValidityAgainstChain, convertCertPemToRaw } from "../certificate/certificate-fns";
|
||||
import { TCertificateAuthorityCertDALFactory } from "../certificate-authority/certificate-authority-cert-dal";
|
||||
import { TCertificateAuthorityDALFactory } from "../certificate-authority/certificate-authority-dal";
|
||||
import { getCaCertChains } from "../certificate-authority/certificate-authority-fns";
|
||||
import { getCaCertChain, getCaCertChains } from "../certificate-authority/certificate-authority-fns";
|
||||
import { TCertificateAuthorityServiceFactory } from "../certificate-authority/certificate-authority-service";
|
||||
import { TCertificateTemplateDALFactory } from "../certificate-template/certificate-template-dal";
|
||||
import { TCertificateTemplateServiceFactory } from "../certificate-template/certificate-template-service";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { TProjectDALFactory } from "../project/project-dal";
|
||||
import { checkCertValidityAgainstChain, convertRawCertToPkcs7 } from "./certificate-est-fns";
|
||||
import { convertRawCertsToPkcs7 } from "./certificate-est-fns";
|
||||
|
||||
type TCertificateEstServiceFactoryDep = {
|
||||
certificateAuthorityService: Pick<TCertificateAuthorityServiceFactory, "signCertFromCa">;
|
||||
certificateTemplateService: Pick<TCertificateTemplateServiceFactory, "getEstConfiguration" | "getCertTemplate">;
|
||||
certificateTemplateService: Pick<TCertificateTemplateServiceFactory, "getEstConfiguration">;
|
||||
certificateTemplateDAL: Pick<TCertificateTemplateDALFactory, "findById">;
|
||||
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
|
||||
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "find">;
|
||||
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "find" | "findById">;
|
||||
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
|
||||
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
|
||||
};
|
||||
@@ -155,7 +156,7 @@ export const certificateEstServiceFactory = ({
|
||||
csr
|
||||
});
|
||||
|
||||
return convertRawCertToPkcs7(rawCertificate);
|
||||
return convertRawCertsToPkcs7([rawCertificate]);
|
||||
};
|
||||
|
||||
const simpleEnroll = async ({
|
||||
@@ -228,10 +229,43 @@ export const certificateEstServiceFactory = ({
|
||||
csr
|
||||
});
|
||||
|
||||
return convertRawCertToPkcs7(rawCertificate);
|
||||
return convertRawCertsToPkcs7([rawCertificate]);
|
||||
};
|
||||
|
||||
const getCaCerts = async ({ certificateTemplateId }: { certificateTemplateId: string }) => {
|
||||
const certTemplate = await certificateTemplateDAL.findById(certificateTemplateId);
|
||||
if (!certTemplate) {
|
||||
throw new NotFoundError({
|
||||
message: "Certificate template not found"
|
||||
});
|
||||
}
|
||||
|
||||
const ca = await certificateAuthorityDAL.findById(certTemplate.caId);
|
||||
if (!ca) {
|
||||
throw new NotFoundError({
|
||||
message: "Certificate Authority not found"
|
||||
});
|
||||
}
|
||||
|
||||
const { caCert, caCertChain } = await getCaCertChain({
|
||||
caCertId: ca.activeCaCertId as string,
|
||||
certificateAuthorityDAL,
|
||||
certificateAuthorityCertDAL,
|
||||
projectDAL,
|
||||
kmsService
|
||||
});
|
||||
|
||||
const caCertRaw = convertCertPemToRaw(caCert);
|
||||
const caParentsRaw = caCertChain
|
||||
.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g)
|
||||
?.map(convertCertPemToRaw);
|
||||
|
||||
return convertRawCertsToPkcs7([caCertRaw, ...(caParentsRaw ?? [])]);
|
||||
};
|
||||
|
||||
return {
|
||||
simpleEnroll,
|
||||
simpleReenroll
|
||||
simpleReenroll,
|
||||
getCaCerts
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,3 +24,26 @@ export const revocationReasonToCrlCode = (crlReason: CrlReason) => {
|
||||
return x509.X509CrlReason.unspecified;
|
||||
}
|
||||
};
|
||||
|
||||
export const convertCertPemToRaw = (certPem: string) => {
|
||||
return new x509.X509Certificate(certPem).rawData;
|
||||
};
|
||||
|
||||
export const checkCertValidityAgainstChain = async (cert: x509.X509Certificate, chainCerts: x509.X509Certificate[]) => {
|
||||
let isSslClientCertValid = true;
|
||||
let certToVerify = cert;
|
||||
|
||||
for await (const issuerCert of chainCerts) {
|
||||
if (
|
||||
await certToVerify.verify({
|
||||
publicKey: issuerCert.publicKey
|
||||
})
|
||||
) {
|
||||
certToVerify = issuerCert; // Move to the next certificate in the chain
|
||||
} else {
|
||||
isSslClientCertValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return isSslClientCertValid;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user