【问题标题】:Swift/URLSession returns a different public key than OpenSSLSwift/URLSession 返回与 OpenSSL 不同的公钥
【发布时间】:2020-09-30 15:36:00
【问题描述】:

我有这段代码(可以在操场上运行):

import UIKit
import CryptoKit

let url: URL = URL(string: "https://apple.com")!

final class SSLExtractor: NSObject, URLSessionDelegate {
    private var session: URLSession!

    init(url: URL) {
        super.init()
        let session = URLSession.init(configuration: .default, delegate: self, delegateQueue: nil)
        session.dataTask(with: url).resume()
    }

    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
              let serverTrust = challenge.protectionSpace.serverTrust,
              let publicKey = SecTrustCopyKey(serverTrust),
              let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil)
        else { return }
        let publicKeyHash = SHA256.hash(data: publicKeyData as Data)
        print("publicKey: \(publicKey)")
        print("publicKey: \(publicKeyData)")
        print("publicKey: \((publicKeyData as Data).base64EncodedString() )")
        print(publicKeyHash)
    }
}

let extractor = SSLExtractor(url: url)

据说最后的打印应该给我服务器的公钥:

SHA256 摘要:b0faa00170de7c1ac7994644efadb59f149656546394bd22c95527e78f1984b6

但是,当我使用 OpenSSL 时:

$ openssl s_client -connect apple.com:443 | openssl x509 -pubkey -noout  | openssl rsa -pubin -outform der| openssl dgst -sha256

我得到一个不同的哈希:

1786e93d8e16512ea34ea1475e39597e77d7e39239ba1a97dcd71f97e64d6619

如何得到正确的哈希?

编辑:也尝试过

              let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0),
              let certifKey = SecCertificateCopyKey(certificate),
              let certifPubKey = SecKeyCopyPublicKey(certifKey),
              let certifPubKeyData = SecKeyCopyExternalRepresentation(certifPubKey, nil)

但我得到了同样的结果

【问题讨论】:

  • 我没有从 OpenSSL 获得相同的哈希值;你能展示你使用 OpenSSL 获得的 cert 吗? (在 PEM 中,因此不会丢失任何信息。)是的,openssl x509 -pubkey 在 PEM 中输出 SPKI;要转换为 OpenSSL 调用 DER 的二进制文件,请通过 openssl rsa -pubin -outform der 进行管道传输(然后从该管道传输到哈希)。或者,丢弃 BEGIN 和 END 行并对其余行进行 base64 解码。
  • @dave_thompson_085 这是openssl s_client -connect apple.com:443的过去bin:pastebin.com/ic3u7gPi
  • @dave_thompson_085 我更新了我的答案以正确散列公钥而不是 pem。然而,哈希仍然不正确。
  • It is the same cert, but I realized I did my test on Windows: that cert's SPKI in PEM with CRLF hashes to 93eacd62ace2ea5e7286b43ea12e3376583532f2794a77ec335ac3e0c46e3fc7 as I had, with LF to 58053494eb340ddc7d23608a5b4608d792f6777caa8782582ce246574980e230 as你以前有过,和现在一样 DER 1786e93d8e16512ea34ea1475e39597e77d7e39239ba1a97dcd71f97e64d6619。我不知道 Swift 以及它在此处的情况下做什么(或应该做什么),但我会查看“外部”publicKeyData 或 certifPubKeyData 以了解实际情况。
  • @dave_thompson_085 非常感谢您的帮助。事实证明,derpem 格式都包含一些标题。 Swift 返回正确的值,没有标题。我不确定是否有一种 OpenSSL 方法可以删除 der 标头,但如果我这样做了,我会得到相同的哈希值。

标签: swift openssl nsurlsession


【解决方案1】:

只是一个答案,但对于 cmets 来说太多了。您发现 Swift 提供(和散列)的“外部”公钥是 OpenSSL 使用的后缀。

正如我所提到的,OpenSSL 使用由X.509/PKIX=RFC5280 section 4 定义的“SPKI”(SubjectPublicKeyInfo)结构,它是一个 DER 编码的 ASN.1 序列,包含一个算法标识符和一个包含嵌入算法特定数据的位串。 RFC 7468 section 13(部分官方化了 OpenSSL,尽管它没有这么说)确认这是“标准”公钥表示的内容,RFC 3279 section 2.3.1 定义了 for RSA(Apple证书的密钥是)BIT STRING 部分的内容是 ASN.1 结构 RSAPublicKey,它实际上是在 PKCS1 currently RFC8017 section A.1.1 中定义的(虽然 3279 没有对密钥这么说,但它对于 2.2.1 中的签名确实如此) (但与早期版本没有变化)。

由于 DER 编码的工作方式,BIT STRING 的内容——在本例中为 ASN.1 结构 RSAPublicKey——恰好是整个 SPKI 编码的后缀。

如果我们查看并解析,SPKI OpenSSL 会从证书中获取(使用 x509 -pubkey

$ openssl rsa -pubin -in applespki -outform der |od -Ax -tx1
writing RSA key
000000 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01
000010 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01
000020 00 e0 e5 ca aa 34 ea 32 d1 f5 e3 56 e5 05 e8 07
000030 c3 d3 3b 86 93 60 94 37 20 9f 8d d0 17 8f ba da
000040 16 f1 b2 6a bc 41 7a 6f dc 22 87 4b 05 e8 57 48
000050 56 3c da a2 02 e5 57 73 94 95 18 dd 7c c9 b0 68
000060 fe 17 2c 8b 6f fa 42 a9 b1 a8 77 88 22 d4 41 08
000070 08 d9 80 59 92 bc e9 3a 0a 17 e0 2b 13 fe bf ec
000080 69 7d 61 15 14 21 71 73 a0 70 fd 6d a0 0f 46 13
000090 60 8d c1 bd 8c 66 60 04 05 e0 44 f0 a1 53 b7 00
0000a0 7f a3 f3 55 da d2 6c c6 dd 7f 83 79 1f 6e cb 1d
0000b0 78 3e d9 9f fa 58 34 38 41 c5 70 c1 c7 dd ea b0
0000c0 81 c0 d4 a3 18 a4 da 02 15 b8 cb 48 10 fa 42 86
0000d0 75 1c 55 51 6b 48 6e 37 43 98 09 af 4f 52 c0 c8
0000e0 75 40 a5 e7 65 ba 62 2a be 6c 2a 6d 72 5b 82 21
0000f0 d1 75 97 ea 7e 21 a1 04 f4 76 7c 85 db 50 c7 9f
000100 b5 d8 f7 80 15 ba a5 83 9e 2c da f0 73 c6 14 9a
000110 fd 35 07 41 4b 53 21 8d 0d 01 f1 05 b3 04 05 83
000120 cb 02 03 01 00 01
000126
$ openssl asn1parse -i -dump -in applespki1
    0:d=0  hl=4 l= 290 cons: SEQUENCE
    4:d=1  hl=2 l=  13 cons:  SEQUENCE
    6:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
   17:d=2  hl=2 l=   0 prim:   NULL
   19:d=1  hl=4 l= 271 prim:  BIT STRING
      0000 - 00 30 82 01 0a 02 82 01-01 00 e0 e5 ca aa 34 ea   .0............4.
      0010 - 32 d1 f5 e3 56 e5 05 e8-07 c3 d3 3b 86 93 60 94   2...V......;..`.
      0020 - 37 20 9f 8d d0 17 8f ba-da 16 f1 b2 6a bc 41 7a   7 ..........j.Az
      0030 - 6f dc 22 87 4b 05 e8 57-48 56 3c da a2 02 e5 57   o.".K..WHV<....W
      0040 - 73 94 95 18 dd 7c c9 b0-68 fe 17 2c 8b 6f fa 42   s....|..h..,.o.B
      0050 - a9 b1 a8 77 88 22 d4 41-08 08 d9 80 59 92 bc e9   ...w.".A....Y...
      0060 - 3a 0a 17 e0 2b 13 fe bf-ec 69 7d 61 15 14 21 71   :...+....i}a..!q
      0070 - 73 a0 70 fd 6d a0 0f 46-13 60 8d c1 bd 8c 66 60   s.p.m..F.`....f`
      0080 - 04 05 e0 44 f0 a1 53 b7-00 7f a3 f3 55 da d2 6c   ...D..S.....U..l
      0090 - c6 dd 7f 83 79 1f 6e cb-1d 78 3e d9 9f fa 58 34   ....y.n..x>...X4
      00a0 - 38 41 c5 70 c1 c7 dd ea-b0 81 c0 d4 a3 18 a4 da   8A.p............
      00b0 - 02 15 b8 cb 48 10 fa 42-86 75 1c 55 51 6b 48 6e   ....H..B.u.UQkHn
      00c0 - 37 43 98 09 af 4f 52 c0-c8 75 40 a5 e7 65 ba 62   7C...OR..u@..e.b
      00d0 - 2a be 6c 2a 6d 72 5b 82-21 d1 75 97 ea 7e 21 a1   *.l*mr[.!.u..~!.
      00e0 - 04 f4 76 7c 85 db 50 c7-9f b5 d8 f7 80 15 ba a5   ..v|..P.........
      00f0 - 83 9e 2c da f0 73 c6 14-9a fd 35 07 41 4b 53 21   ..,..s....5.AKS!
      0100 - 8d 0d 01 f1 05 b3 04 05-83 cb 02 03 01 00 01      ...............

我们可以看到BIT STRING的内容,由于DER对BIT STRING的工作方式,跳过了第一个字节00,因此从偏移量24=0x18开始一直到最后,本身就是RSAPublicKey的DER编码( 30 82 01 0a 是序列,02 82 01 01 ... 是整数(有符号)模数,02 03 01 00 01 是整数(有符号)公共指数)。 OpenSSL 1.0.0 up(现在无处不在,虽然我记得当时还没有)可以提取这个,并得到你预期的哈希:

$ openssl rsa -pubin -in applespki -RSAPublicKey_out -outform der |od -Ax -tx1
writing RSA key
000000 30 82 01 0a 02 82 01 01 00 e0 e5 ca aa 34 ea 32
000010 d1 f5 e3 56 e5 05 e8 07 c3 d3 3b 86 93 60 94 37
000020 20 9f 8d d0 17 8f ba da 16 f1 b2 6a bc 41 7a 6f
000030 dc 22 87 4b 05 e8 57 48 56 3c da a2 02 e5 57 73
000040 94 95 18 dd 7c c9 b0 68 fe 17 2c 8b 6f fa 42 a9
000050 b1 a8 77 88 22 d4 41 08 08 d9 80 59 92 bc e9 3a
000060 0a 17 e0 2b 13 fe bf ec 69 7d 61 15 14 21 71 73
000070 a0 70 fd 6d a0 0f 46 13 60 8d c1 bd 8c 66 60 04
000080 05 e0 44 f0 a1 53 b7 00 7f a3 f3 55 da d2 6c c6
000090 dd 7f 83 79 1f 6e cb 1d 78 3e d9 9f fa 58 34 38
0000a0 41 c5 70 c1 c7 dd ea b0 81 c0 d4 a3 18 a4 da 02
0000b0 15 b8 cb 48 10 fa 42 86 75 1c 55 51 6b 48 6e 37
0000c0 43 98 09 af 4f 52 c0 c8 75 40 a5 e7 65 ba 62 2a
0000d0 be 6c 2a 6d 72 5b 82 21 d1 75 97 ea 7e 21 a1 04
0000e0 f4 76 7c 85 db 50 c7 9f b5 d8 f7 80 15 ba a5 83
0000f0 9e 2c da f0 73 c6 14 9a fd 35 07 41 4b 53 21 8d
000100 0d 01 f1 05 b3 04 05 83 cb 02 03 01 00 01
00010e
$ openssl rsa -pubin -in applespki -RSAPublicKey_out -outform der |openssl sha256
writing RSA key
(stdin)= b0faa00170de7c1ac7994644efadb59f149656546394bd22c95527e78f1984b6

这仅适用于 RSA。看看您的 Swift 代码如何处理经过认证的非 RSA 密钥可能会很有趣,尽管目前在公共网络上很难找到这些密钥;我目前知道的唯一稳定的是在'badssl',比如https://ecc256.badssl.com

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 1970-01-01
    • 2014-01-23
    • 2018-04-02
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    相关资源
    最近更新 更多