fix: requested changes

This commit is contained in:
Daniel Hougaard
2025-04-04 04:21:00 +04:00
parent c7416c825c
commit 53b5497271
23 changed files with 222 additions and 202 deletions

View File

@@ -1,6 +1,6 @@
import { Knex } from "knex";
import { KmsKeyIntent } from "@app/services/kms/kms-types";
import { KmsKeyUsage } from "@app/services/kms/kms-types";
import { TableName } from "../schemas";
@@ -8,12 +8,12 @@ export async function up(knex: Knex): Promise<void> {
const hasTypeColumn = await knex.schema.hasColumn(TableName.KmsKey, "type");
await knex.schema.alterTable(TableName.KmsKey, (t) => {
if (!hasTypeColumn) t.string("type").notNullable().defaultTo(KmsKeyIntent.ENCRYPT_DECRYPT);
if (!hasTypeColumn) t.string("keyUsage").notNullable().defaultTo(KmsKeyUsage.ENCRYPT_DECRYPT);
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable(TableName.KmsKey, (t) => {
t.dropColumn("type");
t.dropColumn("keyUsage");
});
}

View File

@@ -17,7 +17,7 @@ export const KmsKeysSchema = z.object({
createdAt: z.date(),
updatedAt: z.date(),
projectId: z.string().nullable().optional(),
type: z.string().default("encrypt-decrypt")
keyUsage: z.string().default("encrypt-decrypt")
});
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;

View File

@@ -2,7 +2,7 @@ import z from "zod";
import { KmsKeysSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@@ -74,7 +74,7 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
schema: {
description: "KMIP endpoint for creating managed objects",
body: z.object({
algorithm: z.nativeEnum(SymmetricKeyEncryptDecrypt)
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
}),
response: {
200: KmsKeysSchema
@@ -433,7 +433,7 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
body: z.object({
key: z.string(),
name: z.string(),
algorithm: z.nativeEnum(SymmetricKeyEncryptDecrypt)
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
}),
response: {
200: z.object({

View File

@@ -4,8 +4,8 @@ import {
} from "@app/ee/services/project-template/project-template-types";
import { SshCaStatus, SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
import { SshCertTemplateStatus } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-types";
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign/types";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
import { TProjectPermission } from "@app/lib/types";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { TCreateAppConnectionDTO, TUpdateAppConnectionDTO } from "@app/services/app-connection/app-connection-types";
@@ -1903,7 +1903,7 @@ interface CreateCmekEvent {
keyId: string;
name: string;
description?: string;
encryptionAlgorithm: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
encryptionAlgorithm: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
};
}

View File

@@ -7,7 +7,7 @@ import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/er
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsDataKey, KmsKeyIntent } from "@app/services/kms/kms-types";
import { KmsDataKey, KmsKeyUsage } from "@app/services/kms/kms-types";
import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
@@ -115,7 +115,7 @@ export const externalKmsServiceFactory = ({
{
isReserved: false,
description,
type: KmsKeyIntent.ENCRYPT_DECRYPT,
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
name: kmsName,
orgId: actorOrgId
},

View File

@@ -3,7 +3,7 @@ import { ForbiddenError } from "@casl/ability";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsKeyIntent } from "@app/services/kms/kms-types";
import { KmsKeyUsage } from "@app/services/kms/kms-types";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
@@ -404,7 +404,7 @@ export const kmipOperationServiceFactory = ({
algorithm,
isReserved: false,
projectId,
type: KmsKeyIntent.ENCRYPT_DECRYPT,
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
orgId: project.orgId
});

View File

@@ -1,4 +1,4 @@
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { OrderByDirection, TOrgPermission, TProjectPermission } from "@app/lib/types";
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
@@ -49,7 +49,7 @@ type KmipOperationBaseDTO = {
} & Omit<TOrgPermission, "orgId">;
export type TKmipCreateDTO = {
algorithm: SymmetricKeyEncryptDecrypt;
algorithm: SymmetricKeyAlgorithm;
} & KmipOperationBaseDTO;
export type TKmipGetDTO = {
@@ -77,7 +77,7 @@ export type TKmipLocateDTO = KmipOperationBaseDTO;
export type TKmipRegisterDTO = {
name: string;
key: string;
algorithm: SymmetricKeyEncryptDecrypt;
algorithm: SymmetricKeyAlgorithm;
} & KmipOperationBaseDTO;
export type TSetupOrgKmipDTO = {

View File

@@ -1,6 +1,6 @@
import crypto from "crypto";
import { SymmetricKeyEncryptDecrypt, TSymmetricEncryptionFns } from "./types";
import { SymmetricKeyAlgorithm, TSymmetricEncryptionFns } from "./types";
const getIvLength = () => {
return 12;
@@ -11,7 +11,7 @@ const getTagLength = () => {
};
export const symmetricCipherService = (
type: SymmetricKeyEncryptDecrypt.AES_GCM_128 | SymmetricKeyEncryptDecrypt.AES_GCM_256
type: SymmetricKeyAlgorithm.AES_GCM_128 | SymmetricKeyAlgorithm.AES_GCM_256
): TSymmetricEncryptionFns => {
const IV_LENGTH = getIvLength();
const TAG_LENGTH = getTagLength();

View File

@@ -1,2 +1,2 @@
export { symmetricCipherService } from "./cipher";
export { AllowedEncryptionKeyAlgorithms, SymmetricKeyEncryptDecrypt } from "./types";
export { AllowedEncryptionKeyAlgorithms, SymmetricKeyAlgorithm } from "./types";

View File

@@ -1,19 +1,17 @@
import { z } from "zod";
import { AsymmetricKeySignVerify } from "../sign/types";
import { AsymmetricKeyAlgorithm } from "../sign/types";
// Supported symmetric encrypt/decrypt algorithms
export enum SymmetricKeyEncryptDecrypt {
export enum SymmetricKeyAlgorithm {
AES_GCM_256 = "aes-256-gcm",
AES_GCM_128 = "aes-128-gcm"
}
export const SymmetricKeyEncryptDecryptEnum = z.enum(
Object.values(SymmetricKeyEncryptDecrypt) as [string, ...string[]]
).options;
export const SymmetricKeyAlgorithmEnum = z.enum(Object.values(SymmetricKeyAlgorithm) as [string, ...string[]]).options;
export const AllowedEncryptionKeyAlgorithms = z.enum([
...Object.values(SymmetricKeyEncryptDecrypt),
...Object.values(AsymmetricKeySignVerify)
...Object.values(SymmetricKeyAlgorithm),
...Object.values(AsymmetricKeyAlgorithm)
] as [string, ...string[]]).options;
export type TSymmetricEncryptionFns = {

View File

@@ -1,2 +1,2 @@
export { signingService } from "./signing";
export { AsymmetricKeySignVerify, SigningAlgorithm } from "./types";
export { AsymmetricKeyAlgorithm, SigningAlgorithm } from "./types";

View File

@@ -3,7 +3,7 @@ import crypto from "crypto";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { AsymmetricKeySignVerify, SigningAlgorithm, TAsymmetricSignVerifyFns } from "./types";
import { AsymmetricKeyAlgorithm, SigningAlgorithm, TAsymmetricSignVerifyFns } from "./types";
// Map of signing algorithms to their parameters
interface SigningParams {
@@ -22,7 +22,7 @@ const SHA512_DIGEST_LENGTH = 64;
* @param algorithm The signing algorithm to use
* @returns Object with sign and verify functions
*/
export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricSignVerifyFns => {
export const signingService = (algorithm: AsymmetricKeyAlgorithm): TAsymmetricSignVerifyFns => {
const $getSigningParams = (signingAlgorithm: SigningAlgorithm): SigningParams => {
switch (signingAlgorithm) {
// RSA PSS
@@ -76,10 +76,10 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
};
// For ECC key generation, nodejs has some strange and hardly documented curve naming conventions
const $getEcCurveName = (keyAlgorithm: AsymmetricKeySignVerify): string => {
const $getEcCurveName = (keyAlgorithm: AsymmetricKeyAlgorithm): string => {
// We will support more in the future
switch (keyAlgorithm) {
case AsymmetricKeySignVerify.ECC_NIST_P256:
case AsymmetricKeyAlgorithm.ECC_NIST_P256:
return "prime256v1";
default:
throw new Error(`Unsupported EC curve: ${keyAlgorithm}`);
@@ -172,7 +172,6 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
type: "pkcs8"
});
// Return public key in PEM format for both RSA and EC
const publicKey = crypto.createPublicKey(privateKeyObj).export({
type: "spki",
format: "pem"
@@ -210,7 +209,8 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
}
// For PKCS1 v1.5 padding
return signer.sign({
key: privateKeyObject
key: privateKeyObject,
padding
});
}
if (signingAlgorithm.startsWith("ECDSA")) {
@@ -252,7 +252,8 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
// For PKCS1 v1.5 padding
return verifier.verify(
{
key: publicKey.toString()
key: publicKey.toString(),
padding
},
signature
);

View File

@@ -8,13 +8,13 @@ export type TAsymmetricSignVerifyFns = {
};
// Supported asymmetric key types
export enum AsymmetricKeySignVerify {
export enum AsymmetricKeyAlgorithm {
RSA_4096 = "rsa-4096",
ECC_NIST_P256 = "ecc-nist-p256"
}
export const AsymmetricKeySignVerifyEnum = z.enum(
Object.values(AsymmetricKeySignVerify) as [string, ...string[]]
export const AsymmetricKeyAlgorithmEnum = z.enum(
Object.values(AsymmetricKeyAlgorithm) as [string, ...string[]]
).options;
export enum SigningAlgorithm {

View File

@@ -4,22 +4,20 @@ import { InternalKmsSchema, KmsKeysSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { KMS } from "@app/lib/api-docs";
import { getBase64SizeInBytes, isBase64 } from "@app/lib/base64";
import { AllowedEncryptionKeyAlgorithms, SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign";
import { AllowedEncryptionKeyAlgorithms, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign";
import { OrderByDirection } from "@app/lib/types";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { slugSchema } from "@app/server/lib/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CmekOrderBy, TCmekKeyEncryptionAlgorithm } from "@app/services/cmek/cmek-types";
import { KmsKeyIntent } from "@app/services/kms/kms-types";
import { KmsKeyUsage } from "@app/services/kms/kms-types";
const keyNameSchema = slugSchema({ min: 1, max: 32, field: "Name" });
const keyDescriptionSchema = z.string().trim().max(500).optional();
const CmekSchema = KmsKeysSchema.merge(
InternalKmsSchema.pick({ version: true, encryptionAlgorithm: true, type: true })
).omit({
const CmekSchema = KmsKeysSchema.merge(InternalKmsSchema.pick({ version: true, encryptionAlgorithm: true })).omit({
isReserved: true
});
@@ -54,37 +52,37 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
projectId: z.string().describe(KMS.CREATE_KEY.projectId),
name: keyNameSchema.describe(KMS.CREATE_KEY.name),
description: keyDescriptionSchema.describe(KMS.CREATE_KEY.description),
type: z
.nativeEnum(KmsKeyIntent)
keyUsage: z
.nativeEnum(KmsKeyUsage)
.optional()
.default(KmsKeyIntent.ENCRYPT_DECRYPT)
.default(KmsKeyUsage.ENCRYPT_DECRYPT)
.describe(KMS.CREATE_KEY.type),
encryptionAlgorithm: z
.enum(AllowedEncryptionKeyAlgorithms)
.optional()
.default(SymmetricKeyEncryptDecrypt.AES_GCM_256)
.default(SymmetricKeyAlgorithm.AES_GCM_256)
.describe(KMS.CREATE_KEY.encryptionAlgorithm)
})
.superRefine((data, ctx) => {
if (
data.type === KmsKeyIntent.ENCRYPT_DECRYPT &&
!Object.values(SymmetricKeyEncryptDecrypt).includes(data.encryptionAlgorithm as SymmetricKeyEncryptDecrypt)
data.keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT &&
!Object.values(SymmetricKeyAlgorithm).includes(data.encryptionAlgorithm as SymmetricKeyAlgorithm)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `encryptionAlgorithm must be a valid symmetric encryption algorithm. Valid options are: ${Object.values(
SymmetricKeyEncryptDecrypt
SymmetricKeyAlgorithm
).join(", ")}`
});
}
if (
data.type === KmsKeyIntent.SIGN_VERIFY &&
!Object.values(AsymmetricKeySignVerify).includes(data.encryptionAlgorithm as AsymmetricKeySignVerify)
data.keyUsage === KmsKeyUsage.SIGN_VERIFY &&
!Object.values(AsymmetricKeyAlgorithm).includes(data.encryptionAlgorithm as AsymmetricKeyAlgorithm)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `encryptionAlgorithm must be a valid asymmetric sign-verify algorithm. Valid options are: ${Object.values(
AsymmetricKeySignVerify
AsymmetricKeyAlgorithm
).join(", ")}`
});
}
@@ -98,7 +96,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const {
body: { projectId, name, description, encryptionAlgorithm, type },
body: { projectId, name, description, encryptionAlgorithm, keyUsage },
permission
} = req;
@@ -109,7 +107,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
name,
description,
encryptionAlgorithm: encryptionAlgorithm as TCmekKeyEncryptionAlgorithm,
type
keyUsage
},
permission
);
@@ -167,7 +165,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId: cmek.projectId!,
event: {
type: EventType.UPDATE_CMEK,
metadata: {
@@ -210,7 +208,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId: cmek.projectId!,
event: {
type: EventType.DELETE_CMEK,
metadata: {
@@ -390,11 +388,11 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
permission
} = req;
const ciphertext = await server.services.cmek.cmekEncrypt({ keyId, plaintext }, permission);
const { ciphertext, projectId } = await server.services.cmek.cmekEncrypt({ keyId, plaintext }, permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId,
event: {
type: EventType.CMEK_ENCRYPT,
metadata: {
@@ -431,11 +429,11 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
permission
} = req;
const publicKey = await server.services.cmek.getPublicKey({ keyId }, permission);
const { publicKey, projectId } = await server.services.cmek.getPublicKey({ keyId }, permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId,
event: {
type: EventType.CMEK_GET_PUBLIC_KEY,
metadata: {
@@ -444,7 +442,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
}
});
return publicKey;
return { publicKey };
}
});
@@ -469,11 +467,14 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
const { keyId } = req.params;
const result = await server.services.cmek.listSigningAlgorithms({ keyId }, req.permission);
const { signingAlgorithms, projectId } = await server.services.cmek.listSigningAlgorithms(
{ keyId },
req.permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId,
event: {
type: EventType.CMEK_LIST_SIGNING_ALGORITHMS,
metadata: {
@@ -482,7 +483,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
}
});
return result;
return { signingAlgorithms };
}
});
@@ -527,11 +528,14 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
permission
} = req;
const result = await server.services.cmek.cmekSign({ keyId: inputKeyId, data, signingAlgorithm }, permission);
const { projectId, ...result } = await server.services.cmek.cmekSign(
{ keyId: inputKeyId, data, signingAlgorithm },
permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId,
event: {
type: EventType.CMEK_SIGN,
metadata: {
@@ -597,11 +601,14 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
permission
} = req;
const result = await server.services.cmek.cmekVerify({ keyId, data, signature, signingAlgorithm }, permission);
const { projectId, ...result } = await server.services.cmek.cmekVerify(
{ keyId, data, signature, signingAlgorithm },
permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId,
event: {
type: EventType.CMEK_VERIFY,
metadata: {
@@ -645,11 +652,11 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
permission
} = req;
const plaintext = await server.services.cmek.cmekDecrypt({ keyId, ciphertext }, permission);
const { plaintext, projectId } = await server.services.cmek.cmekDecrypt({ keyId, ciphertext }, permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: permission.orgId,
projectId,
event: {
type: EventType.CMEK_DECRYPT,
metadata: {

View File

@@ -22,7 +22,7 @@ import {
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsKeyIntent } from "../kms/kms-types";
import { KmsKeyUsage } from "../kms/kms-types";
import { TProjectDALFactory } from "../project/project-dal";
type TCmekServiceFactoryDep = {
@@ -228,7 +228,10 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
const { cipherTextBlob } = await encrypt({ plainText: Buffer.from(plaintext, "base64") });
return cipherTextBlob.toString("base64");
return {
ciphertext: cipherTextBlob.toString("base64"),
projectId: key.projectId
};
};
const listSigningAlgorithms = async ({ keyId }: TCmekListSigningAlgorithmsDTO, actor: OrgServiceActor) => {
@@ -249,7 +252,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
if (key.type !== KmsKeyIntent.SIGN_VERIFY) {
if (key.keyUsage !== KmsKeyUsage.SIGN_VERIFY) {
throw new BadRequestError({ message: `Key with ID '${keyId}' is not intended for signing` });
}
@@ -276,7 +279,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
throw new BadRequestError({ message: `Unsupported encryption algorithm: ${encryptionAlgorithm}` });
}
return { signingAlgorithms: selectedAlgorithm.signingAlgorithms };
return { signingAlgorithms: selectedAlgorithm.signingAlgorithms, projectId: key.projectId };
};
const getPublicKey = async ({ keyId }: TCmekGetPublicKeyDTO, actor: OrgServiceActor) => {
@@ -299,7 +302,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
const publicKey = await kmsService.getPublicKey({ kmsId: keyId });
return { publicKey };
return { publicKey, projectId: key.projectId };
};
const cmekSign = async ({ keyId, data, signingAlgorithm }: TCmekSignDTO, actor: OrgServiceActor) => {
@@ -329,6 +332,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
return {
signature: signature.toString("base64"),
keyId: key.id,
projectId: key.projectId,
signingAlgorithm: algorithm
};
};
@@ -363,6 +367,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
return {
signatureValid,
keyId: key.id,
projectId: key.projectId,
signingAlgorithm: algorithm
};
};
@@ -391,7 +396,10 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
const plaintextBlob = await decrypt({ cipherTextBlob: Buffer.from(ciphertext, "base64") });
return plaintextBlob.toString("base64");
return {
plaintext: plaintextBlob.toString("base64"),
projectId: key.projectId
};
};
return {

View File

@@ -1,10 +1,10 @@
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign";
import { OrderByDirection } from "@app/lib/types";
import { KmsKeyIntent } from "../kms/kms-types";
import { KmsKeyUsage } from "../kms/kms-types";
export type TCmekKeyEncryptionAlgorithm = SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
export type TCmekKeyEncryptionAlgorithm = SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
export type TCreateCmekDTO = {
orgId: string;
@@ -12,7 +12,7 @@ export type TCreateCmekDTO = {
name: string;
description?: string;
encryptionAlgorithm: TCmekKeyEncryptionAlgorithm;
type: KmsKeyIntent;
keyUsage: KmsKeyUsage;
};
export type TUpdabteCmekByIdDTO = {

View File

@@ -1,36 +1,36 @@
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify } from "@app/lib/crypto/sign";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm } from "@app/lib/crypto/sign";
import { BadRequestError } from "@app/lib/errors";
import { KmsKeyIntent } from "./kms-types";
import { KmsKeyUsage } from "./kms-types";
export const KMS_ROOT_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
export const getByteLengthForSymmetricEncryptionAlgorithm = (encryptionAlgorithm: SymmetricKeyEncryptDecrypt) => {
export const getByteLengthForSymmetricEncryptionAlgorithm = (encryptionAlgorithm: SymmetricKeyAlgorithm) => {
switch (encryptionAlgorithm) {
case SymmetricKeyEncryptDecrypt.AES_GCM_128:
case SymmetricKeyAlgorithm.AES_GCM_128:
return 16;
case SymmetricKeyEncryptDecrypt.AES_GCM_256:
case SymmetricKeyAlgorithm.AES_GCM_256:
default:
return 32;
}
};
export const verifyKeyTypeAndAlgorithm = (
type: KmsKeyIntent,
algorithm: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify,
keyUsage: KmsKeyUsage,
algorithm: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm,
extra?: {
forceType?: KmsKeyIntent;
forceType?: KmsKeyUsage;
}
) => {
if (extra?.forceType && type !== extra.forceType) {
if (extra?.forceType && keyUsage !== extra.forceType) {
throw new BadRequestError({
message: `Unsupported key type, expected ${extra.forceType} but got ${type}`
message: `Unsupported key type, expected ${extra.forceType} but got ${keyUsage}`
});
}
if (type === KmsKeyIntent.ENCRYPT_DECRYPT) {
if (!Object.values(SymmetricKeyEncryptDecrypt).includes(algorithm as SymmetricKeyEncryptDecrypt)) {
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
if (!Object.values(SymmetricKeyAlgorithm).includes(algorithm as SymmetricKeyAlgorithm)) {
throw new BadRequestError({
message: `Unsupported encryption algorithm for encrypt/decrypt key: ${algorithm as string}`
});
@@ -39,8 +39,8 @@ export const verifyKeyTypeAndAlgorithm = (
return true;
}
if (type === KmsKeyIntent.SIGN_VERIFY) {
if (!Object.values(AsymmetricKeySignVerify).includes(algorithm as AsymmetricKeySignVerify)) {
if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
if (!Object.values(AsymmetricKeyAlgorithm).includes(algorithm as AsymmetricKeyAlgorithm)) {
throw new BadRequestError({
message: `Unsupported sign/verify algorithm for sign/verify key: ${algorithm as string}`
});
@@ -50,6 +50,6 @@ export const verifyKeyTypeAndAlgorithm = (
}
throw new BadRequestError({
message: `Unsupported key type: ${type as string}`
message: `Unsupported key type: ${keyUsage as string}`
});
};

View File

@@ -17,9 +17,9 @@ import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
import { TEnvConfig } from "@app/lib/config/env";
import { randomSecureBytes } from "@app/lib/crypto";
import { symmetricCipherService, SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { symmetricCipherService, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { generateHash } from "@app/lib/crypto/encryption";
import { AsymmetricKeySignVerify, signingService } from "@app/lib/crypto/sign";
import { AsymmetricKeyAlgorithm, signingService } from "@app/lib/crypto/sign";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { alphaNumericNanoId } from "@app/lib/nanoid";
@@ -36,7 +36,7 @@ import { TKmsKeyDALFactory } from "./kms-key-dal";
import { TKmsRootConfigDALFactory } from "./kms-root-config-dal";
import {
KmsDataKey,
KmsKeyIntent,
KmsKeyUsage,
KmsType,
RootKeyEncryptionStrategy,
TDecryptWithKeyDTO,
@@ -94,21 +94,21 @@ export const kmsServiceFactory = ({
tx,
name,
projectId,
encryptionAlgorithm = SymmetricKeyEncryptDecrypt.AES_GCM_256,
type = KmsKeyIntent.ENCRYPT_DECRYPT,
encryptionAlgorithm = SymmetricKeyAlgorithm.AES_GCM_256,
keyUsage = KmsKeyUsage.ENCRYPT_DECRYPT,
description
}: TGenerateKMSDTO) => {
// daniel: ensure that the key type (sign/encrypt) and the encryption algorithm are compatible.
verifyKeyTypeAndAlgorithm(type, encryptionAlgorithm);
verifyKeyTypeAndAlgorithm(keyUsage, encryptionAlgorithm);
let kmsKeyMaterial: Buffer | null = null;
if (type === KmsKeyIntent.ENCRYPT_DECRYPT) {
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
kmsKeyMaterial = randomSecureBytes(
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyEncryptDecrypt)
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyAlgorithm)
);
} else if (type === KmsKeyIntent.SIGN_VERIFY) {
} else if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
const { generateAsymmetricPrivateKey, getPublicKeyFromPrivateKey } = signingService(
encryptionAlgorithm as AsymmetricKeySignVerify
encryptionAlgorithm as AsymmetricKeyAlgorithm
);
kmsKeyMaterial = await generateAsymmetricPrivateKey();
@@ -118,18 +118,18 @@ export const kmsServiceFactory = ({
if (!kmsKeyMaterial) {
throw new BadRequestError({
message: `Invalid KMS key type. No key material was created for key type '${type}' using algorithm '${encryptionAlgorithm}'`
message: `Invalid KMS key type. No key material was created for key usage '${keyUsage}' using algorithm '${encryptionAlgorithm}'`
});
}
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
const sanitizedName = name ? slugify(name) : slugify(alphaNumericNanoId(8).toLowerCase());
const dbQuery = async (db: Knex) => {
const kmsDoc = await kmsDAL.create(
{
name: sanitizedName,
type,
keyUsage,
orgId,
isReserved,
projectId,
@@ -169,7 +169,7 @@ export const kmsServiceFactory = ({
*/
const encryptWithInputKey = async ({ key }: Omit<TEncryptionWithKeyDTO, "plainText">) => {
// akhilmhdh: as more encryption are added do a check here on kmsDoc.encryptionAlgorithm
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
const encryptedPlainTextBlob = cipher.encrypt(plainText, key);
// Buffer#1 encrypted text + Buffer#2 version number
@@ -184,7 +184,7 @@ export const kmsServiceFactory = ({
* This can be even later exposed directly as api for encryption as function
*/
const decryptWithInputKey = async ({ key }: Omit<TDecryptWithKeyDTO, "cipherTextBlob">) => {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return ({ cipherTextBlob: versionedCipherTextBlob }: Pick<TDecryptWithKeyDTO, "cipherTextBlob">) => {
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
@@ -262,7 +262,7 @@ export const kmsServiceFactory = ({
};
const encryptWithRootKey = () => {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return (plainTextBuffer: Buffer) => {
const encryptedBuffer = cipher.encrypt(plainTextBuffer, ROOT_ENCRYPTION_KEY);
@@ -271,7 +271,7 @@ export const kmsServiceFactory = ({
};
const decryptWithRootKey = () => {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return (cipherTextBuffer: Buffer) => {
return cipher.decrypt(cipherTextBuffer, ROOT_ENCRYPTION_KEY);
@@ -290,9 +290,9 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyEncryptDecrypt;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.ENCRYPT_DECRYPT
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.ENCRYPT_DECRYPT
});
if (kmsDoc.externalKms) {
@@ -356,7 +356,7 @@ export const kmsServiceFactory = ({
}
// internal KMS
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const dataCipher = symmetricCipherService(encryptionAlgorithm);
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -385,22 +385,22 @@ export const kmsServiceFactory = ({
});
}
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
return kmsKey;
};
const importKeyMaterial = async (
{ key, algorithm, name, isReserved, projectId, orgId, type }: TImportKeyMaterialDTO,
{ key, algorithm, name, isReserved, projectId, orgId, keyUsage }: TImportKeyMaterialDTO,
tx?: Knex
) => {
// daniel: currently we only support imports for encrypt/decrypt keys
verifyKeyTypeAndAlgorithm(type, algorithm, { forceType: KmsKeyIntent.ENCRYPT_DECRYPT });
verifyKeyTypeAndAlgorithm(keyUsage, algorithm, { forceType: KmsKeyUsage.ENCRYPT_DECRYPT });
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const expectedByteLength = getByteLengthForSymmetricEncryptionAlgorithm(algorithm as SymmetricKeyEncryptDecrypt);
const expectedByteLength = getByteLengthForSymmetricEncryptionAlgorithm(algorithm as SymmetricKeyAlgorithm);
if (key.byteLength !== expectedByteLength) {
throw new BadRequestError({
message: `Invalid key length for ${algorithm}. Expected ${expectedByteLength} bytes but got ${key.byteLength} bytes`
@@ -413,7 +413,7 @@ export const kmsServiceFactory = ({
const kmsDoc = await kmsDAL.create(
{
name: sanitizedName,
type: KmsKeyIntent.ENCRYPT_DECRYPT,
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
orgId,
isReserved,
projectId
@@ -443,13 +443,13 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.SIGN_VERIFY
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.SIGN_VERIFY
});
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
const publicKeyBuffer = signingService(encryptionAlgorithm).getPublicKeyFromPrivateKey(kmsKey);
@@ -469,12 +469,12 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.SIGN_VERIFY
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.SIGN_VERIFY
});
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const { sign } = signingService(encryptionAlgorithm);
return ({ data, signingAlgorithm }: Pick<TSignWithKmsDTO, "data" | "signingAlgorithm">) => {
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -493,12 +493,12 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.SIGN_VERIFY
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.SIGN_VERIFY
});
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const { verify, getPublicKeyFromPrivateKey } = signingService(encryptionAlgorithm);
return ({ data, signature }: Pick<TVerifyWithKmsDTO, "data" | "signature">) => {
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -515,9 +515,9 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyEncryptDecrypt;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.ENCRYPT_DECRYPT
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.ENCRYPT_DECRYPT
});
if (kmsDoc.externalKms) {
@@ -575,7 +575,7 @@ export const kmsServiceFactory = ({
}
// internal KMS
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const dataCipher = symmetricCipherService(encryptionAlgorithm);
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -850,7 +850,7 @@ export const kmsServiceFactory = ({
// case 2: root key is encrypted with software encryption
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Software) {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const encryptionKeyBuffer = $getBasicEncryptionKey();
return cipher.decrypt(kmsRootConfig.encryptedRootKey, encryptionKeyBuffer);
@@ -870,7 +870,7 @@ export const kmsServiceFactory = ({
}
if (strategy === RootKeyEncryptionStrategy.Software) {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const encryptionKeyBuffer = $getBasicEncryptionKey();
return cipher.encrypt(plainKeyBuffer, encryptionKeyBuffer);
@@ -886,7 +886,7 @@ export const kmsServiceFactory = ({
const createCipherPairWithDataKey = async (encryptionContext: TEncryptWithKmsDataKeyDTO, trx?: Knex) => {
const dataKey = await $getDataKey(encryptionContext, trx);
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return {
encryptor: ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {

View File

@@ -1,7 +1,7 @@
import { Knex } from "knex";
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign/types";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
export enum KmsDataKey {
Organization,
@@ -14,7 +14,7 @@ export enum KmsType {
Internal = "internal"
}
export enum KmsKeyIntent {
export enum KmsKeyUsage {
ENCRYPT_DECRYPT = "encrypt-decrypt",
SIGN_VERIFY = "sign-verify"
}
@@ -31,8 +31,8 @@ export type TEncryptWithKmsDataKeyDTO =
export type TGenerateKMSDTO = {
orgId: string;
projectId?: string;
encryptionAlgorithm?: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
type?: KmsKeyIntent;
encryptionAlgorithm?: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
keyUsage?: KmsKeyUsage;
isReserved?: boolean;
name?: string;
description?: string;
@@ -91,10 +91,10 @@ export type TGetKeyMaterialDTO = {
export type TImportKeyMaterialDTO = {
key: Buffer;
algorithm: SymmetricKeyEncryptDecrypt;
algorithm: SymmetricKeyAlgorithm;
name?: string;
isReserved: boolean;
projectId: string;
orgId: string;
type: KmsKeyIntent;
keyUsage: KmsKeyUsage;
};

View File

@@ -1,21 +1,17 @@
import {
AsymmetricKeySignVerify,
KmsKeyIntent,
SymmetricKeyEncryptDecrypt
} from "@app/hooks/api/cmeks";
import { AsymmetricKeyAlgorithm, KmsKeyUsage, SymmetricKeyAlgorithm } from "@app/hooks/api/cmeks";
export const kmsKeyUsageOptions: Record<
KmsKeyIntent,
KmsKeyUsage,
{
label: string;
tooltip: string;
}
> = {
[KmsKeyIntent.ENCRYPT_DECRYPT]: {
[KmsKeyUsage.ENCRYPT_DECRYPT]: {
label: "Encrypt/Decrypt",
tooltip: "Use the key only to encrypt and decrypt data."
},
[KmsKeyIntent.SIGN_VERIFY]: {
[KmsKeyUsage.SIGN_VERIFY]: {
label: "Sign/Verify",
tooltip:
"Key pairs for digital signing. Uses the private key for signing and the public key for verification."
@@ -23,9 +19,9 @@ export const kmsKeyUsageOptions: Record<
};
export const keyUsageDefaultOption: Record<
KmsKeyIntent,
SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify
KmsKeyUsage,
SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm
> = {
[KmsKeyIntent.ENCRYPT_DECRYPT]: SymmetricKeyEncryptDecrypt.AES_GCM_256,
[KmsKeyIntent.SIGN_VERIFY]: AsymmetricKeySignVerify.RSA_4096
[KmsKeyUsage.ENCRYPT_DECRYPT]: SymmetricKeyAlgorithm.AES_GCM_256,
[KmsKeyUsage.SIGN_VERIFY]: AsymmetricKeyAlgorithm.RSA_4096
};

View File

@@ -2,17 +2,17 @@ import { z } from "zod";
import { OrderByDirection } from "@app/hooks/api/generic/types";
export enum KmsKeyIntent {
export enum KmsKeyUsage {
ENCRYPT_DECRYPT = "encrypt-decrypt",
SIGN_VERIFY = "sign-verify"
}
export type TCmek = {
id: string;
type: KmsKeyIntent;
keyUsage: KmsKeyUsage;
name: string;
description?: string;
encryptionAlgorithm: AsymmetricKeySignVerify | SymmetricKeyEncryptDecrypt;
encryptionAlgorithm: AsymmetricKeyAlgorithm | SymmetricKeyAlgorithm;
projectId: string;
isDisabled: boolean;
isReserved: boolean;
@@ -25,7 +25,7 @@ export type TCmek = {
type ProjectRef = { projectId: string };
type KeyRef = { keyId: string };
export type TCreateCmek = Pick<TCmek, "name" | "description" | "encryptionAlgorithm" | "type"> &
export type TCreateCmek = Pick<TCmek, "name" | "description" | "encryptionAlgorithm" | "keyUsage"> &
ProjectRef;
export type TUpdateCmek = KeyRef &
Partial<Pick<TCmek, "name" | "description" | "isDisabled">> &
@@ -80,20 +80,20 @@ export enum CmekOrderBy {
Name = "name"
}
export enum AsymmetricKeySignVerify {
export enum AsymmetricKeyAlgorithm {
RSA_4096 = "rsa-4096",
ECC_NIST_P256 = "ecc-nist-p256"
}
// Supported symmetric encrypt/decrypt algorithms
export enum SymmetricKeyEncryptDecrypt {
export enum SymmetricKeyAlgorithm {
AES_GCM_256 = "aes-256-gcm",
AES_GCM_128 = "aes-128-gcm"
}
export const AllowedEncryptionKeyAlgorithms = z.enum([
...Object.values(SymmetricKeyEncryptDecrypt),
...Object.values(AsymmetricKeySignVerify)
...Object.values(SymmetricKeyAlgorithm),
...Object.values(AsymmetricKeyAlgorithm)
] as [string, ...string[]]).options;
export enum SigningAlgorithm {

View File

@@ -18,9 +18,9 @@ import { useWorkspace } from "@app/context";
import { keyUsageDefaultOption, kmsKeyUsageOptions } from "@app/helpers/kms";
import {
AllowedEncryptionKeyAlgorithms,
AsymmetricKeySignVerify,
KmsKeyIntent,
SymmetricKeyEncryptDecrypt,
AsymmetricKeyAlgorithm,
KmsKeyUsage,
SymmetricKeyAlgorithm,
TCmek,
useCreateCmek,
useUpdateCmek
@@ -31,7 +31,7 @@ const formSchema = z.object({
name: slugSchema({ min: 1, max: 32, field: "Name" }),
description: z.string().max(500).optional(),
encryptionAlgorithm: z.enum(AllowedEncryptionKeyAlgorithms),
type: z.nativeEnum(KmsKeyIntent)
keyUsage: z.nativeEnum(KmsKeyUsage)
});
export type FormData = z.infer<typeof formSchema>;
@@ -65,22 +65,25 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
defaultValues: {
name: cmek?.name,
description: cmek?.description,
encryptionAlgorithm: SymmetricKeyEncryptDecrypt.AES_GCM_256,
type: KmsKeyIntent.ENCRYPT_DECRYPT
encryptionAlgorithm: SymmetricKeyAlgorithm.AES_GCM_256,
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT
}
});
const handleCreateCmek = async ({ encryptionAlgorithm, name, description, type }: FormData) => {
const handleCreateCmek = async ({
encryptionAlgorithm,
name,
description,
keyUsage
}: FormData) => {
const mutation = isUpdate
? updateCmek.mutateAsync({ keyId: cmek.id, projectId, name, description })
: createCmek.mutateAsync({
projectId,
name,
description,
type,
encryptionAlgorithm: encryptionAlgorithm as
| AsymmetricKeySignVerify
| SymmetricKeyEncryptDecrypt
keyUsage,
encryptionAlgorithm: encryptionAlgorithm as AsymmetricKeyAlgorithm | SymmetricKeyAlgorithm
});
try {
@@ -99,7 +102,7 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
}
};
const selectedType = watch("type");
const selectedKeyUsage = watch("keyUsage");
return (
<form onSubmit={handleSubmit(handleCreateCmek)}>
@@ -116,13 +119,13 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
<>
<Controller
control={control}
name="type"
name="keyUsage"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
className="w-full"
tooltipText={
<div className="space-y-4">
{Object.entries(KmsKeyIntent).map(([key, value]) => (
{Object.entries(KmsKeyUsage).map(([key, value]) => (
<div key={`key-usage-${key}`}>
<p className="font-bold">{kmsKeyUsageOptions[value].label}</p>
<p>{kmsKeyUsageOptions[value].tooltip}</p>
@@ -137,8 +140,8 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
<Select
defaultValue={field.value}
onValueChange={(e) => {
if (keyUsageDefaultOption[e as KmsKeyIntent]) {
setValue("encryptionAlgorithm", keyUsageDefaultOption[e as KmsKeyIntent], {
if (keyUsageDefaultOption[e as KmsKeyUsage]) {
setValue("encryptionAlgorithm", keyUsageDefaultOption[e as KmsKeyUsage], {
shouldDirty: true,
shouldValidate: true
});
@@ -148,7 +151,7 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
}}
className="w-full"
>
{Object.entries(KmsKeyIntent)?.map(([key, value]) => (
{Object.entries(KmsKeyUsage)?.map(([key, value]) => (
<SelectItem value={value} key={`key-usage-${key}`}>
{kmsKeyUsageOptions[value].label}
</SelectItem>
@@ -176,14 +179,14 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
{Object.entries(AllowedEncryptionKeyAlgorithms)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
?.filter(([_, value]) => {
if (selectedType === KmsKeyIntent.ENCRYPT_DECRYPT) {
return Object.values(SymmetricKeyEncryptDecrypt).includes(
value as unknown as SymmetricKeyEncryptDecrypt
if (selectedKeyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
return Object.values(SymmetricKeyAlgorithm).includes(
value as unknown as SymmetricKeyAlgorithm
);
}
if (selectedType === KmsKeyIntent.SIGN_VERIFY) {
return Object.values(AsymmetricKeySignVerify).includes(
value as unknown as AsymmetricKeySignVerify
if (selectedKeyUsage === KmsKeyUsage.SIGN_VERIFY) {
return Object.values(AsymmetricKeyAlgorithm).includes(
value as unknown as AsymmetricKeyAlgorithm
);
}

View File

@@ -55,7 +55,7 @@ import {
import { kmsKeyUsageOptions } from "@app/helpers/kms";
import { usePagination, usePopUp, useResetPageHelper, useTimedReset } from "@app/hooks";
import { useGetCmeksByProjectId, useUpdateCmek } from "@app/hooks/api/cmeks";
import { CmekOrderBy, KmsKeyIntent, TCmek } from "@app/hooks/api/cmeks/types";
import { CmekOrderBy, KmsKeyUsage, TCmek } from "@app/hooks/api/cmeks/types";
import { OrderByDirection } from "@app/hooks/api/generic/types";
import { CmekDecryptModal } from "./CmekDecryptModal";
@@ -273,8 +273,15 @@ export const CmekTable = () => {
{!isPending &&
keys.length > 0 &&
keys.map((cmek) => {
const { name, id, version, description, encryptionAlgorithm, isDisabled, type } =
cmek;
const {
name,
id,
version,
description,
encryptionAlgorithm,
isDisabled,
keyUsage
} = cmek;
const { variant, label } = getStatusBadgeProps(isDisabled);
return (
@@ -314,8 +321,8 @@ export const CmekTable = () => {
</Td>
<Td>
<div className="flex items-center gap-2">
{kmsKeyUsageOptions[type].label}
<Tooltip content={kmsKeyUsageOptions[type].tooltip}>
{kmsKeyUsageOptions[keyUsage].label}
<Tooltip content={kmsKeyUsageOptions[keyUsage].tooltip}>
<FontAwesomeIcon icon={faInfoCircle} className="text-mineshaft-400" />
</Tooltip>
</div>
@@ -339,7 +346,7 @@ export const CmekTable = () => {
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent className="min-w-[160px]">
{type === KmsKeyIntent.ENCRYPT_DECRYPT && (
{keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT && (
<>
<Tooltip
content={
@@ -388,7 +395,7 @@ export const CmekTable = () => {
</>
)}
{type === KmsKeyIntent.SIGN_VERIFY && (
{keyUsage === KmsKeyUsage.SIGN_VERIFY && (
<>
<Tooltip
content={