开发者用特殊公钥抗议SSL/TLS证书体系
来源标题:Horrible Public Key Tricks
开发者Maurycyz通过使用特殊私钥(如313333333337)生成可被轻易破解的证书,以此抗议SSL/TLS证书机制过于复杂。他指出证书需频繁续期、依赖ACME自动化,且系统本身存在明文签发等问题,但强调仍希望加密流量以防被动窃听。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
我一直对 SSL/TLS 有点不爽。它要求每个想架设公开网站的人都要走一遍复杂的「ACME」流程。更糟的是,证书每几个月就过期一次,所以不是一劳永逸的事:即便有自动化,维护证书也需要小心确保 ACME 客户端始终能访问 DNS 记录或 Web 服务器。……而且这整套系统根本就行不通,因为证书是通过明文连接签发的,而受信任的证书颁发机构用的还是像「4」这样非常安全的密钥。以前也有过抗议式的 SSL 实现,但我确实还是想加密 Web 流量。被动窃听是真实存在的风险……但要防止它并不需要整套证书机制:因此,最好的选择就是一张抗议证书。证书中我唯一能直接控制的部分就是公钥。所以,获得一张烂证书的最简单办法,就是使用一个花哨的私钥,比如 313333333337(最 eleet 的素数之一)。不过,这样得到的公钥虽然很弱,但除非有人真的去尝试破解,否则没人会知道。
openssl s_client -connect maurycyz.com:443 /dev/null \
| sed -n /BEGIN/,/END/p | grep -zE '////.?*////' --color=yes -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgISBjst/cQvgUTu+O7siJYo8bAFMA0GCSqGSIb3DQEBCwUA MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD EwNZUjIwHhcNMjYxMTA4MjE0NzM5WhcNMjcwMjA2MjE0NzM4WjAXMRUwEwYDVQQD EwxtYXVyeWN5ei5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz lkaPgD2IZPPtC6fB////You+dont+actually+have+to+pick+random+privat e+keys//No+one+checks+these+things//A+certificate+aurthority+got +away+with+the+number+4+for+a+year////8HzhFiAzSv/zKHf7l4u6d6d3w6 nOg7N/C2ra5QvNpFnZVzrS5IcZmvRdi0dcptavcB8s4ThHNZLhY414Mvdo5t0kr0 n8WFrydnc6NEMKDPiZxehnF5D3n7z1piI5YCsNcS0NVFb45+8QvBZrv0O2BSIKNE 7M9hcE00KsaSzZ3eDBsRAgMBAAGjggIoMIICJDAOBgNVHQ8BAf8EBAMCBaAwEwYD VR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUZoonXxel KC563vN2kbvwXTLBQgMwHwYDVR0jBBgwFoAUQBUtJnntMiCe35pyHdYyH4EMgQww MwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAChhdodHRwOi8veXIyLmkubGVuY3Iu b3JnLzAnBgNVHREEIDAegg4qLm1hdXJ5Y3l6LmNvbYIMbWF1cnljeXouY29tMBMG A1UdIAQMMAowCAYGZ4EMAQIBMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly95cjIu Yy5sZW5jci5vcmcvNi5jcmwwggELBgorBgEEAdZ5AgQCBIH8BIH5APcAdgAAGl0a HC2TdbZIVXj4L3Ghrm7vOX0pfIrjFXvK3uGgHgAAAaG9Vy0ZAAAEAwBHMEUCIEof iI14E0jzfOz9woGKiiYR4pUAm/Dv9FmFWEr5ma8uAiEAyl2EMpURJ65Oe+FIFE6v Uj4QomzFJ98qVqhQozQxcC4AfQAai51rjdeR0c0FSe22A1XWBrZPrTDbcf54jw/H yPvEsQAAAaG9Vy2AAAgAAAUAFVVRHQQDAEYwRAIgTBocYGR/XcTqNx58xJh/pAme q+w6fDl+NktKUuPBqZcCIFJU6/GE71s9OkORDBC4+XHiQWWxrHk8uuD6nTQzCtHS MA0GCSqGSIb3DQEBCwUAA4IBAQAUIK5MyB3bhSFc6NOkC1UYYi2BQZN4zDfZMTD1 gGtnK7FCCNKvsanv9FIeGgr7e3A50TJhqIWH42uz9mQt8rnofwKVu7fJ77l/HZIf oAqNol06AbtwM2I4vOEAZyfD3zAfL/3G70rGw4omDFpzX852Yi3Ou40wpHbdboYY Bn58bZDvBVaUrKVdTdN+S5Ea2usWKgUjqfouz/VjnlEgLfcxqPwF2IPfPCOPKJH2 uIo3tnjx267OWY3O8nyxuOAxrBuP5fc8g2bEcKI5RewRWh7CCVZB23Ov5dyFQVcb ICN41m494GUBgwqYpAjLgdIubvyoJzBpACGuIl2QlJza1p/y -----END CERTIFICATE-----
首先,我们来看一下 RSA 的数学框架。生成密钥时,选两个大素数(p 和 q),将它们相乘得到模数(n)。再选一个小数 e 作为公开指数。RSA 公钥由模数(n)和公开指数组成:
加密需要知道 e(公开)
cyphertext = plaintext^e mod n
私钥包含模数和私有指数(d),d 被选为 e 模 n 的乘法逆元。d 具体是怎么求出来的并不重要,但这个过程需要知道 p 和 q。
解密需要知道 d(私有)
= cyphertext^d mod n = plaintext^e^d mod n = plaintext^(e*d) mod n = plaintext^1 mod n = plaintext
<!-- 这个过程也可以用于签名:只需把用私钥做的操作称为「加密」,把用公钥做的操作称为「解密」。发送一条任何人都能解密、但只有密钥持有者才能加密的消息,对于验证消息来源很有用。 -->好,回到花哨密钥。e 的标准值是 65537(0x10001),因为置位比特数少能让加密更快。事实上,我用的那家 CA 会拒绝为非标准公开指数签发的密钥,所以这方面我玩不了什么花样。模数 n 是 2,048 或 4,096 个「用户可控」比特,因此它是藏消息的理想位置。不过,要用这张证书,我需要找到两个大素数,它们的乘积正好等于那个花哨模数。我的方法是先随机选两个素数,算出得到的 n 值。然后修改 n 的字节,把消息引入 base64 编码中。当然,修改后的 n 并不是 p 和 q 的乘积,但这可以通过令 q = n/p 来修正。得到的 q 值极不可能是素数(甚至不可能是整数),所以我把它四舍五入,再找到理想 q 之后的下一个素数:通常这只需把 q 的值改动几百。由于 p 和 q 大小相近,q 的小改动只会影响乘积的最低有效半部分:
58174124 * 918491824 = 53432457262362176 (递增直到下一个素数……) 58174124 * 918491843 = 53432458367670532
只要消息嵌入在 n 的高半部分,它很可能完好无损地保留下来。原来的 p 和新选出的 q 现在可以按常规方式构造出可用的 RSA 私钥。接下来,就只是让证书颁发机构给这个密钥签名的事了:
单域名
openssl req -new -key priv.pem -subj '/C=US/CN=example.com' > cert_request certbot certonly --manual --csr cert_request
通配符
cat > config<<EOF [ req ] req_extensions = req_ext [ req_ext ] subjectAltName = @alt_names [ alt_names ] DNS.1 = *.example.com DNS.2 = example.com EOF openssl req -new -key priv.pem -config config -subj '/C=US/CN=example.com' > cert_request certbot certonly --manual --csr cert_request
……不过,由于 base64 是按三个字节一组进行操作的,消息有可能错位而变得不可读。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。