专注于高性能网络应用开发,核心技术包括PHP、Java、GO、NodeJS等后端语言,VUE、UNI、APP等前端开发,服务器运维、数据库、实时通信、AI等领域拥有丰富经验

Go 语言生成在 macOS 、 iOS、Windows 下可用的自签 CA 及域名证书

在开发内网服务或测试 HTTPS 接口时,我们经常需要自签发 CA 及域名证书,之前有介绍一个工具 macOS下使用mkcert创建本地HTTPS证书完全指南,如果你不想安装工具的话,就可以使用本教程提供的在线生成证书教程。对于 macOS,使用自签 CA 证书通常比较简单,但 iOS 对证书信任有更严格的要求,直接生成的证书往往无法被 iOS 信任。本文将介绍如何使用 Go 语言生成符合 macOS 和 iOS 要求的 CA 证书,并签发域名证书,同时讲解 iOS 的信任机制及常见坑点。

  1. 显式使用 SHA-2 系列签名算法
  2. 设置 EKU 为 serverAuth
  3. 控制有效期 ≤ 825 天
  4. 确保 SAN 填写完整
  5. 部署时使用完整证书链

先用后讲原理

通过在线生成工具 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 证书有严格的规则:

  1. 签名算法必须是 SHA-2 系列
    iOS 不再信任使用 SHA-1 的证书,包括 CA 和服务器证书。推荐使用 SHA256、SHA384 或 SHA512。
  2. TLS 服务器证书必须包含 serverAuth EKU
    ExtKeyUsageServerAuth,否则 iOS 会拒绝。
  3. TLS 服务器证书有效期 ≤ 825 天
    超过 825 天的证书会被 iOS 拒绝。
  4. 证书链必须完整
    服务器需要返回完整链(leaf + CA)。macOS 有时会自动补全,但 iOS 不会。
  5. 必须安装根 CA 并“完全信任”
    设置路径:设置 → 通用 → 关于本机 → 证书信任设置

二、Go 语言实现方案

1. 生成自签 CA 证书

使用 Go 的 crypto/x509 包可以生成 RSA 或 ECC 根证书。需要注意几点:

  • 显式指定 SignatureAlgorithm(避免默认 SHA-1)
  • 生成 ECC 时根据曲线选择 SHA256/384/512
  • 设置 KeyUsage 包含 CertSignDigitalSignatureCRLSign
  • 为 CA 证书生成 SubjectKeyIdAuthorityKeyId

示例代码片段:

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()

相关文章

macOS启动台消失不用慌:命令行一键恢复指南

经过我的测试,最新的系统中启动命令已经不能正常使用了,但是恢复命令却是可以的! 另外就是...26太不习惯了...果断切回14.8俗话说,我可不用,但你不能不给呀...结果升级了新系统后,你给我...

macOS下使用mkcert创建本地HTTPS证书完全指南

在Web开发过程中,我们经常需要在本地环境中测试HTTPS功能。传统的自签名证书会导致浏览器显示不安全警告,影响开发体验和测试结果。而公共证书服务(如Let's Encrypt)不适合本地开发使...