Added key algorithm opts to CA generation

This commit is contained in:
Tuan Dang
2024-05-30 10:12:28 -07:00
parent 14229931ac
commit 45fdd4ebc2
12 changed files with 145 additions and 43 deletions
@@ -25,6 +25,7 @@ export async function up(knex: Knex): Promise<void> {
t.unique(["dn", "projectId"]);
t.string("serialNumber").nullable().unique();
t.integer("maxPathLength").nullable();
t.string("keyAlgorithm").notNullable();
t.datetime("notBefore").nullable();
t.datetime("notAfter").nullable();
});
@@ -24,6 +24,7 @@ export const CertificateAuthoritiesSchema = z.object({
dn: z.string(),
serialNumber: z.string().nullable().optional(),
maxPathLength: z.number().nullable().optional(),
keyAlgorithm: z.string(),
notBefore: z.date().nullable().optional(),
notAfter: z.date().nullable().optional()
});
+2 -2
View File
@@ -23,8 +23,8 @@ export const UsersSchema = z.object({
isGhost: z.boolean().default(false),
username: z.string(),
isEmailVerified: z.boolean().default(false).nullable().optional(),
consecutiveFailedMfaAttempts: z.number().optional(),
isLocked: z.boolean().optional(),
consecutiveFailedMfaAttempts: z.number().default(0).nullable().optional(),
isLocked: z.boolean().default(false).nullable().optional(),
temporaryLockDateEnd: z.date().nullable().optional()
});
@@ -4,7 +4,7 @@ import { CertificateAuthoritiesSchema } from "@app/db/schemas";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CaStatus, CaType } from "@app/services/certificate-authority/certificate-authority-types";
import { CaStatus, CaType, CertKeyAlgorithm } from "@app/services/certificate-authority/certificate-authority-types";
import { validateCaDateField } from "@app/services/certificate-authority/certificate-authority-validators";
export const registerCaRouter = async (server: FastifyZodProvider) => {
@@ -30,7 +30,15 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
// format: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format
notBefore: validateCaDateField.optional(),
notAfter: validateCaDateField.optional(),
maxPathLength: z.number().min(-1).optional()
maxPathLength: z.number().min(-1).default(-1),
keyAlgorithm: z
.enum([
CertKeyAlgorithm.RSA_2048,
CertKeyAlgorithm.RSA_4096,
CertKeyAlgorithm.ECDSA_P256,
CertKeyAlgorithm.ECDSA_P384
])
.default(CertKeyAlgorithm.RSA_2048)
})
.refine(
(data) => {
@@ -1,4 +1,4 @@
import { TDNParts } from "./certificate-authority-types";
import { CertKeyAlgorithm, TDNParts } from "./certificate-authority-types";
export const createDistinguishedName = (parts: TDNParts) => {
const dnParts = [];
@@ -10,3 +10,36 @@ export const createDistinguishedName = (parts: TDNParts) => {
if (parts.locality) dnParts.push(`L=${parts.locality}`);
return dnParts.join(", ");
};
export const keyAlgorithmToAlgCfg = (keyAlgorithm: CertKeyAlgorithm) => {
switch (keyAlgorithm) {
case CertKeyAlgorithm.RSA_4096:
return {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
publicExponent: new Uint8Array([1, 0, 1]),
modulusLength: 4096
};
case CertKeyAlgorithm.ECDSA_P256:
return {
name: "ECDSA",
namedCurve: "P-256",
hash: "SHA-256"
};
case CertKeyAlgorithm.ECDSA_P384:
return {
name: "ECDSA",
namedCurve: "P-384",
hash: "SHA-384"
};
default: {
// RSA_2048
return {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
publicExponent: new Uint8Array([1, 0, 1]),
modulusLength: 2048
};
}
}
};
@@ -13,11 +13,12 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TCertStatus } from "../certificate/certificate-types";
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import { createDistinguishedName } from "./certificate-authority-fns";
import { createDistinguishedName, keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
import { TCertificateAuthoritySkDALFactory } from "./certificate-authority-sk-dal";
import {
CaStatus,
CaType,
CertKeyAlgorithm,
TCreateCaDTO,
TDeleteCaDTO,
TGetCaCertDTO,
@@ -68,6 +69,7 @@ export const certificateAuthorityServiceFactory = ({
notBefore,
notAfter,
maxPathLength,
keyAlgorithm,
actorId,
actorAuthMethod,
actor,
@@ -98,12 +100,7 @@ export const certificateAuthorityServiceFactory = ({
locality
});
const alg = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
publicExponent: new Uint8Array([1, 0, 1]),
modulusLength: 2048
};
const alg = keyAlgorithmToAlgCfg(keyAlgorithm);
const keys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
// https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey
@@ -133,7 +130,13 @@ export const certificateAuthorityServiceFactory = ({
commonName,
status: type === CaType.ROOT ? CaStatus.ACTIVE : CaStatus.PENDING_CERTIFICATE,
dn,
...(type === CaType.ROOT && { maxPathLength, notBefore: notBeforeDate, notAfter: notAfterDate, serialNumber })
keyAlgorithm,
...(type === CaType.ROOT && {
maxPathLength,
notBefore: notBeforeDate,
notAfter: notAfterDate,
serialNumber
})
},
tx
);
@@ -272,12 +275,7 @@ export const certificateAuthorityServiceFactory = ({
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
const alg = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
publicExponent: new Uint8Array([1, 0, 1]),
modulusLength: 2048
};
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
const pkObj = crypto.createPublicKey({ key: caKeys.pk, format: "pem", type: "spki" });
@@ -371,12 +369,7 @@ export const certificateAuthorityServiceFactory = ({
if (ca.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" });
const alg = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
publicExponent: new Uint8Array([1, 0, 1]),
modulusLength: 2048
};
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
@@ -566,12 +559,7 @@ export const certificateAuthorityServiceFactory = ({
const caCertObj = new x509.X509Certificate(caCert.certificate);
const alg = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
publicExponent: new Uint8Array([1, 0, 1]),
modulusLength: 2048
};
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
@@ -11,6 +11,13 @@ export enum CaStatus {
PENDING_CERTIFICATE = "pending-certificate"
}
export enum CertKeyAlgorithm {
RSA_2048 = "RSA_2048",
RSA_4096 = "RSA_4096",
ECDSA_P256 = "EC_prime256v1",
ECDSA_P384 = "EC_secp384r1"
}
export type TCreateCaDTO = {
projectSlug: string;
type: CaType;
@@ -22,7 +29,8 @@ export type TCreateCaDTO = {
locality: string;
notBefore?: string;
notAfter?: string;
maxPathLength?: number;
maxPathLength: number;
keyAlgorithm: CertKeyAlgorithm;
} & Omit<TProjectPermission, "projectId">;
export type TGetCaDTO = {