Surge 自签发 CA 根证书

准备工具

  • macOS / Ubuntu
  • OpenSSL

macOS 自带了 OpenSSL(LibreSSL),不需要另行安装。Ubuntu 可以使用包管理器安装 OpenSSL:

apt install openssl

LibreSSL 与 OpenSSL 在使用上几乎一致,不过默认摘要算法有所不同。下文命令中的 -sha256 在较新版本 OpenSSL (Ubuntu) 下可以省略,但在 LibreSSL (macOS) 下不能省略。[1]

Easy Way:使用 openssl x509 工具签发

首先做好准备工作:

mkdir cert && cd cert # 创建存放证书的文件夹

生成私钥:

openssl genrsa -out ca.key 2048 # 生成 RSA 私钥

# 或者
openssl ecparam -genkey -name prime256v1 -out ca.key # 生成 ECC 私钥
# -name 后的字段指定了椭圆曲线算法
# 可通过 openssl ecparam -list_curves 查看所有可选项
# 目前可用算法只有 prime256v1 (secp256r1), secp384r1, secp521r1 三种

随后,用 openssl req 生成证书请求:

openssl req -new -sha256 -key ca.key -out ca.csr

# 参数说明:
# -new 生成新的证书请求
# -sha256 使用 SHA-256 摘要算法
# -key 指定已有的私钥文件
# -out 指定生成的证书请求名

此时,openssl 会让你逐条填入证书主题 (subject):

$ openssl req -new -sha256 -key ca.key -out ca.csr

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

其中,Common Name 为必填项,它将成为证书安装时的名称;其他项目均为可选填。如果要留空某个项目,则填入 . 即可。以下是填写示例:

Country Name (2 letter code) [AU]:HK
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
Organizational Unit Name (eg, section) []:.
Common Name (e.g. server FQDN or YOUR name) []:Custom CA
Email Address []:.

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:.
An optional company name []:.

如果你不想一条条地填写,那么你也可以在生成证书请求时直接指定证书主题:

openssl req -new -sha256 -key ca.key -out ca.csr -subj "/C=HK/CN=Custom CA"

最后,用 openssl x509 进行自签名,得到根证书:

openssl x509 -req -sha256 -days 3650 -in ca.csr -signkey ca.key -out ca.crt

# 参数说明:
# -req 指定输入的是证书请求文件
# -sha256 使用 SHA-256 摘要算法
# -days 指定证书的有效时间,示例中为 3650 天
# -in 指定证书请求文件
# -signkey 指定私钥文件以进行自签名
# -out 指定生成的证书名

另外,用 openssl req 生成证书请求和用 openssl x509 自签名的两步也可以只用 openssl req 一行命令完成:

openssl req -x509 -new -sha256 -key ca.key -days 3650 -out ca.crt -subj "/C=HK/CN=Custom CA"

# 注意这里并不是用 x509,而是用 req 工具签发的证书

# 参数说明:
# -x509 指定输出一个 X509 格式的证书
# -new 生成新的证书请求
# -sha256 使用 SHA-256 摘要算法
# -key 指定已有的私钥文件
# -days 指定证书的有效时间,示例中为 3650 天
# -out 指定生成的证书名
# -subj 指定证书主题,格式参见示例

Hard Way:使用 openssl ca 签发

使用 openssl x509 工具签发非常方便,然而,如果我们要自定义更多内容(尤其是证书的生效时间、失效时间),openssl x509 就不能实现了。这时,我们就需要借助 openssl ca 来完成。

首先依旧是做好准备工作:

mkdir cert && cd cert # 创建存放证书的文件夹

openssl genrsa -out ca.key 2048 # 生成 RSA 私钥
# 或者
openssl ecparam -genkey -name prime256v1 -out ca.key # 生成 ECC 私钥

随后,用 openssl req 生成证书请求:

openssl req -new -sha256 -key ca.key -out ca.csr -subj "/C=HK/CN=Custom CA"

在用 openssl ca 签发前,我们还需要进行一些配置。首先将默认的 openssl ca 配置文件拷贝到当前目录:

cp /private/etc/ssl/openssl.cnf . # macOS

cp /usr/lib/ssl/openssl.cnf . # Ubuntu

编辑配置文件:vim openssl.cnf

对于配置文件,我们需要修改 [ CA_default ] 下 dir =  这一项,将其改为 .,即当前目录。

随后,准备必须的文件:

touch index.txt && echo 01 > serial

最后,签发证书:

openssl ca -selfsign -in ca.csr -out ca.crt -outdir . -keyfile ca.key -startdate 20190101000000Z -enddate 20290101000000Z -config openssl.cnf -extensions v3_ca -notext -md sha256 -policy policy_anything

# 参数说明:
# -selfsign 使用证书请求中附带的私钥对该请求进行签名,即自签名
# -in 指定证书请求文件
# -out 指定生成的证书名
# -outdir 指定新证书的输出位置
# -keyfile 指定已有的私钥文件
# -startdate 指定证书生效时间,格式为 YYYYMMDDHHMMSSZ 或 YYMMDDHHMMSSZ,时区为 GMT
# -enddate 指定证书失效时间,格式同上
# -config 指定所使用的配置文件
# -extensions 指定使用的扩展字段,选取 v3_ca 来签发 CA 机构证书
# -notext 在生成的证书文件中,不输出文本格式的证书信息
# -md 指定摘要算法,选择 SHA-256
# -policy 指定 CA 策略,使用 policy_anything 以允许不完整的证书主题

在提示 Sign the certificate? 和 1 out of 1 certificate requests certified, commit? 时,按 y 并回车确认即可。

将证书打包并编码

首先将证书打包为 p12 格式:

openssl pkcs12 -export -clcerts -in ca.crt -inkey ca.key -out ca.p12 -password pass:AbCd1234

# 参数说明:
# -export 指定输出一个 PKCS 12 文件
# -clcerts 仅输出客户端证书
# -in 指定证书文件
# -inkey 指定私钥文件
# -out 指定生成的文件名
# -password 指定密码,示例中密码为 AbCd1234

随后对 p12 格式的证书进行 BASE64 编码:

base64 ca.p12

# 或者直接将编码结果复制到剪贴板:
base64 ca.p12 | pbcopy

修改 Surge 配置文件

在 Surge 配置文件的 [MITM] 部分写入如下内容:

[MITM]
ca-passphrase = 上一步中设置的 password
ca-p12 = 上一步中 BASE64 编码后的结果

安装并信任证书

方法 1:借助 Quantumult X 安装

在 Quantumult X 配置文件的 [mitm] 部分写入如下内容:

[mitm]
passphrase = 上一步中设置的 password
p12 = 上一步中 BASE64 编码后的结果

随后在设置中点击 Install CA 安装证书,再到 设置 > 通用 > 关于 > 证书信任设置 中打开对该根证书的完全信任即可。

方法 2:借助 GitHub Gist 下载安装

打开 GitHub,登录你的 GitHub 账号,然后打开 GitHub Gists

使用以下命令将要安装的证书内容拷贝到剪贴板:

pbcopy < ca.crt

在新建的 gist 中,Filename including extension 填入 ca.crt,文件内容中粘贴你复制到的内容。随后点击 Create secret gist 新建 gist。

随后,在该 gist 页面右键点击右上角的 Raw,选择 Copy Link。将获得的网址粘贴到 iOS Safari 浏览器中并前往,按提示安装证书,再到 设置 > 通用 > 关于 > 证书信任设置 中打开对该根证书的完全信任即可。

小结

至此,我们成功为 Surge 签发并安装了 CA 根证书。另外,我们得到的 p12 和 passphrase 也可以用于其他代理软件的 MitM,从而使我们不需要多次生成和安装证书。