local-aws/src/kms/get-public-key.handler.ts

124 lines
3.6 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
import { Action } from '../action.enum';
import * as Joi from 'joi';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { KeySpec, KeyUsage, KmsKey } from './kms-key.entity';
import { breakdownArn } from '../util/breakdown-arn';
import { KmsService } from './kms.service';
import * as crypto from 'crypto';
type QueryParams = {
GrantTokens: string[];
KeyId: string;
}
interface StandardOutput {
KeyId: string;
KeySpec: KeySpec;
KeyUsage: KeyUsage;
PublicKey: string;
CustomerMasterKeySpec: KeySpec;
}
interface EncryptDecrypt extends StandardOutput {
KeyUsage: 'ENCRYPT_DECRYPT';
EncryptionAlgorithms: ('SYMMETRIC_DEFAULT' | 'RSAES_OAEP_SHA_1' | 'RSAES_OAEP_SHA_256' | 'SM2PKE')[];
}
interface SignVerify extends StandardOutput {
KeyUsage: 'SIGN_VERIFY';
SigningAlgorithms: ('RSASSA_PSS_SHA_256' | 'RSASSA_PSS_SHA_384' | 'RSASSA_PSS_SHA_512' | 'RSASSA_PKCS1_V1_5_SHA_256' | 'RSASSA_PKCS1_V1_5_SHA_384' | 'RSASSA_PKCS1_V1_5_SHA_512' | 'ECDSA_SHA_256' | 'ECDSA_SHA_384' | 'ECDSA_SHA_512' | 'SM2DSA')[];
}
type Output = EncryptDecrypt | SignVerify | StandardOutput;
@Injectable()
export class GetPublicKeyHandler extends AbstractActionHandler<QueryParams> {
constructor(
@InjectRepository(KmsKey)
private readonly keyRepo: Repository<KmsKey>,
private readonly kmsService: KmsService,
) {
super();
}
format = Format.Json;
action = Action.KmsGetPublicKey;
validator = Joi.object<QueryParams, true>({
KeyId: Joi.string().required(),
GrantTokens: Joi.array().items(Joi.string()),
});
protected async handle({ KeyId }: QueryParams, awsProperties: AwsProperties): Promise<Output> {
const searchable = KeyId.startsWith('arn') ? breakdownArn(KeyId) : {
service: 'kms',
region: awsProperties.region,
accountId: awsProperties.accountId,
identifier: KeyId,
};
const [ type, pk ] = searchable.identifier.split('/');
const keyId: Promise<string> = type === 'key' ?
Promise.resolve(pk) :
this.kmsService.findKeyIdFromAlias(pk, searchable);
const keyRecord = await this.keyRepo.findOne({ where: {
id: await keyId,
region: searchable.region,
accountId: searchable.accountId,
}});
const pubKeyObject = crypto.createPublicKey({
key: keyRecord.key,//.split(String.raw`\n`).join('\n'),
format: 'pem',
});
if (keyRecord.usage === 'ENCRYPT_DECRYPT') {
return {
CustomerMasterKeySpec: keyRecord.keySpec,
EncryptionAlgorithms: [ "SYMMETRIC_DEFAULT" ],
KeyId: keyRecord.arn,
KeySpec: keyRecord.keySpec,
KeyUsage: keyRecord.usage,
PublicKey: Buffer.from(pubKeyObject.export({
format: 'der',
type: 'spki',
})).toString('base64'),
}
}
if (keyRecord.usage === 'SIGN_VERIFY') {
const PublicKey = Buffer.from(pubKeyObject.export({
format: 'der',
type: 'spki',
})).toString('base64')
console.log({PublicKey})
return {
CustomerMasterKeySpec: keyRecord.keySpec,
KeyId: keyRecord.arn,
KeySpec: keyRecord.keySpec,
KeyUsage: keyRecord.usage,
PublicKey,
SigningAlgorithms: [ 'RSASSA_PKCS1_V1_5_SHA_256' ]
}
}
return {
CustomerMasterKeySpec: keyRecord.keySpec,
KeyId: keyRecord.arn,
KeySpec: keyRecord.keySpec,
KeyUsage: keyRecord.usage,
PublicKey: Buffer.from(pubKeyObject.export({
format: 'pem',
type: 'spki',
})).toString('utf-8'),
}
}
}