Modularized repetitive ca + chain logic

This commit is contained in:
Tuan Dang
2024-06-10 22:37:20 -07:00
parent bf430925e4
commit 868d0345d6
4 changed files with 227 additions and 114 deletions
@@ -5,7 +5,7 @@ import { BadRequestError } from "@app/lib/errors";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns"; import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
import { CertKeyAlgorithm, CertStatus } from "../certificate/certificate-types"; import { CertKeyAlgorithm, CertStatus } from "../certificate/certificate-types";
import { TDNParts, TRebuildCaCrlDTO } from "./certificate-authority-types"; import { TDNParts, TGetCaCertChainDTO, TGetCaCredentialsDTO, TRebuildCaCrlDTO } from "./certificate-authority-types";
export const createDistinguishedName = (parts: TDNParts) => { export const createDistinguishedName = (parts: TDNParts) => {
const dnParts = []; const dnParts = [];
@@ -51,6 +51,101 @@ export const keyAlgorithmToAlgCfg = (keyAlgorithm: CertKeyAlgorithm) => {
} }
}; };
/**
* Return the public and private key of CA with id [caId]
* Note: credentials are returned as crypto.webcrypto.CryptoKey
* suitable for use with @peculiar/x509 module
*/
export const getCaCredentials = async ({
caId,
certificateAuthorityDAL,
certificateAuthoritySecretDAL,
projectDAL,
kmsService
}: TGetCaCredentialsDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" });
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId });
if (!caSecret) throw new BadRequestError({ message: "CA secret not found" });
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const decryptedPrivateKey = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caSecret.encryptedPrivateKey
});
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const skObj = crypto.createPrivateKey({ key: decryptedPrivateKey, format: "der", type: "pkcs8" });
const caPrivateKey = await crypto.subtle.importKey(
"pkcs8",
skObj.export({ format: "der", type: "pkcs8" }),
alg,
true,
["sign"]
);
const pkObj = crypto.createPublicKey(skObj);
const caPublicKey = await crypto.subtle.importKey("spki", pkObj.export({ format: "der", type: "spki" }), alg, true, [
"verify"
]);
return {
caPrivateKey,
caPublicKey
};
};
/**
* Return the decrypted pem-encoded certificate and certificate chain
* for CA with id [caId].
*/
export const getCaCertChain = async ({
caId,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
kmsService
}: TGetCaCertChainDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" });
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const decryptedCaCert = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificate
});
const caCertObj = new x509.X509Certificate(decryptedCaCert);
const decryptedChain = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificateChain
});
return {
caCert: caCertObj.toString("pem"),
caCertChain: decryptedChain.toString("utf-8"),
serialNumber: caCertObj.serialNumber
};
};
/**
* Rebuilds the certificate revocation list (CRL)
* for CA with id [caId]
*/
export const rebuildCaCrl = async ({ export const rebuildCaCrl = async ({
caId, caId,
certificateAuthorityDAL, certificateAuthorityDAL,
@@ -16,7 +16,12 @@ import { CertKeyAlgorithm, CertStatus } from "../certificate/certificate-types";
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal"; import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal"; import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal"; import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import { createDistinguishedName, keyAlgorithmToAlgCfg } from "./certificate-authority-fns"; import {
createDistinguishedName,
getCaCertChain,
getCaCredentials,
keyAlgorithmToAlgCfg
} from "./certificate-authority-fns";
import { TCertificateAuthorityQueueFactory } from "./certificate-authority-queue"; import { TCertificateAuthorityQueueFactory } from "./certificate-authority-queue";
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal"; import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";
import { import {
@@ -65,7 +70,7 @@ export const certificateAuthorityServiceFactory = ({
permissionService permissionService
}: TCertificateAuthorityServiceFactoryDep) => { }: TCertificateAuthorityServiceFactoryDep) => {
/** /**
* Generates a new root or intermediate CA * Generates new root or intermediate CA
*/ */
const createCa = async ({ const createCa = async ({
projectSlug, projectSlug,
@@ -237,6 +242,9 @@ export const certificateAuthorityServiceFactory = ({
return newCa; return newCa;
}; };
/**
* Return CA with id [caId]
*/
const getCaById = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaDTO) => { const getCaById = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaDTO) => {
const ca = await certificateAuthorityDAL.findById(caId); const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" }); if (!ca) throw new BadRequestError({ message: "CA not found" });
@@ -256,6 +264,10 @@ export const certificateAuthorityServiceFactory = ({
return ca; return ca;
}; };
/**
* Update CA with id [caId].
* Note: Used to enable/disable CA
*/
const updateCaById = async ({ caId, status, actorId, actorAuthMethod, actor, actorOrgId }: TUpdateCaDTO) => { const updateCaById = async ({ caId, status, actorId, actorAuthMethod, actor, actorOrgId }: TUpdateCaDTO) => {
const ca = await certificateAuthorityDAL.findById(caId); const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" }); if (!ca) throw new BadRequestError({ message: "CA not found" });
@@ -278,6 +290,9 @@ export const certificateAuthorityServiceFactory = ({
return updatedCa; return updatedCa;
}; };
/**
* Delete CA with id [caId]
*/
const deleteCaById = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCaDTO) => { const deleteCaById = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCaDTO) => {
const ca = await certificateAuthorityDAL.findById(caId); const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" }); if (!ca) throw new BadRequestError({ message: "CA not found" });
@@ -301,7 +316,7 @@ export const certificateAuthorityServiceFactory = ({
}; };
/** /**
* Generates a CSR for a CA * Return certificate signing request (CSR) made with CA with id [caId]
*/ */
const getCaCsr = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaCsrDTO) => { const getCaCsr = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaCsrDTO) => {
const ca = await certificateAuthorityDAL.findById(caId); const ca = await certificateAuthorityDAL.findById(caId);
@@ -325,33 +340,22 @@ export const certificateAuthorityServiceFactory = ({
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id }); const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
if (caCert) throw new BadRequestError({ message: "CA already has a certificate installed" }); if (caCert) throw new BadRequestError({ message: "CA already has a certificate installed" });
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id }); const { caPrivateKey, caPublicKey } = await getCaCredentials({
caId,
const keyId = await getProjectKmsCertificateKeyId({ certificateAuthorityDAL,
projectId: ca.projectId, certificateAuthoritySecretDAL,
projectDAL, projectDAL,
kmsService kmsService
}); });
const privateKey = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caSecret.encryptedPrivateKey
});
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm); const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
"sign"
]);
const pkObj = crypto.createPublicKey(skObj);
const pk = await crypto.subtle.importKey("spki", pkObj.export({ format: "der", type: "spki" }), alg, true, [
"verify"
]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({ const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
name: ca.dn, name: ca.dn,
keys: { privateKey: sk, publicKey: pk }, keys: {
privateKey: caPrivateKey,
publicKey: caPublicKey
},
signingAlgorithm: alg, signingAlgorithm: alg,
extensions: [ extensions: [
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
@@ -388,30 +392,18 @@ export const certificateAuthorityServiceFactory = ({
ProjectPermissionSub.CertificateAuthorities ProjectPermissionSub.CertificateAuthorities
); );
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id }); const { caCert, caCertChain, serialNumber } = await getCaCertChain({
caId,
const keyId = await getProjectKmsCertificateKeyId({ certificateAuthorityDAL,
projectId: ca.projectId, certificateAuthorityCertDAL,
projectDAL, projectDAL,
kmsService kmsService
}); });
const decryptedCaCert = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificate
});
const certObj = new x509.X509Certificate(decryptedCaCert);
const decryptedChain = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificateChain
});
return { return {
certificate: certObj.toString("pem"), certificate: caCert,
certificateChain: decryptedChain.toString("utf-8"), certificateChain: caCertChain,
serialNumber: certObj.serialNumber serialNumber
}; };
}; };
@@ -456,18 +448,6 @@ export const certificateAuthorityServiceFactory = ({
}); });
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id }); const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
const privateKey = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caSecret.encryptedPrivateKey
});
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
"sign"
]);
const decryptedCaCert = await kmsService.decrypt({ const decryptedCaCert = await kmsService.decrypt({
kmsId: keyId, kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificate cipherTextBlob: caCert.encryptedCertificate
@@ -507,6 +487,14 @@ export const certificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" }); throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
} }
const { caPrivateKey } = await getCaCredentials({
caId: ca.id,
certificateAuthorityDAL,
certificateAuthoritySecretDAL,
projectDAL,
kmsService
});
const serialNumber = crypto.randomBytes(32).toString("hex"); const serialNumber = crypto.randomBytes(32).toString("hex");
const intermediateCert = await x509.X509CertificateGenerator.create({ const intermediateCert = await x509.X509CertificateGenerator.create({
serialNumber, serialNumber,
@@ -514,7 +502,7 @@ export const certificateAuthorityServiceFactory = ({
issuer: caCertObj.subject, issuer: caCertObj.subject,
notBefore: notBeforeDate, notBefore: notBeforeDate,
notAfter: notAfterDate, notAfter: notAfterDate,
signingKey: sk, signingKey: caPrivateKey,
publicKey: csrObj.publicKey, publicKey: csrObj.publicKey,
signingAlgorithm: alg, signingAlgorithm: alg,
extensions: [ extensions: [
@@ -531,21 +519,27 @@ export const certificateAuthorityServiceFactory = ({
] ]
}); });
const caCertChain = await kmsService.decrypt({ const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({
kmsId: keyId, caId,
cipherTextBlob: caCert.encryptedCertificateChain certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
kmsService
}); });
const certificateChain = `${caCertObj.toString("pem")}\n${caCertChain.toString("utf-8")}`.trim();
return { return {
certificate: intermediateCert.toString("pem"), certificate: intermediateCert.toString("pem"),
issuingCaCertificate: caCertObj.toString("pem"), issuingCaCertificate,
certificateChain, certificateChain: `${issuingCaCertificate}\n${caCertChain}`.trim(),
serialNumber: intermediateCert.serialNumber serialNumber: intermediateCert.serialNumber
}; };
}; };
/**
* Import certificate for (un-installed) CA with id [caId].
* Note: Can be used to import an external certificate and certificate chain
* to be installed into the CA.
*/
const importCertToCa = async ({ const importCertToCa = async ({
caId, caId,
actorId, actorId,
@@ -643,6 +637,9 @@ export const certificateAuthorityServiceFactory = ({
}); });
}; };
/**
* Return new leaf certificate issued by CA with id [caId]
*/
const issueCertFromCa = async ({ const issueCertFromCa = async ({
caId, caId,
commonName, commonName,
@@ -685,33 +682,6 @@ export const certificateAuthorityServiceFactory = ({
const caCertObj = new x509.X509Certificate(decryptedCaCert); const caCertObj = new x509.X509Certificate(decryptedCaCert);
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
const privateKey = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caSecret.encryptedPrivateKey
});
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const caSkObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const caSk = await crypto.subtle.importKey("pkcs8", caSkObj.export({ format: "der", type: "pkcs8" }), alg, true, [
"sign"
]);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
name: `CN=${commonName}`,
keys: leafKeys,
signingAlgorithm: alg,
extensions: [
// eslint-disable-next-line no-bitwise
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment)
],
attributes: [new x509.ChallengePasswordAttribute("password")]
});
const notBeforeDate = notBefore ? new Date(notBefore) : new Date(); const notBeforeDate = notBefore ? new Date(notBefore) : new Date();
let notAfterDate = new Date(new Date().setFullYear(new Date().getFullYear() + 1)); let notAfterDate = new Date(new Date().setFullYear(new Date().getFullYear() + 1));
@@ -737,6 +707,28 @@ export const certificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" }); throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
} }
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
name: `CN=${commonName}`,
keys: leafKeys,
signingAlgorithm: alg,
extensions: [
// eslint-disable-next-line no-bitwise
new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment)
],
attributes: [new x509.ChallengePasswordAttribute("password")]
});
const { caPrivateKey } = await getCaCredentials({
caId: ca.id,
certificateAuthorityDAL,
certificateAuthoritySecretDAL,
projectDAL,
kmsService
});
const serialNumber = crypto.randomBytes(32).toString("hex"); const serialNumber = crypto.randomBytes(32).toString("hex");
const leafCert = await x509.X509CertificateGenerator.create({ const leafCert = await x509.X509CertificateGenerator.create({
serialNumber, serialNumber,
@@ -744,7 +736,7 @@ export const certificateAuthorityServiceFactory = ({
issuer: caCertObj.subject, issuer: caCertObj.subject,
notBefore: notBeforeDate, notBefore: notBeforeDate,
notAfter: notAfterDate, notAfter: notAfterDate,
signingKey: caSk, signingKey: caPrivateKey,
publicKey: csrObj.publicKey, publicKey: csrObj.publicKey,
signingAlgorithm: alg, signingAlgorithm: alg,
extensions: [ extensions: [
@@ -763,11 +755,6 @@ export const certificateAuthorityServiceFactory = ({
plainText: Buffer.from(new Uint8Array(leafCert.rawData)) plainText: Buffer.from(new Uint8Array(leafCert.rawData))
}); });
const caCertChain = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificateChain
});
await certificateDAL.transaction(async (tx) => { await certificateDAL.transaction(async (tx) => {
const cert = await certificateDAL.create( const cert = await certificateDAL.create(
{ {
@@ -792,19 +779,25 @@ export const certificateAuthorityServiceFactory = ({
return cert; return cert;
}); });
const certificateChain = `${caCertObj.toString("pem")}\n${caCertChain.toString("utf-8")}`.trim(); const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({
caId: ca.id,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
kmsService
});
return { return {
certificate: leafCert.toString("pem"), certificate: leafCert.toString("pem"),
certificateChain, certificateChain: `${issuingCaCertificate}\n${caCertChain}`.trim(),
issuingCaCertificate: caCertObj.toString("pem"), issuingCaCertificate,
privateKey: skLeaf, privateKey: skLeaf,
serialNumber serialNumber
}; };
}; };
/** /**
* Return the Certificate Revocation List (CRL) for the CA * Return the Certificate Revocation List (CRL) for CA with id [caId]
*/ */
const getCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCrl) => { const getCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCrl) => {
const ca = await certificateAuthorityDAL.findById(caId); const ca = await certificateAuthorityDAL.findById(caId);
@@ -4,6 +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 { CertKeyAlgorithm } from "../certificate/certificate-types"; import { CertKeyAlgorithm } from "../certificate/certificate-types";
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal"; import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-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";
@@ -94,6 +95,22 @@ export type TDNParts = {
locality?: string; locality?: string;
}; };
export type TGetCaCredentialsDTO = {
caId: string;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decrypt" | "generateKmsKey">;
};
export type TGetCaCertChainDTO = {
caId: string;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decrypt" | "generateKmsKey">;
};
export type TRebuildCaCrlDTO = { export type TRebuildCaCrlDTO = {
caId: string; caId: string;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">; certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
@@ -13,7 +13,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 { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns"; import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
import { rebuildCaCrl } from "../certificate-authority/certificate-authority-fns"; import { getCaCertChain, rebuildCaCrl } from "../certificate-authority/certificate-authority-fns";
import { revocationReasonToCrlCode } from "./certificate-fns"; import { revocationReasonToCrlCode } from "./certificate-fns";
import { CertStatus, TDeleteCertDTO, TGetCertCertDTO, TGetCertDTO, TRevokeCertDTO } from "./certificate-types"; import { CertStatus, TDeleteCertDTO, TGetCertCertDTO, TGetCertDTO, TRevokeCertDTO } from "./certificate-types";
@@ -42,6 +42,9 @@ export const certificateServiceFactory = ({
kmsService, kmsService,
permissionService permissionService
}: TCertificateServiceFactoryDep) => { }: TCertificateServiceFactoryDep) => {
/**
* Return details for certificate with serial number [serialNumber]
*/
const getCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertDTO) => { const getCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertDTO) => {
const cert = await certificateDAL.findOne({ serialNumber }); const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId); const ca = await certificateAuthorityDAL.findById(cert.caId);
@@ -59,6 +62,9 @@ export const certificateServiceFactory = ({
return cert; return cert;
}; };
/**
* Delete certificate with serial number [serialNumber]
*/
const deleteCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCertDTO) => { const deleteCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCertDTO) => {
const cert = await certificateDAL.findOne({ serialNumber }); const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId); const ca = await certificateAuthorityDAL.findById(cert.caId);
@@ -77,6 +83,11 @@ export const certificateServiceFactory = ({
return deletedCert; return deletedCert;
}; };
/**
* Revoke certificate with serial number [serialNumber].
* Note: Revoking a certificate adds it to the certificate revocation list (CRL)
* of its issuing CA
*/
const revokeCert = async ({ const revokeCert = async ({
serialNumber, serialNumber,
revocationReason, revocationReason,
@@ -126,10 +137,13 @@ export const certificateServiceFactory = ({
return { revokedAt }; return { revokedAt };
}; };
/**
* Return certificate body and certificate chain for certificate with
* serial number [serialNumber]
*/
const getCertCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertCertDTO) => { const getCertCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertCertDTO) => {
const cert = await certificateDAL.findOne({ serialNumber }); const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId); const ca = await certificateAuthorityDAL.findById(cert.caId);
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
@@ -154,25 +168,19 @@ export const certificateServiceFactory = ({
cipherTextBlob: certCert.encryptedCertificate cipherTextBlob: certCert.encryptedCertificate
}); });
const caCertChain = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCert.encryptedCertificateChain
});
const certObj = new x509.X509Certificate(decryptedCert); const certObj = new x509.X509Certificate(decryptedCert);
const decryptedCaCert = await kmsService.decrypt({ const { caCert, caCertChain } = await getCaCertChain({
kmsId: keyId, caId: ca.id,
cipherTextBlob: caCert.encryptedCertificate certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
kmsService
}); });
const caCertObj = new x509.X509Certificate(decryptedCaCert);
const certificateChain = `${caCertObj.toString("pem")}\n${caCertChain.toString("utf-8")}`.trim();
return { return {
certificate: certObj.toString("pem"), certificate: certObj.toString("pem"),
certificateChain, certificateChain: `${caCert}\n${caCertChain}`.trim(),
serialNumber: certObj.serialNumber serialNumber: certObj.serialNumber
}; };
}; };