From 2a2e9e0d6b83d15564e7266aa8a3f846e0fa3902 Mon Sep 17 00:00:00 2001 From: cheney Date: Wed, 1 Jul 2026 15:27:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Readme.md | 3 +- src/App.tsx | 152 ++++++++++++- src/__tests__/algorithm/cert.test.ts | 42 ++++ src/utils/algorithm/cert.ts | 318 +++++++++++++++++++++------ 4 files changed, 445 insertions(+), 70 deletions(-) create mode 100644 src/__tests__/algorithm/cert.test.ts diff --git a/Readme.md b/Readme.md index c750ad5..675e33c 100644 --- a/Readme.md +++ b/Readme.md @@ -2,4 +2,5 @@ - [x] CI 集成,将 dist 传输到指定服务器指定目录。 - [x] 添加 SM2 算法 - +- [x] 证书工具支持输入逗号分隔证书 id 并下载 DER 格式 CRL 文件。 +- [x] 根证书生成后支持下载 CRT 文件和根证书私钥。 diff --git a/src/App.tsx b/src/App.tsx index 9333704..a67e343 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import { VERSION } from './version' import { sm3Digest, sm3Hmac } from './utils/algorithm/sm3' import { sm4Encrypt, sm4Decrypt } from './utils/algorithm/sm4' import { sm2GenerateKeyPair, sm2GetPublicKeyFromPrivateKey, sm2Encrypt, sm2Decrypt, sm2Sign, sm2Verify, sm2DerToC1C3C2, sm2C1C3C2ToDer } from './utils/algorithm/sm2' -import { parseSm2Cert, parseCertFromFile, generateRootCert, generateAppCert } from './utils/algorithm/cert' +import { parseSm2Cert, parseCertFromFile, generateRootCert, generateAppCert, generateCrlFile, loadRootPrivateKeyFromCache } from './utils/algorithm/cert' import { hexToUtf8, utf8ToHex, hexToBase64, base64ToHex } from './utils/convert' import { getInfoFromPKCS7, verifyPKCS7 } from './utils/crypto.js' @@ -182,6 +182,7 @@ function App() { const [appCert, setAppCert] = useState('') const [commonName, setCommonName] = useState('test.example.com') const [certError, setCertError] = useState('') + const [crlCertificateIds, setCrlCertificateIds] = useState('') // PKCS7 签名工具状态 const [pkcs7Signature, setPkcs7Signature] = useState('') @@ -335,6 +336,46 @@ function App() { setCertError((error as Error).message) } } + + // 下载文本文件 + // 参数:content 为文件内容,fileName 为下载文件名,mimeType 为文件类型。 + // 返回值:无。 + const downloadTextFile = (content: string, fileName: string, mimeType: string) => { + const blob = new Blob([content], { type: mimeType }) + const downloadUrl = URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = downloadUrl + link.download = fileName + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(downloadUrl) + } + + // 处理根证书文件下载 + // 参数:无。 + // 返回值:无。 + const handleDownloadRootCert = () => { + if (!rootCert) { + setCertError('请先生成根证书') + return + } + downloadTextFile(rootCert, 'root-cert.crt', 'application/x-x509-ca-cert') + setCertError('') + } + + // 处理根证书私钥下载 + // 参数:无。 + // 返回值:无。 + const handleDownloadRootPrivateKey = () => { + const rootPrivateKey = loadRootPrivateKeyFromCache() + if (!rootPrivateKey) { + setCertError('根证书私钥不存在,请重新生成根证书') + return + } + downloadTextFile(rootPrivateKey, 'root-private-key.key', 'application/x-pem-file') + setCertError('') + } // 处理生成应用证书 const handleGenerateAppCert = () => { @@ -346,6 +387,28 @@ function App() { setCertError((error as Error).message) } } + + // 处理 CRL 文件下载 + // 参数:无。 + // 返回值:无。 + // 注意事项:证书 id 按证书序列号处理,多个 id 使用英文逗号分隔。 + const handleDownloadCrlFile = () => { + try { + const crlFile = generateCrlFile(crlCertificateIds) + const blob = new Blob([crlFile], { type: 'application/pkix-crl' }) + const downloadUrl = URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = downloadUrl + link.download = 'certificate-revocation-list.crl' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(downloadUrl) + setCertError('') + } catch (error) { + setCertError((error as Error).message) + } + } // 处理 PKCS7 签名信息提取 const handleGetInfoFromPKCS7 = () => { @@ -1678,6 +1741,40 @@ function App() { minHeight: '150px' }} /> +
+ + +
)} @@ -1755,9 +1852,56 @@ function App() { )} + {/* 生成 CRL 文件 */} +
+

3. 生成 CRL 文件

+
+ +