Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions src/controllers/x509/crypto-util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createPrivateKey, KeyObject } from 'crypto';
import { createPrivateKey, KeyObject } from 'crypto'

/**
* Extracts the raw private key (hex) from a PEM-encoded EC (P-256) private key.
Expand All @@ -7,29 +7,32 @@ async function pemToRawEcPrivateKey(pem: string): Promise<string> {
const keyObj: KeyObject = createPrivateKey({
key: pem,
format: 'pem',
});
})

// Extract raw private key (as Buffer)
const rawPrivateKey = keyObj.export({
format: 'jwk',
}).d!;
}).d!

return Buffer.from(rawPrivateKey, 'base64').toString('hex');
return Buffer.from(rawPrivateKey, 'base64').toString('hex')
}

/**
* Extracts the raw private key (hex) from a PEM-encoded Ed25519 private key.
*/
export async function pemToRawEd25519PrivateKey(pem: string): Promise<string> {
const keyObj: KeyObject = createPrivateKey({
key: pem.replace(/\\n/g, '\n'),
format: 'pem',
});

// Ed25519 JWK exports the *seed* (first 32 bytes of the private key)
const jwk = keyObj.export({ format: 'jwk' });
if (!jwk.d) throw new Error("Not an Ed25519 private key");

return Buffer.from(jwk.d, 'base64').toString('hex');
}

export async function pemToRawEd25519PrivateKey(derKey: string | Buffer): Promise<string> {
// If it's a base64 string, convert to Buffer
const keyBuffer = typeof derKey === 'string' ? Buffer.from(derKey, 'base64') : derKey

const keyObj: KeyObject = createPrivateKey({
key: keyBuffer,
format: 'der',
type: 'pkcs8', // Use 'pkcs8' for private keys (works for Ed25519, P256, RSA)
})

// Ed25519 JWK exports the *seed* (first 32 bytes of the private key)
const jwk = keyObj.export({ format: 'jwk' })
if (!jwk.d) throw new Error('Not an Ed25519 private key')

return Buffer.from(jwk.d, 'base64').toString('hex')
}
68 changes: 33 additions & 35 deletions src/controllers/x509/x509.Controller.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,78 @@
import type { RestMultiTenantAgentModules } from '../../cliAgent'
import type { TenantRecord } from '@credo-ts/tenants'

import { Agent, JsonTransformer, injectable, RecordNotFoundError, X509CreateCertificateOptions, X509Service, X509KeyUsage, KeyType, TypedArrayEncoder, CredoError, X509ExtendedKeyUsage, Key } from '@credo-ts/core'
import { injectable } from '@credo-ts/core'
import { Request as Req } from 'express'
import jwt from 'jsonwebtoken'
import { Body, Controller, Delete, Post, Route, Tags, Path, Security, Request, Res, TsoaResponse, Get } from 'tsoa'
import { Body, Controller, Post, Route, Tags, Security, Request, Get } from 'tsoa'

import { AgentRole, SCOPES } from '../../enums'
import { SCOPES } from '../../enums'
import ErrorHandlingService from '../../errorHandlingService'
import { BasicX509CreateCertificateConfig, CreateTenantOptions, X509ImportCertificateOptionsDto } from '../types'
import { generateSecretKey, getCertificateValidityForSystem } from '../../utils/helpers'
import { X509ImportCertificateOptionsDto } from '../types'
import { x509ServiceT } from './x509.service'

import { X509CreateCertificateOptionsDto } from './x509.types'

@Tags('x509')
@Security('jwt', [SCOPES.TENANT_AGENT, SCOPES.DEDICATED_AGENT])
@Route('/x509')
@injectable()
export class X509Controller extends Controller {
@Post('/')
public async createSelfSignedDCS(@Request() request: Req, @Body() createX509Options: BasicX509CreateCertificateConfig) {

public async createX509Certificate(
@Request() request: Req,
@Body() createX509Options: X509CreateCertificateOptionsDto,
) {
try {

return await x509ServiceT.createSelfSignedDCS(createX509Options, request);
return await x509ServiceT.createCertificate(request, createX509Options)
} catch (error) {
throw ErrorHandlingService.handle(error)
}
}


@Post('/import')
public async ImportX509Certficates(@Request() request: Req, @Body() importX509Options: X509ImportCertificateOptionsDto) {

public async ImportX509Certificates(
@Request() request: Req,
@Body() importX509Options: X509ImportCertificateOptionsDto,
) {
try {

return await x509ServiceT.ImportX509Certficates(request, importX509Options);
return await x509ServiceT.ImportX509Certificates(request, importX509Options)
} catch (error) {
throw ErrorHandlingService.handle(error)
}
}

@Post('/trusted')
public async addTrustedCertificate(@Request() request: Req, @Body() options: {
certificate: string
}) {
public async addTrustedCertificate(
@Request() request: Req,
@Body()
options: {
certificate: string
},
) {
try {

return await x509ServiceT.addTrustedCertificate(request, options);
return await x509ServiceT.addTrustedCertificate(request, options)
} catch (error) {
throw ErrorHandlingService.handle(error)
}
}

@Get('/trusted')
public async getTrustedCertificates(@Request() request: Req) {

try {
return await x509ServiceT.getTrustedCertificates(request);
return await x509ServiceT.getTrustedCertificates(request)
} catch (error) {
throw ErrorHandlingService.handle(error)
}
}


@Post('/decode')
public async decodeCertificate(@Request() request: Req, @Body() options: {
certificate: string
}) {
public async decodeCertificate(
@Request() request: Req,
@Body()
options: {
certificate: string
},
) {
try {

return await x509ServiceT.decodeCertificate(request, options);
return await x509ServiceT.decodeCertificate(request, options)
} catch (error) {
throw ErrorHandlingService.handle(error)
}
}


}
}
Loading