File

src/crypto/key/adapters/db-key.service.ts

Description

The key service is responsible for managing the keys of the issuer.

Extends

KeyService

Index

Properties
Methods

Constructor

constructor(configService: ConfigService, cryptoService: CryptoImplementationService, keyRepository: Repository<KeyEntity>, configImportService: ConfigImportService, certRepository: Repository<CertEntity>, tenantRepository: Repository<TenantEntity>, configImportOrchestrator: ConfigImportOrchestratorService)
Parameters :
Name Type Optional
configService ConfigService No
cryptoService CryptoImplementationService No
keyRepository Repository<KeyEntity> No
configImportService ConfigImportService No
certRepository Repository<CertEntity> No
tenantRepository Repository<TenantEntity> No
configImportOrchestrator ConfigImportOrchestratorService No

Properties

Private Readonly crypto
Type : CryptoImplementation
Protected Readonly logger
Type : unknown
Default value : new Logger(KeyService.name)
Inherited from KeyService
Defined in KeyService:23

Methods

Async create
create(tenantId: string)
Inherited from KeyService
Defined in KeyService:101

Creates a new keypair and wrtites the private key to the file system.

Parameters :
Name Type Optional
tenantId string No
Returns : Promise<string>

key id of the generated key.

Async deleteKey
deleteKey(tenantId: string, keyId: string)
Inherited from KeyService
Defined in KeyService:222
Parameters :
Name Type Optional
tenantId string No
keyId string No
Returns : Promise<void>
getKid
getKid(tenantId: string)
Inherited from KeyService
Defined in KeyService:151

Gets one key id for the tenant. If no key exists, it will throw an error.

Parameters :
Name Type Optional
tenantId string No
Returns : Promise<string>
Private Async getPrivateKey
getPrivateKey(tenantId: string, keyId?: string)

Get the keys from the file system or generate them if they do not exist

Parameters :
Name Type Optional
tenantId string No
keyId string Yes
Returns : unknown
Private getPubFromPrivateKey
getPubFromPrivateKey(privateKey: JWK_EC_Private)

Get the public key from the private key.

Parameters :
Name Type Optional
privateKey JWK_EC_Private No
Returns : EC_Public
getPublicKey
getPublicKey(type: unknown, tenantId: string, keyId?: string)
Inherited from KeyService
Defined in KeyService:163

Get the public key

Parameters :
Name Type Optional
type unknown No
tenantId string No
keyId string Yes
Returns : Promise<JWK>
getPublicKey
getPublicKey(type: unknown, tenantId: string, keyId?: string)
Parameters :
Name Type Optional
type unknown No
tenantId string No
keyId string Yes
Returns : Promise<string>
Async getPublicKey
getPublicKey(type: "pem" | "jwk", tenantId: string, keyId?: string)
Parameters :
Name Type Optional
type "pem" | "jwk" No
tenantId string No
keyId string Yes
Returns : Promise<JWK | string>
import
import(tenantId: string, body: KeyImportDto)
Inherited from KeyService
Defined in KeyService:59

Import a key into the key service.

Parameters :
Name Type Optional
tenantId string No
body KeyImportDto No
Returns : Promise<string>
init
init(tenant: string)
Inherited from KeyService
Defined in KeyService:92

Initialize the key service for a specific tenant. This will create the keys if they do not exist.

Parameters :
Name Type Optional
tenant string No
Returns : Promise<string>
Async signer
signer(tenantId: string, keyId?: string)
Inherited from KeyService
Defined in KeyService:124

Get the signer for the key service

Parameters :
Name Type Optional
tenantId string No
keyId string Yes
Returns : Promise<Signer>
Async signJWT
signJWT(payload: JWTPayload, header: JWTHeaderParameters, tenantId: string, keyId?: string)
Inherited from KeyService
Defined in KeyService:206
Parameters :
Name Type Optional
payload JWTPayload No
header JWTHeaderParameters No
tenantId string No
keyId string Yes
Returns : Promise<string>
getKey
getKey(tenantId: string, keyId: string)
Inherited from KeyService
Defined in KeyService:116
Parameters :
Name Type Optional
tenantId string No
keyId string No
Returns : Promise<KeyEntity>
getKeys
getKeys(id: string)
Inherited from KeyService
Defined in KeyService:112
Parameters :
Name Type Optional
id string No
Async importForTenant
importForTenant(tenantId: string)
Inherited from KeyService
Defined in KeyService:131

Imports keys for a specific tenant from the file system.

Parameters :
Name Type Optional
tenantId string No
Returns : any
update
update(tenantId: string, id: string, body: UpdateKeyDto)
Inherited from KeyService
Defined in KeyService:61

Update key metadata

Parameters :
Name Type Optional
tenantId string No
id string No
body UpdateKeyDto No
Returns : any
import { ConfigService } from "@nestjs/config";
import { Signer } from "@sd-jwt/types";
import {
    CryptoKey,
    exportJWK,
    exportSPKI,
    importJWK,
    JWK,
    JWK_EC_Private,
    JWTHeaderParameters,
    JWTPayload,
    SignJWT,
} from "jose";
import { Repository } from "typeorm";
import { v4 } from "uuid";
import { TenantEntity } from "../../../auth/tenant/entitites/tenant.entity";
import { EC_Public } from "../../../issuer/issuance/oid4vci/well-known/dto/jwks-response.dto";
import { ConfigImportService } from "../../../shared/utils/config-import/config-import.service";
import { ConfigImportOrchestratorService } from "../../../shared/utils/config-import/config-import-orchestrator.service";
import { CryptoImplementation } from "../crypto-implementation/crypto-implementation";
import { CryptoImplementationService } from "../crypto-implementation/crypto-implementation.service";
import { KeyImportDto } from "../dto/key-import.dto";
import { CertEntity } from "../entities/cert.entity";
import { KeyEntity } from "../entities/keys.entity";
import { KeyService } from "../key.service";

/**
 * The key service is responsible for managing the keys of the issuer.
 */
export class DBKeyService extends KeyService {
    private readonly crypto: CryptoImplementation;

    constructor(
        configService: ConfigService,
        private readonly cryptoService: CryptoImplementationService,
        keyRepository: Repository<KeyEntity>,
        configImportService: ConfigImportService,
        certRepository: Repository<CertEntity>,
        tenantRepository: Repository<TenantEntity>,
        configImportOrchestrator: ConfigImportOrchestratorService,
    ) {
        super(
            configService,
            keyRepository,
            configImportService,
            certRepository,
            tenantRepository,
            configImportOrchestrator,
        );
        this.crypto = cryptoService.getCrypto();
    }

    /**
     * Import a key into the key service.
     * @param tenantId
     * @param body
     * @returns
     */
    import(tenantId: string, body: KeyImportDto): Promise<string> {
        return this.keyRepository
            .save({
                ...body,
                tenantId,
            })
            .then(() => body.id);
    }

    /**
     * Get the public key from the private key.
     * @param privateKey
     * @returns
     */
    private getPubFromPrivateKey(privateKey: JWK_EC_Private): EC_Public {
        const {
            d: _d,
            key_ops: _key_ops,
            ext: _ext,
            ...publicKey
        } = privateKey;
        // Ensure alg is set if not present
        if (!publicKey.alg) {
            publicKey.alg = this.cryptoService.getAlg();
        }
        return publicKey as EC_Public;
    }

    /**
     * Initialize the key service for a specific tenant.
     * This will create the keys if they do not exist.
     * @param tenant
     */
    init(tenant: string): Promise<string> {
        return this.getKid(tenant).catch(async () => this.create(tenant));
    }

    /**
     * Creates a new keypair and wrtites the private key to the file system.
     * @param tenantId
     * @returns key id of the generated key.
     */
    async create(tenantId: string): Promise<string> {
        const keys = await this.crypto.generateKeyPair();
        const privateKey = keys.privateKey as JWK;
        //add a random key id for reference
        privateKey.kid = v4();
        privateKey.alg = this.crypto.alg;

        //remove exportable and key_ops from the private key
        delete privateKey.ext;
        delete privateKey.key_ops;

        return this.keyRepository
            .save({
                id: privateKey.kid,
                tenantId,
                key: privateKey,
            })
            .then(() => privateKey.kid!);
    }

    /**
     * Get the signer for the key service
     */
    async signer(tenantId: string, keyId?: string): Promise<Signer> {
        const privateKey = await this.getPrivateKey(tenantId, keyId);
        return this.crypto.getSigner(privateKey);
    }

    /**
     * Get the keys from the file system or generate them if they do not exist
     * @returns
     */
    private async getPrivateKey(tenantId: string, keyId?: string) {
        keyId =
            keyId ||
            (await this.getKid(tenantId).catch(() => this.create(tenantId)));

        return this.keyRepository
            .findOneByOrFail({
                id: keyId,
                tenantId,
            })
            .then((key) => key.key);
    }

    /**
     * Gets one key id for the tenant.
     * If no key exists, it will throw an error.
     * @returns
     */
    getKid(tenantId: string): Promise<string> {
        return this.keyRepository
            .findOneByOrFail({
                tenantId,
            })
            .then((key) => key.id);
    }

    /**
     * Get the public key
     * @returns
     */
    getPublicKey(type: "jwk", tenantId: string, keyId?: string): Promise<JWK>;
    getPublicKey(
        type: "pem",
        tenantId: string,
        keyId?: string,
    ): Promise<string>;
    async getPublicKey(
        type: "pem" | "jwk",
        tenantId: string,
        keyId?: string,
    ): Promise<JWK | string> {
        const privateKey = await this.getPrivateKey(tenantId, keyId);

        // Convert the private key to a public key
        // First import the private key as a CryptoKey
        const privateKeyInstance = await importJWK(
            privateKey,
            this.cryptoService.getAlg(),
            { extractable: true },
        );

        // Export it as a JWK to get the public key components
        const privateKeyJWK = (await exportJWK(
            privateKeyInstance,
        )) as JWK_EC_Private;

        // Remove private key components to get only the public key

        const publicKey = this.getPubFromPrivateKey(privateKeyJWK);

        if (type === "pem") {
            // Import the public key and export as PEM
            const publicKeyInstance = await importJWK(
                publicKey,
                this.cryptoService.getAlg(),
                { extractable: true },
            );
            return exportSPKI(publicKeyInstance as CryptoKey);
        } else {
            return publicKey;
        }
    }

    async signJWT(
        payload: JWTPayload,
        header: JWTHeaderParameters,
        tenantId: string,
        keyId?: string,
    ): Promise<string> {
        const privateKey = await this.getPrivateKey(tenantId, keyId);
        const privateKeyInstance = (await importJWK(
            privateKey,
            this.cryptoService.getAlg(),
        )) as CryptoKey;
        return new SignJWT(payload)
            .setProtectedHeader(header)
            .sign(privateKeyInstance);
    }

    async deleteKey(tenantId: string, keyId: string): Promise<void> {
        await this.keyRepository.delete({ tenantId, id: keyId });
    }
}

results matching ""

    No results matching ""