diff --git a/packages/core/acme-client/src/crypto/forge.js b/packages/core/acme-client/src/crypto/forge.js index 4bf942c8..b13f4b1a 100644 --- a/packages/core/acme-client/src/crypto/forge.js +++ b/packages/core/acme-client/src/crypto/forge.js @@ -10,6 +10,7 @@ const net = require('net'); const { promisify } = require('util'); const forge = require('node-forge'); +const { createPrivateEcdsaKey, getPublicKey } = require('./index'); const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair); @@ -378,13 +379,17 @@ function formatCsrAltNames(altNames) { * }, certificateKey); */ -exports.createCsr = async (data, key = null) => { - if (!key) { +exports.createCsr = async (data, keyType = null) => { + let key = null; + if (keyType === 'ec') { + key = await createPrivateEcdsaKey(); + } + else { key = await createPrivateKey(data.keySize); } - else if (!Buffer.isBuffer(key)) { - key = Buffer.from(key); - } + // else if (!Buffer.isBuffer(key)) { + // key = Buffer.from(key); + // } if (typeof data.altNames === 'undefined') { data.altNames = []; @@ -396,6 +401,8 @@ exports.createCsr = async (data, key = null) => { const privateKey = forge.pki.privateKeyFromPem(key); const publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e); csr.publicKey = publicKey; + // const privateKey = key; + // csr.publicKey = getPublicKey(key); /* Ensure subject common name is present in SAN - https://cabforum.org/wp-content/uploads/BRv1.2.3.pdf */ if (data.commonName && !data.altNames.includes(data.commonName)) { diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts index 2569d63a..f191b8a9 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -14,6 +14,7 @@ export type CertInfo = { csr: string; }; export type SSLProvider = "letsencrypt" | "google" | "zerossl"; +export type PrivateKeyType = "rsa" | "ec"; type AcmeServiceOptions = { userContext: IContext; logger: Logger; @@ -21,6 +22,7 @@ type AcmeServiceOptions = { eab?: ClientExternalAccountBindingOptions; skipLocalVerify?: boolean; useMappingProxy?: boolean; + privateKeyType?: PrivateKeyType; }; export class AcmeService { @@ -208,18 +210,33 @@ export class AcmeService { } } - async order(options: { email: string; domains: string | string[]; dnsProvider: any; csrInfo: any; isTest?: boolean }) { + async order(options: { + email: string; + domains: string | string[]; + dnsProvider: any; + csrInfo: any; + isTest?: boolean; + privateKeyType?: string; + }): Promise { const { email, isTest, domains, csrInfo, dnsProvider } = options; const client: acme.Client = await this.getAcmeClient(email, isTest); /* Create CSR */ const { commonName, altNames } = this.buildCommonNameByDomains(domains); - - const [key, csr] = await acme.forge.createCsr({ - commonName, - ...csrInfo, - altNames, - }); + let privateKey = null; + if (options.privateKeyType == "ec") { + privateKey = await acme.crypto.createPrivateEcdsaKey(); + } else { + privateKey = await acme.crypto.createPrivateRsaKey(); + } + const [key, csr] = await acme.forge.createCsr( + { + commonName, + ...csrInfo, + altNames, + }, + privateKey + ); if (dnsProvider == null) { throw new Error("dnsProvider 不能为空"); } diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index 88f96a77..fd62426b 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -1,5 +1,5 @@ import { Decorator, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; -import type { CertInfo, SSLProvider } from "./acme.js"; +import type { CertInfo, PrivateKeyType, SSLProvider } from "./acme.js"; import { AcmeService } from "./acme.js"; import _ from "lodash-es"; import { DnsProviderContext, DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider/index.js"; @@ -42,6 +42,21 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }) sslProvider!: SSLProvider; + @TaskInput({ + title: "证书私钥类型", + value: "rsa", + component: { + name: "a-select", + vModel: "value", + options: [ + { value: "rsa", label: "RSA" }, + { value: "ec", label: "EC" }, + ], + }, + required: true, + }) + privateKeyType!: PrivateKeyType; + @TaskInput({ title: "EAB授权", component: { @@ -116,6 +131,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { eab, skipLocalVerify: this.skipLocalVerify, useMappingProxy: this.useProxy, + privateKeyType: this.privateKeyType, }); } @@ -156,6 +172,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { dnsProvider, csrInfo, isTest: false, + privateKeyType: this.privateKeyType, }); const certInfo = this.formatCerts(cert); diff --git a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts index 99cc34a3..56f7dc14 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts @@ -283,6 +283,9 @@ export class PipelineService extends BaseService { const entity: PipelineEntity = await this.info(id); const pipeline = JSON.parse(entity.content); + if (!pipeline.id) { + pipeline.id = id; + } if (!pipeline.stages || pipeline.stages.length === 0) { return; @@ -306,7 +309,7 @@ export class PipelineService extends BaseService { await this.saveHistory(history); } catch (e) { const pipelineEntity = new PipelineEntity(); - pipelineEntity.id = parseInt(history.pipeline.id); + pipelineEntity.id = id; pipelineEntity.status = 'error'; pipelineEntity.lastHistoryTime = history.pipeline.status.startTime; await this.update(pipelineEntity); @@ -339,7 +342,7 @@ export class PipelineService extends BaseService { } } - async cancel(historyId) { + async cancel(historyId:number) { const executor = runningTasks.get(historyId); if (executor) { await executor.cancel();