mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 12:29:26 +00:00
review fixes
This commit is contained in:
@@ -4,11 +4,6 @@ import { TableName } from "../schemas";
|
|||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
if (await knex.schema.hasTable(TableName.Certificate)) {
|
if (await knex.schema.hasTable(TableName.Certificate)) {
|
||||||
await knex.schema.alterTable(TableName.Certificate, (t) => {
|
|
||||||
t.uuid("caId").nullable().alter();
|
|
||||||
t.uuid("caCertId").nullable().alter();
|
|
||||||
});
|
|
||||||
|
|
||||||
const hasProjectIdColumn = await knex.schema.hasColumn(TableName.Certificate, "projectId");
|
const hasProjectIdColumn = await knex.schema.hasColumn(TableName.Certificate, "projectId");
|
||||||
if (!hasProjectIdColumn) {
|
if (!hasProjectIdColumn) {
|
||||||
await knex.transaction(async (trx) => {
|
await knex.transaction(async (trx) => {
|
||||||
@@ -29,6 +24,11 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.Certificate, (t) => {
|
||||||
|
t.uuid("caId").nullable().alter();
|
||||||
|
t.uuid("caCertId").nullable().alter();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectSlug: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.projectSlug),
|
projectSlug: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.projectSlug),
|
||||||
|
|
||||||
certificatePem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.certificatePem),
|
certificatePem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.certificatePem),
|
||||||
privateKeyPem: z.string().trim().describe(CERTIFICATES.IMPORT.privateKeyPem),
|
privateKeyPem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.privateKeyPem),
|
||||||
chainPem: z.string().trim().describe(CERTIFICATES.IMPORT.chainPem),
|
chainPem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.chainPem),
|
||||||
|
|
||||||
friendlyName: z.string().trim().optional().describe(CERTIFICATES.IMPORT.friendlyName),
|
friendlyName: z.string().trim().optional().describe(CERTIFICATES.IMPORT.friendlyName),
|
||||||
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATES.IMPORT.pkiCollectionId)
|
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATES.IMPORT.pkiCollectionId)
|
||||||
@@ -491,7 +491,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: cert.projectId,
|
projectId: cert.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_CERT,
|
type: EventType.GET_CERT_BODY,
|
||||||
metadata: {
|
metadata: {
|
||||||
certId: cert.id,
|
certId: cert.id,
|
||||||
cn: cert.commonName,
|
cn: cert.commonName,
|
||||||
|
|||||||
@@ -279,29 +279,49 @@ export const certificateServiceFactory = ({
|
|||||||
|
|
||||||
// Verify the certificate chain
|
// Verify the certificate chain
|
||||||
const chainCerts = splitPemChain(chainPem).map((pem) => new x509.X509Certificate(pem));
|
const chainCerts = splitPemChain(chainPem).map((pem) => new x509.X509Certificate(pem));
|
||||||
|
|
||||||
|
// Remove leaf cert from the chain if it's present
|
||||||
|
if (chainCerts[0].equal(leafCert)) {
|
||||||
|
chainCerts.splice(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (chainCerts.length === 0) {
|
if (chainCerts.length === 0) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Certificate chain must contain at least one issuer certificate"
|
message: "Certificate chain must contain at least one issuer certificate"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const chainValidationPromises = chainCerts.map((issuerCert) =>
|
// Verify leaf certificate is signed by the first certificate in the chain
|
||||||
leafCert.verify({ publicKey: issuerCert.publicKey }).catch(() => false)
|
const isLeafVerified = await leafCert.verify({ publicKey: chainCerts[0].publicKey }).catch(() => false);
|
||||||
);
|
if (!isLeafVerified) {
|
||||||
|
throw new BadRequestError({ message: "Leaf certificate verification against chain failed" });
|
||||||
|
}
|
||||||
|
|
||||||
const results = await Promise.all(chainValidationPromises);
|
// Verify the entire chain of trust
|
||||||
|
const verificationPromises = chainCerts.slice(0, -1).map(async (currentCert, index) => {
|
||||||
|
const issuerCert = chainCerts[index + 1];
|
||||||
|
return currentCert.verify({ publicKey: issuerCert.publicKey }).catch(() => false);
|
||||||
|
});
|
||||||
|
|
||||||
if (!results.some((result) => result === true)) {
|
const verificationResults = await Promise.all(verificationPromises);
|
||||||
throw new BadRequestError({ message: "Certificate chain verification failed" });
|
|
||||||
|
if (verificationResults.some((result) => !result)) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Certificate chain verification failed: broken trust chain"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify private key matches the certificate
|
// Verify private key matches the certificate
|
||||||
|
let privateKey;
|
||||||
try {
|
try {
|
||||||
const message = Buffer.from("certificate-verification-test");
|
privateKey = createPrivateKey(privateKeyPem);
|
||||||
|
} catch (err) {
|
||||||
|
throw new BadRequestError({ message: "Invalid private key format" });
|
||||||
|
}
|
||||||
|
|
||||||
const privateKey = createPrivateKey(privateKeyPem);
|
try {
|
||||||
|
const message = Buffer.from(Buffer.alloc(32));
|
||||||
const publicKey = createPublicKey(certificatePem);
|
const publicKey = createPublicKey(certificatePem);
|
||||||
|
|
||||||
const signature = sign(null, message, privateKey);
|
const signature = sign(null, message, privateKey);
|
||||||
const isValid = verify(null, message, publicKey, signature);
|
const isValid = verify(null, message, publicKey, signature);
|
||||||
|
|
||||||
@@ -309,7 +329,10 @@ export const certificateServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Private key does not match certificate" });
|
throw new BadRequestError({ message: "Private key does not match certificate" });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new BadRequestError({ message: "Invalid private key format" });
|
if (err instanceof BadRequestError) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
throw new BadRequestError({ message: "Error verifying private key against certificate" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get certificate attributes
|
// Get certificate attributes
|
||||||
@@ -394,15 +417,9 @@ export const certificateServiceFactory = ({
|
|||||||
|
|
||||||
return txCert;
|
return txCert;
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (
|
// @ts-expect-error We're expecting a database error
|
||||||
typeof error === "object" &&
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
error !== null &&
|
if (error?.error?.code === "23505") {
|
||||||
"error" in error &&
|
|
||||||
error.error &&
|
|
||||||
typeof error.error === "object" &&
|
|
||||||
"code" in error.error &&
|
|
||||||
error.error.code === "23505"
|
|
||||||
) {
|
|
||||||
throw new BadRequestError({ message: "Certificate serial already exists in your project" });
|
throw new BadRequestError({ message: "Certificate serial already exists in your project" });
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
+2
-2
@@ -22,8 +22,8 @@ import { CertificateContent } from "./CertificateContent";
|
|||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
certificatePem: z.string().trim().min(1, "Certificate PEM is required"),
|
certificatePem: z.string().trim().min(1, "Certificate PEM is required"),
|
||||||
privateKeyPem: z.string().trim(),
|
privateKeyPem: z.string().trim().min(1, "Private Key PEM is required"),
|
||||||
chainPem: z.string().trim(),
|
chainPem: z.string().trim().min(1, "Certificate Chain PEM is required"),
|
||||||
|
|
||||||
friendlyName: z.string(),
|
friendlyName: z.string(),
|
||||||
collectionId: z.string().optional()
|
collectionId: z.string().optional()
|
||||||
|
|||||||
Reference in New Issue
Block a user