fix: add password parameter to pemToPfx and importCertificate functions for enhanced security
This commit is contained in:
+2
-1
@@ -47,8 +47,9 @@ export class KeyVaultStore {
|
|||||||
return expiresOn.getTime() - Date.now() <= thresholdMs;
|
return expiresOn.getTime() - Date.now() <= thresholdMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
async importCertificate(name: string, cert: string | Buffer, format: 'pem' | 'pfx' = 'pem'): Promise<void> {
|
async importCertificate(name: string, cert: string | Buffer, format: 'pem' | 'pfx' = 'pem', password?: string): Promise<void> {
|
||||||
const options: ImportCertificateOptions = {
|
const options: ImportCertificateOptions = {
|
||||||
|
password,
|
||||||
policy: {
|
policy: {
|
||||||
contentType: format === 'pfx' ? 'application/x-pkcs12' : 'application/x-pem-file',
|
contentType: format === 'pfx' ? 'application/x-pkcs12' : 'application/x-pem-file',
|
||||||
issuerName: 'Unknown',
|
issuerName: 'Unknown',
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@ export interface PemBundle {
|
|||||||
chainPem: string;
|
chainPem: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pemToPfx(privateKeyPem: string, certPem: string, chainPem: string): Buffer {
|
export function pemToPfx(privateKeyPem: string, certPem: string, chainPem: string, password: string): Buffer {
|
||||||
const key = forge.pki.privateKeyFromPem(privateKeyPem);
|
const key = forge.pki.privateKeyFromPem(privateKeyPem);
|
||||||
const cert = forge.pki.certificateFromPem(certPem);
|
const cert = forge.pki.certificateFromPem(certPem);
|
||||||
const chain = chainPem
|
const chain = chainPem
|
||||||
@@ -14,7 +14,7 @@ export function pemToPfx(privateKeyPem: string, certPem: string, chainPem: strin
|
|||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map(p => forge.pki.certificateFromPem(p));
|
.map(p => forge.pki.certificateFromPem(p));
|
||||||
|
|
||||||
const p12 = forge.pkcs12.toPkcs12Asn1(key, [cert, ...chain], null);
|
const p12 = forge.pkcs12.toPkcs12Asn1(key, [cert, ...chain], password, { algorithm: '3des' });
|
||||||
const der = forge.asn1.toDer(p12).getBytes();
|
const der = forge.asn1.toDer(p12).getBytes();
|
||||||
return Buffer.from(der, 'binary');
|
return Buffer.from(der, 'binary');
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-6
@@ -1,3 +1,4 @@
|
|||||||
|
import { randomUUID } from 'node:crypto';
|
||||||
import { DefaultAzureCredential } from '@azure/identity';
|
import { DefaultAzureCredential } from '@azure/identity';
|
||||||
import { AcmeClient } from './acme.js';
|
import { AcmeClient } from './acme.js';
|
||||||
import { ChallengeHandler } from './challenge.js';
|
import { ChallengeHandler } from './challenge.js';
|
||||||
@@ -105,10 +106,12 @@ export class Provisioner {
|
|||||||
|
|
||||||
const fqdns = group.map(d => d.fqdn);
|
const fqdns = group.map(d => d.fqdn);
|
||||||
const issued = await this.acme.orderCertificate(fqdns, this.challengeHandler);
|
const issued = await this.acme.orderCertificate(fqdns, this.challengeHandler);
|
||||||
const [cert, format] = this.config.pfx
|
if (this.config.pfx) {
|
||||||
? [pemToPfx(issued.privateKeyPem, issued.certificatePem, issued.chainPem), 'pfx' as const]
|
const password = randomUUID();
|
||||||
: [issued.privateKeyPem + issued.certificatePem + issued.chainPem, 'pem' as const];
|
await this.store.importCertificate(certName, pemToPfx(issued.privateKeyPem, issued.certificatePem, issued.chainPem, password), 'pfx', password);
|
||||||
await this.store.importCertificate(certName, cert, format);
|
} else {
|
||||||
|
await this.store.importCertificate(certName, issued.privateKeyPem + issued.certificatePem + issued.chainPem, 'pem');
|
||||||
|
}
|
||||||
|
|
||||||
if (status === 'missing') {
|
if (status === 'missing') {
|
||||||
result.certificatesIssued.push(primary.fqdn);
|
result.certificatesIssued.push(primary.fqdn);
|
||||||
@@ -157,9 +160,10 @@ export class Provisioner {
|
|||||||
if (currentFormat === 'pem') {
|
if (currentFormat === 'pem') {
|
||||||
const bundle = parsePemBundle(secretValue);
|
const bundle = parsePemBundle(secretValue);
|
||||||
this.log(`[convert] parsed blocks — key: ${bundle.privateKeyPem.length} chars, cert: ${bundle.certPem.length} chars, chain: ${bundle.chainPem.length} chars`);
|
this.log(`[convert] parsed blocks — key: ${bundle.privateKeyPem.length} chars, cert: ${bundle.certPem.length} chars, chain: ${bundle.chainPem.length} chars`);
|
||||||
const pfxBuffer = pemToPfx(bundle.privateKeyPem, bundle.certPem, bundle.chainPem);
|
const password = randomUUID();
|
||||||
|
const pfxBuffer = pemToPfx(bundle.privateKeyPem, bundle.certPem, bundle.chainPem, password);
|
||||||
this.log(`[convert] PFX buffer size: ${pfxBuffer.length} bytes`);
|
this.log(`[convert] PFX buffer size: ${pfxBuffer.length} bytes`);
|
||||||
await this.store.importCertificate(certName, pfxBuffer, 'pfx');
|
await this.store.importCertificate(certName, pfxBuffer, 'pfx', password);
|
||||||
} else {
|
} else {
|
||||||
const bundle = pfxToPem(Buffer.from(secretValue, 'base64'));
|
const bundle = pfxToPem(Buffer.from(secretValue, 'base64'));
|
||||||
this.log(`[convert] parsed PFX — key: ${bundle.privateKeyPem.length} chars, cert: ${bundle.certPem.length} chars, chain: ${bundle.chainPem.length} chars`);
|
this.log(`[convert] parsed PFX — key: ${bundle.privateKeyPem.length} chars, cert: ${bundle.certPem.length} chars, chain: ${bundle.chainPem.length} chars`);
|
||||||
|
|||||||
Reference in New Issue
Block a user