mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 00:29:34 +00:00
Finish preliminary CA renewal with same key pair
This commit is contained in:
@@ -22,7 +22,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
if (!hasVersionColumn) {
|
||||
await knex.schema.alterTable(TableName.CertificateAuthorityCert, (t) => {
|
||||
t.integer("version").nullable();
|
||||
// t.dropUnique(["caId"]);
|
||||
t.dropUnique(["caId"]);
|
||||
});
|
||||
|
||||
await knex(TableName.CertificateAuthorityCert).update({ version: 1 }).whereNull("version");
|
||||
@@ -48,45 +48,17 @@ export async function up(knex: Knex): Promise<void> {
|
||||
)
|
||||
`);
|
||||
|
||||
// await knex.raw(`
|
||||
// UPDATE ${TableName.CertificateAuthorityCert} cert
|
||||
// SET caSecretId = (
|
||||
// SELECT sec.id
|
||||
// FROM ${TableName.CertificateAuthoritySecret} sec
|
||||
// WHERE sec."caId" = cert."caId"
|
||||
// )
|
||||
// `);
|
||||
|
||||
// await knex(TableName.CertificateAuthorityCert).update({
|
||||
// caSecretId: knex(TableName.CertificateAuthoritySecret)
|
||||
// .select("id")
|
||||
// .whereRaw("?? = ??", ["CertificateAuthoritySecret.caId", "CertificateAuthorityCert.caId"])
|
||||
// });
|
||||
|
||||
// await knex(TableName.CertificateAuthorityCert).update({
|
||||
// caSecretId: function () {
|
||||
// this.select("id")
|
||||
// .from(TableName.CertificateAuthoritySecret)
|
||||
// .whereRaw("??.?? = ??.??", [
|
||||
// TableName.CertificateAuthoritySecret,
|
||||
// "caId",
|
||||
// TableName.CertificateAuthorityCert,
|
||||
// "caId"
|
||||
// ]);
|
||||
// }
|
||||
// });
|
||||
|
||||
await knex.schema.alterTable(TableName.CertificateAuthorityCert, (t) => {
|
||||
t.uuid("caSecretId").notNullable().alter();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if (await knex.schema.hasTable(TableName.CertificateAuthoritySecret)) {
|
||||
// await knex.schema.alterTable(TableName.CertificateAuthoritySecret, (t) => {
|
||||
// t.dropUnique(["caId"]);
|
||||
// });
|
||||
// }
|
||||
if (await knex.schema.hasTable(TableName.CertificateAuthoritySecret)) {
|
||||
await knex.schema.alterTable(TableName.CertificateAuthoritySecret, (t) => {
|
||||
t.dropUnique(["caId"]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
|
||||
@@ -130,6 +130,7 @@ export enum EventType {
|
||||
GET_CA = "get-certificate-authority",
|
||||
UPDATE_CA = "update-certificate-authority",
|
||||
DELETE_CA = "delete-certificate-authority",
|
||||
RENEW_CA = "renew-certificate-authority",
|
||||
GET_CA_CSR = "get-certificate-authority-csr",
|
||||
GET_CA_CERTS = "get-certificate-authority-certs",
|
||||
GET_CA_CERT = "get-certificate-authority-cert",
|
||||
@@ -1094,6 +1095,14 @@ interface DeleteCa {
|
||||
};
|
||||
}
|
||||
|
||||
interface RenewCa {
|
||||
type: EventType.RENEW_CA;
|
||||
metadata: {
|
||||
caId: string;
|
||||
dn: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface GetCaCsr {
|
||||
type: EventType.GET_CA_CSR;
|
||||
metadata: {
|
||||
@@ -1336,6 +1345,7 @@ export type Event =
|
||||
| GetCa
|
||||
| UpdateCa
|
||||
| DeleteCa
|
||||
| RenewCa
|
||||
| GetCaCsr
|
||||
| GetCaCerts
|
||||
| GetCaCert
|
||||
|
||||
@@ -277,7 +277,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
|
||||
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/:caId/renew", // TODO
|
||||
url: "/:caId/renew",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
@@ -300,27 +300,27 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { certificate, certificateChain, serialNumber } = await server.services.certificateAuthority.renewCaCert({
|
||||
caId: req.params.caId,
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
});
|
||||
const { certificate, certificateChain, serialNumber, ca } =
|
||||
await server.services.certificateAuthority.renewCaCert({
|
||||
caId: req.params.caId,
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
});
|
||||
|
||||
// await server.services.auditLog.createAuditLog({
|
||||
// ...req.auditLogInfo,
|
||||
// projectId: ca.projectId,
|
||||
// event: {
|
||||
// type: EventType.SIGN_INTERMEDIATE,
|
||||
// metadata: {
|
||||
// caId: ca.id,
|
||||
// dn: ca.dn,
|
||||
// serialNumber
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
projectId: ca.projectId,
|
||||
event: {
|
||||
type: EventType.RENEW_CA,
|
||||
metadata: {
|
||||
caId: ca.id,
|
||||
dn: ca.dn
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
certificate,
|
||||
|
||||
@@ -61,6 +61,8 @@ 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
|
||||
*
|
||||
* TODO: Update to get latest CA Secret once support for CA renewal with new key pair is added
|
||||
*/
|
||||
export const getCaCredentials = async ({
|
||||
caId,
|
||||
|
||||
@@ -387,6 +387,8 @@ export const certificateAuthorityServiceFactory = ({
|
||||
/**
|
||||
* Renew certificate for CA with id [caId]
|
||||
* Note: Currently implements CA renewal with same key-pair only
|
||||
*
|
||||
* TODO: check rebuilt chain?
|
||||
*/
|
||||
const renewCaCert = async ({ caId, notAfter, actorId, actorAuthMethod, actor, actorOrgId }: TRenewCaCertDTO) => {
|
||||
const ca = await certificateAuthorityDAL.findById(caId);
|
||||
@@ -607,8 +609,18 @@ export const certificateAuthorityServiceFactory = ({
|
||||
plainText: Buffer.from(new Uint8Array(intermediateCert.rawData))
|
||||
});
|
||||
|
||||
const { caCert: parentCaCertificate, caCertChain: parentCaCertChain } = await getCaCertChain({
|
||||
caId: parentCa.id,
|
||||
certificateAuthorityDAL,
|
||||
certificateAuthorityCertDAL,
|
||||
projectDAL,
|
||||
kmsService
|
||||
});
|
||||
|
||||
certificateChain = `${parentCaCertificate}\n${parentCaCertChain}`.trim();
|
||||
|
||||
const { cipherTextBlob: encryptedCertificateChain } = await kmsEncryptor({
|
||||
plainText: Buffer.alloc(0)
|
||||
plainText: Buffer.from(certificateChain)
|
||||
});
|
||||
|
||||
await certificateAuthorityDAL.transaction(async (tx) => {
|
||||
@@ -635,16 +647,7 @@ export const certificateAuthorityServiceFactory = ({
|
||||
);
|
||||
});
|
||||
|
||||
const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({
|
||||
caId,
|
||||
certificateAuthorityDAL,
|
||||
certificateAuthorityCertDAL,
|
||||
projectDAL,
|
||||
kmsService
|
||||
});
|
||||
|
||||
certificate = intermediateCert.toString("pem");
|
||||
certificateChain = `${issuingCaCertificate}\n${caCertChain}`.trim();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -657,7 +660,8 @@ export const certificateAuthorityServiceFactory = ({
|
||||
return {
|
||||
certificate,
|
||||
certificateChain,
|
||||
serialNumber
|
||||
serialNumber,
|
||||
ca
|
||||
};
|
||||
};
|
||||
|
||||
@@ -938,13 +942,31 @@ export const certificateAuthorityServiceFactory = ({
|
||||
plainText: Buffer.from(certificateChain)
|
||||
});
|
||||
|
||||
// TODO: validate that >latest< public-private key of CA is used to sign the certificate
|
||||
const { caSecret, caPublicKey } = await getCaCredentials({
|
||||
caId: ca.id,
|
||||
certificateAuthorityDAL,
|
||||
certificateAuthoritySecretDAL,
|
||||
projectDAL,
|
||||
kmsService
|
||||
});
|
||||
|
||||
const isCaAndCertPublicKeySame = Buffer.from(await crypto.subtle.exportKey("spki", caPublicKey)).equals(
|
||||
Buffer.from(certObj.publicKey.rawData)
|
||||
);
|
||||
|
||||
if (!isCaAndCertPublicKeySame) {
|
||||
throw new BadRequestError({ message: "CA and certificate public key do not match" });
|
||||
}
|
||||
|
||||
await certificateAuthorityCertDAL.transaction(async (tx) => {
|
||||
await certificateAuthorityCertDAL.create(
|
||||
{
|
||||
caId: ca.id,
|
||||
encryptedCertificate,
|
||||
encryptedCertificateChain,
|
||||
version: 1
|
||||
version: 1,
|
||||
caSecretId: caSecret.id
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user