背景及需求
最近,我把自定义的 Surge 配置文件托管到了 GitHub Gist 上(当然,用的是 secret gist)。同时,为了在 Surge app 里看着舒服,我把配置文件写成了 Managed Configuration 的形式。由于 GitHub Gist RAW 文件的 URL 会带有 commit ID,此方式不可用,咱还是太蠢了…(其实把 URL 后面的部分删了就行了,咱确实太年轻了 QAQ…)但是,这也带来了一定的问题 —— Surge 的 Managed Configuration 是完全不可更改的,因此也不能在本地生成并安装 CA 根证书。
为了让 Managed Configuration 也能实现 MitM,我们必须提前自签发 CA 根证书,并在 iOS 系统中安装和信任,同时确保 Surge 配置文件中含有正确的 ca-passphrase
及 ca-p12
。
除此之外,自签 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,从而使我们不需要多次生成和安装证书。
↩︎ 注
在签发根证书(即本文目的)时,并不一定要指定摘要算法为 SHA-256;但在签发服务器证书时,必须指定为 SHA-256,否则 iOS 13/macOS 10.15 以上的系统将不再信任所用证书(参见 Apple 支持页面)。在本文完成时,macOS 自带的 OpenSSL (LibreSSL 2.8.3) 默认摘要算法仍为 SHA-1,必须手动指定摘要算法;而 Ubuntu 通过包管理器安装的 OpenSSL 1.1.1 默认摘要算法已更改为 SHA-256,不需要手动指定。