一个自托管、100% 客户端运行的 PKI 工件工具箱:X.509 证书、PKCS#10 CSR、证书链、CRL、PKCS#7 和 PKCS#12 包、原始 ASN.1、格式转换、指纹以及证书签发。一个尊重隐私、可自托管的 在线证书解码器替代方案。
在线演示: https://pki-toolbox.youkyi.net(该演示与你在下方可自托管的 静态构建完全相同;你粘贴的任何内容都不会离开你的浏览器)。
每一个字节都在你的浏览器内部通过 @peculiar/x509
和 pkijs 解析。任何内容都不会被
上传,后端只提供静态文件。你不必仅凭信任接受这一点:请参阅下方的
可验证的隐私。
| 工具 | 类别 | 描述 |
|---|---|---|
| 证书解码器 | 解码 | X.509 证书的每一个字段:主体、颁发者、有效期、SAN、密钥用途、指纹 |
| CSR 解码器 | 解码 | PKCS#10 请求的主体、公钥、签名算法和请求的扩展 |
| 证书链解码器 | 解码 | 将拼接的 PEM 包拆分为有序证书链,并验证每一条颁发者到主体的链接 |
| CRL 解码器 | 解码 | 已吊销条目、日期和吊销原因 |
| PKCS#7 解码器 | 解码 | PKCS#7 / CMS 包中携带的每一张证书 |
| PKCS#12 解码器 | 解码 | 打开受密码保护的 .p12 / .pfx 文件 |
| 指纹 | 检查 | DER 的 SHA-1 / SHA-256 / SHA-512 |
| ASN.1 查看器 | 检查 | 任意 DER 工件的可展开标签/长度/值树 |
| 格式转换 | 转换 | PEM ↔ DER ↔ PKCS#7 |
| 自签名证书 | 生成 | 通过 WebCrypto 生成自签名证书和密钥对(RSA / EC / Ed25519) |
| 从 CA 签发 | 生成 | 从现有 CA 签发证书:新密钥对或 CSR、叶子或中间证书,附带可直接使用的完整链 |
工具目录位于单一注册表(src/lib/tools.ts)中,该注册表驱动
导航栏和首页网格。
围绕工具本身:
src/lib/pki/detect.ts),并在读取它的工具中打开。/ 会将光标置于输入框中。“它永远不会离开你的浏览器”这一说法可以从页面内部进行验证:
connect-src 指令,统计自你粘贴以来能够携带数据外发的请求数量,并在你面前运行一次浏览器会拒绝的实时尝试,同时引用阻止它的那条指令。始终运行固定且不可变的发布标签(vX.Y.Z),绝不要使用 latest:移动的标签无法审计或回滚。为获得最强保证,请固定镜像摘要(...@sha256:...)。
docker run -p 8080:8080 ghcr.io/youkyi/pki-toolbox:v2.2.0
然后打开 http://localhost:8080。
每个版本都会以相同的不可变 vX.Y.Z 标签发布到:
| 镜像仓库 | 镜像 |
|---|---|
| GitHub Container Registry | ghcr.io/youkyi/pki-toolbox |
| Docker Hub | youkyi/pki-toolbox |
docker pull ghcr.io/youkyi/pki-toolbox:v2.2.0 # or
docker pull youkyi/pki-toolbox:v2.2.0
services:
pki-toolbox:
image: ghcr.io/youkyi/pki-toolbox:v2.2.0
ports:
- '8080:8080'
restart: unless-stopped
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
docker compose up -d
仓库提供了一个完全加固的 docker-compose.yml(只读根文件系统、丢弃 capabilities、内存和 CPU 限制);请直接使用该文件,而不是这个最小示例。
镜像基于 nginx:alpine-slim 构建,大小约 25 MB,监听非特权端口 8080,并以非 root 用户运行。
需要 Node 24(镜像和 CI 构建所用的版本)和 pnpm 11。确切的 pnpm 版本由 package.json 的 packageManager 字段固定,因此执行 corepack enable 即可获取。
pnpm install
pnpm dev # dev server on http://localhost:5173
pnpm test # unit tests, single run (Vitest)
pnpm test:unit # the same tests, in watch mode
pnpm test:e2e # end-to-end tests (Playwright)
pnpm test:e2e:ui # the same, in the Playwright UI
pnpm check # svelte-check / TypeScript
pnpm lint # Prettier + ESLint
pnpm format # rewrite files with Prettier
pnpm build # static build into ./build
pnpm preview # serve ./build locally
docker build -t pki-toolbox .
docker run -p 8080:8080 pki-toolbox
adapter-static 构建为纯
HTML/JS:每个路由都经过预渲染,生产环境中没有 Node 运行时。src/lib/pki/ 下的纯函数中,可测试,且不导入
Svelte:parse.ts、chain.ts、crl.ts、pkcs7.ts、pkcs12.ts、
asn1.ts、convert.ts、format.ts、pem.ts、oids.ts、detect.ts、
generate.ts 和 sign.ts。src/routes/ 下的每个路由都是围绕它们的
轻量 UI 外壳。@peculiar/x509 v2 通过 tsyringe 构建其对象,这需要在消费方提供
Reflect 元数据 polyfill,因此在每个使用该库的模块中,@abraham/reflection
都会先于它被导入。pkijs 处理,其 Web Crypto 引擎在
src/lib/pki/engine.ts 中注册一次。tests/pki/(Vitest),浏览器测试位于 e2e/
(Playwright)。测试夹具是真实的公共根证书(ISRG Root X1/X2)加上
生成的 EC 链和 CSR,参见 scripts/generate-fixtures.mjs。<meta> 标签形式
发出,包含 connect-src 'none';nginx 添加
frame-ancestors 'none'、X-Frame-Options、X-Content-Type-Options、
Referrer-Policy: no-referrer、限制性的 Permissions-Policy 以及
跨源隔离头。Vercel 演示发送相同的头集合
(参见 vercel.json)。docker-compose.yml 添加了只读根文件系统、cap_drop: ALL、
no-new-privileges 和资源限制。trivy fs)还是在新构建的镜像上,当基础操作系统
生命周期结束时镜像也会被拒绝。镜像以未标记的候选形式推送,按摘要扫描,
并且只有经过扫描的摘要才会被提升,因此有漏洞的镜像永远不会获得版本标签。
许可证在单独的非阻塞流程中扫描。本项目遵循 语义化版本 和
约定式提交。重要变更
记录在 CHANGELOG.md 中。贡献规则位于
CONTRIBUTING.md。
CHANGELOG.md 中,将 ## [Unreleased] 标题重命名为
新版本号并附上今天的日期,例如 ## [1.2.3] - 2026-06-01,在其上方添加
一个新的空 ## [Unreleased],并更新文件底部的链接引用。package.json 中的 "version" 提升为相同的数字。main 上提交(约定式提交,例如 chore(release): 1.2.3)并
推送。git tag -a v1.2.3 -m "pki-toolbox v1.2.3"
git push origin v1.2.3
每次推送都会运行代码检查、单元测试和端到端测试。扫描、构建和发布阶段来自共享的 YouKyi-Infra/ci-infrastructure/ci-catalog 组件(gitleaks-scan、ggshield-scan、trivy-vuln、trivy-secret、trivy-license、container-image、gitlab-release),并在 .gitlab-ci.yml 中按版本固定。
vX.Y.Z 标签会运行整条链路:仓库扫描、以 candidate-* 标签推送的镜像构建、按摘要进行的镜像扫描、将该摘要提升为 GitLab 仓库中的 vX.Y.Z 并同步到公共镜像源(ghcr.io、Docker Hub),然后生成一个 GitLab Release,其发布说明是从 CHANGELOG.md 中提取的对应 ## [X.Y.Z] 章节(章节为空会导致任务失败,而不是发布空的发布说明)。
推送到 main 会运行相同的流水线,但不包含发布步骤;镜像任务仅在影响构建的文件发生变更时运行,因此仅涉及文档或配置的推送不会重新构建镜像。
依赖项由 Renovate 保持更新,它扩展了共享的 Renovate-Bot/renovate-config 预设(参见 renovate.json)。