diff --git a/backend/src/db/migrations/20240802181855_ca-cert-version.ts b/backend/src/db/migrations/20240802181855_ca-cert-version.ts index 805cf0a53..24eca185d 100644 --- a/backend/src/db/migrations/20240802181855_ca-cert-version.ts +++ b/backend/src/db/migrations/20240802181855_ca-cert-version.ts @@ -62,6 +62,26 @@ export async function up(knex: Knex): Promise { t.dropUnique(["caId"]); }); } + + if (await knex.schema.hasTable(TableName.Certificate)) { + await knex.schema.alterTable(TableName.Certificate, (t) => { + t.uuid("caCertId").nullable(); + t.foreign("caCertId").references("id").inTable(TableName.CertificateAuthorityCert); + }); + + await knex.raw(` + UPDATE "${TableName.Certificate}" cert + SET "caCertId" = ( + SELECT caCert.id + FROM "${TableName.CertificateAuthorityCert}" caCert + WHERE caCert."caId" = cert."caId" + ) + `); + + await knex.schema.alterTable(TableName.Certificate, (t) => { + t.uuid("caCertId").notNullable().alter(); + }); + } } export async function down(knex: Knex): Promise { @@ -86,4 +106,12 @@ export async function down(knex: Knex): Promise { }); } } + + if (await knex.schema.hasTable(TableName.Certificate)) { + if (await knex.schema.hasColumn(TableName.Certificate, "caCertId")) { + await knex.schema.alterTable(TableName.Certificate, (t) => { + t.dropColumn("caCertId"); + }); + } + } } diff --git a/backend/src/db/schemas/certificates.ts b/backend/src/db/schemas/certificates.ts index 833396fb1..cb14d05f9 100644 --- a/backend/src/db/schemas/certificates.ts +++ b/backend/src/db/schemas/certificates.ts @@ -20,7 +20,8 @@ export const CertificatesSchema = z.object({ notAfter: z.date(), revokedAt: z.date().nullable().optional(), revocationReason: z.number().nullable().optional(), - altNames: z.string().default("").nullable().optional() + altNames: z.string().default("").nullable().optional(), + caCertId: z.string().uuid() }); export type TCertificates = z.infer; diff --git a/backend/src/services/certificate-authority/certificate-authority-fns.ts b/backend/src/services/certificate-authority/certificate-authority-fns.ts index bf9f639e8..4e3df1173 100644 --- a/backend/src/services/certificate-authority/certificate-authority-fns.ts +++ b/backend/src/services/certificate-authority/certificate-authority-fns.ts @@ -195,20 +195,18 @@ export const getCaCertChains = async ({ /** * Return the decrypted pem-encoded certificate and certificate chain - * for CA with id [caId]. + * corresponding to CA certificate with id [caCertId]. */ export const getCaCertChain = async ({ - caId, + caCertId, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL, kmsService }: TGetCaCertChainDTO) => { - const ca = await certificateAuthorityDAL.findById(caId); - if (!ca) throw new BadRequestError({ message: "CA not found" }); - if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" }); - - const caCert = await certificateAuthorityCertDAL.findById(ca.activeCaCertId); + const caCert = await certificateAuthorityCertDAL.findById(caCertId); + if (!caCert) throw new BadRequestError({ message: "CA certificate not found" }); + const ca = await certificateAuthorityDAL.findById(caCert.caId); const keyId = await getProjectKmsCertificateKeyId({ projectId: ca.projectId, diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts index 68d9bbf01..b63ec9ba9 100644 --- a/backend/src/services/certificate-authority/certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/certificate-authority-service.ts @@ -617,7 +617,7 @@ export const certificateAuthorityServiceFactory = ({ }); const { caCert: parentCaCertificate, caCertChain: parentCaCertChain } = await getCaCertChain({ - caId: parentCa.id, + caCertId: parentCa.activeCaCertId, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL, @@ -704,11 +704,11 @@ export const certificateAuthorityServiceFactory = ({ /** * Return current certificate and certificate chain for CA - * get latest?? ca cert */ const getCaCert = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaCertDTO) => { const ca = await certificateAuthorityDAL.findById(caId); if (!ca) throw new BadRequestError({ message: "CA not found" }); + if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" }); const { permission } = await permissionService.getProjectPermission( actor, @@ -724,7 +724,7 @@ export const certificateAuthorityServiceFactory = ({ ); const { caCert, caCertChain, serialNumber } = await getCaCertChain({ - caId, + caCertId: ca.activeCaCertId, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL, @@ -860,7 +860,7 @@ export const certificateAuthorityServiceFactory = ({ }); const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({ - caId, + caCertId: ca.activeCaCertId, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL, @@ -1166,6 +1166,7 @@ export const certificateAuthorityServiceFactory = ({ const cert = await certificateDAL.create( { caId: ca.id, + caCertId: caCert.id, status: CertStatus.ACTIVE, friendlyName: friendlyName || commonName, commonName, @@ -1189,7 +1190,7 @@ export const certificateAuthorityServiceFactory = ({ }); const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({ - caId: ca.id, + caCertId: caCert.id, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL, @@ -1369,6 +1370,7 @@ export const certificateAuthorityServiceFactory = ({ const cert = await certificateDAL.create( { caId: ca.id, + caCertId: caCert.id, status: CertStatus.ACTIVE, friendlyName: friendlyName || csrObj.subject, commonName: cn, @@ -1392,7 +1394,7 @@ export const certificateAuthorityServiceFactory = ({ }); const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({ - caId: ca.id, + caCertId: ca.activeCaCertId, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL, diff --git a/backend/src/services/certificate-authority/certificate-authority-types.ts b/backend/src/services/certificate-authority/certificate-authority-types.ts index 91e76e49c..31a6e1629 100644 --- a/backend/src/services/certificate-authority/certificate-authority-types.ts +++ b/backend/src/services/certificate-authority/certificate-authority-types.ts @@ -132,7 +132,7 @@ export type TGetCaCertChainsDTO = { }; export type TGetCaCertChainDTO = { - caId: string; + caCertId: string; certificateAuthorityDAL: Pick; certificateAuthorityCertDAL: Pick; projectDAL: Pick; diff --git a/backend/src/services/certificate/certificate-service.ts b/backend/src/services/certificate/certificate-service.ts index 01f736c29..8dc2de901 100644 --- a/backend/src/services/certificate/certificate-service.ts +++ b/backend/src/services/certificate/certificate-service.ts @@ -180,7 +180,7 @@ export const certificateServiceFactory = ({ const certObj = new x509.X509Certificate(decryptedCert); const { caCert, caCertChain } = await getCaCertChain({ - caId: ca.id, + caCertId: cert.caCertId, certificateAuthorityDAL, certificateAuthorityCertDAL, projectDAL,