Go 语言生成在 macOS 、 iOS、Windows 下可用的自签 CA 及域名证书
在开发内网服务或测试 HTTPS 接口时,我们经常需要自签发 CA 及域名证书,之前有介绍一个工具 macOS下使用mkcert创建本地HTTPS证书完全指南,如果你不想安装工具的话,就可以使用本教程提供的在线生成证书教程。对于 macOS,使用自签 CA 证书通常比较简单,但 iOS 对证书信任有更严格的要求,直接生成的证书往往无法被 iOS 信任。本文将介绍如何使用 Go 语言生成符合 macOS 和 iOS 要求的 CA 证书,并签发域名证书,同时讲解 iOS 的信任机制及常见坑点。
- 显式使用 SHA-2 系列签名算法
- 设置 EKU 为 serverAuth
- 控制有效期 ≤ 825 天
- 确保 SAN 填写完整
- 部署时使用完整证书链
先用后讲原理
通过在线生成工具 https://tool.lvtao.net/mkcert 生成证书后,比如我使用的
macOS下安装CA证书并信任
双击ca.crt,打开macOS的钥匙串访问
登录中找到如下
双击打开
展开信任,选择始终信任
点击关闭X即可,会要你输入系统登录密码,你输入即可
现在你的macOS证书安装成功了
网站站点安装证书,将domain.crt和domain.key根据你的站点配置即可
比如我nginx中的是
listen 443 ssl;
ssl_certificate ssl/diqi.net+6.crt;
ssl_certificate_key ssl/diqi.net+6.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
现在在pc上访问是正常了
iOS移动端稍复杂一点
比如我签的IP,它会提示我不信任
先安装ca证书,tool工具生成站会有对应的ca根证书,你直接点击安装即可,选择允许
文件下载应该会很,提示关闭即可
然后打开手机设置
-通用
-VPN与设备管理
找到配置描述文件,点击证书
点击安装
,输入密码,警告提示,继续安装
还没完,我开始以为只到这一步就可以了,发现打开还是提示我不信任
依次是 设置
- 通用
- 关于本机
- 证书信任设置
将证书后的开关打开
再访问就正常了
windows下信任CA证书
下载证书,打开文件
如果有这个提示 直接打开
提示这个证书不受信任,并告诉我们要安装到受信任的根证书颁发机构
存储区
点击安装证书
选择本地计算机
下一步,指定存储位置
浏览 选择受信任的根证书颁发机构
切记一定要指定这个位置,不然即使你安装了,依旧会有下面的这样的提示
确认再下一步
成功 确认
这样就可以了
windows下的证书管理,在控制面板中管理用户证书
这是我们安装的证书
好啦!现在我们就可以愉快的玩耍了...
接着我们讲下源代码
一、iOS 对证书的要求
苹果官方对 TLS 证书有严格的规则:
- 签名算法必须是 SHA-2 系列
iOS 不再信任使用 SHA-1 的证书,包括 CA 和服务器证书。推荐使用 SHA256、SHA384 或 SHA512。 - TLS 服务器证书必须包含
serverAuth
EKU
即ExtKeyUsageServerAuth
,否则 iOS 会拒绝。 - TLS 服务器证书有效期 ≤ 825 天
超过 825 天的证书会被 iOS 拒绝。 - 证书链必须完整
服务器需要返回完整链(leaf + CA)。macOS 有时会自动补全,但 iOS 不会。 - 必须安装根 CA 并“完全信任”
设置路径:设置 → 通用 → 关于本机 → 证书信任设置
。
二、Go 语言实现方案
1. 生成自签 CA 证书
使用 Go 的 crypto/x509
包可以生成 RSA 或 ECC 根证书。需要注意几点:
- 显式指定
SignatureAlgorithm
(避免默认 SHA-1) - 生成 ECC 时根据曲线选择 SHA256/384/512
- 设置
KeyUsage
包含CertSign
、DigitalSignature
、CRLSign
- 为 CA 证书生成
SubjectKeyId
和AuthorityKeyId
示例代码片段:
caTmpl := &x509.Certificate{
Subject: pkix.Name{
CommonName: "Dev RSA Root CA",
},
SignatureAlgorithm: x509.SHA256WithRSA,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(30, 0, 0), // 根 CA 可长期有效
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
IsCA: true,
MaxPathLenZero: true,
SubjectKeyId: keyID,
AuthorityKeyId: keyID,
}
2. 签发域名证书
生成域名证书时,需要满足 iOS 的要求:
- 设置
ExtKeyUsage
包含ExtKeyUsageServerAuth
- KeyUsage 根据算法选择:RSA 加
KeyEncipherment
,ECC 只用DigitalSignature
NotAfter
≤ 825 天- SAN(Subject Alternative Name)字段必须填写域名或 IP,否则 iOS 拒绝
示例:
certTmpl := &x509.Certificate{
SerialNumber: big.NewInt(time.Now().UnixNano()),
Subject: pkix.Name{
CommonName: domains[0],
},
SignatureAlgorithm: x509.SHA256WithRSA,
NotBefore: time.Now().Add(-time.Minute),
NotAfter: time.Now().Add(2*365*24*time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
DNSNames: dnsNames,
IPAddresses: ipAddresses,
SubjectKeyId: generateKeyID(pubKey),
AuthorityKeyId: caCert.SubjectKeyId,
}
3. 完整证书链与 iOS 信任
iOS 验证证书时要求完整链,如果服务器只返回 leaf 证书,会导致“不信任”错误。解决方案:
- 将 leaf 证书和 CA 证书拼接成 fullchain:
fullChain := append(leafCertPEM, caCertPEM...)
- 部署服务器时使用
fullchain
作为证书链文件 - 确保私钥对应 leaf 证书
4. 打包证书供下载
在开发环境中,可以使用 Go 的 archive/zip
打包生成的 CA 和域名证书供下载,包括:
ca.crt
(根 CA)domain.crt
(域名证书)domain.key
(域名私钥)domain-fullchain.crt
(leaf + CA)
示例:
zw := zip.NewWriter(buf)
add("ca.crt", caCertPEM)
add("domain.crt", certPEM)
add("domain.key", keyPEM)
add("domain-fullchain.crt", fullChain)
zw.Close()
版权声明:本文为原创文章,版权归 全栈开发技术博客 所有。
本文链接:https://www.lvtao.net/tool/go-ca-certificates.html
转载时须注明出处及本声明