0x1. TLS 如何握手?

TLS 握手流程

图片来自 cloudflare

具体流程:

  1. Client Hello

    客户端发送 Client hello 给服务器,包含协议版本号,客户端随机数,支持的密码套件(例如TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) 等信息

  2. Server Hello

    服务器收到 Client Hello 信息后, 服务器回复 Server Hello 给客户端,包含服务器随机数,服务器选择的加密套件,服务器证书等信息

  3. 交换密钥

    a. 客户端验证服务器的证书合法后,生成预主密钥, 通过服务器公钥加密后发给服务器

    b. 服务器用私钥解密,获得预主密钥;客户端,服务器用 客户端随机码,服务器随机码,预主密钥生成会话密钥,后续通讯用该会话密钥加密;

    c. 握手结束

0x2. 证书里面有什么?

证书是 X.509 格式,主要包含公钥,颁发机构 (CA),签名,过期时间等信息,证书的常见后缀有 CRT (linux/unix),CER (windows),KEY (包含公钥,私钥),其内部采用 DER 或者 PEM 来编码;

  1. PEM

    PEM 可以用来表示证书,公钥,私钥,PEM 是一串字符串,由 “ ——xxxx—— + base64(内容) + ——xxxx—— “ 组成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    -----BEGIN CERTIFICATE-----
    MIIEqjCCApKgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAweDELMAkGA1UEBhMCR0Ix
    DjAMBgNVBAgMBUNoaW5hMQ0wCwYDVQQKDARBSVNBMScwJQYDVQQLDB5BSVNBIEx0
    ZCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxITAfBgNVBAMMGEFJU0EgTHRkIEludGVy
    bWVkaWF0ZSBDQTAeFw0xOTExMjIxMDQyNDNaFw0yMDEyMDExMDQyNDNaMGExCzAJ
    BgNVBAYTAkdCMQswCQYDVQQIDAJVUzENMAsGA1UECgwEQUlTQTEcMBoGA1UECwwT
    QUlTQSBMdGQgV2ViIFNlcnZlcjEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMFww
    DQYJKoZIhvcNAQEBBQADSwAwSAJBALwxhAYBLf4E9qR+2/JpR+3XtV7FEeBJvbqI
    og5sxcNPIWS5AYA7GTHDjtB0eYD4LpkzngCkWdCN0maAxFSr2YECAwEAAaOCARsw
    ggEXMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQm
    FiRPcGVuU1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYE
    FGQjUZqxYMW8116UcXzsmgcZxorGMH4GA1UdIwR3MHWAFAsw88HU63rhDnopu9HR
    s8MaDX87oVmkVzBVMQswCQYDVQQGEwJHQjEOMAwGA1UECAwFQ2hpbmExDTALBgNV
    BAoMBEFJU0ExJzAlBgNVBAsMHkFJU0EgTHRkIENlcnRpZmljYXRlIEF1dGhvcml0
    eYICEAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqG
    SIb3DQEBCwUAA4ICAQBkvyM+2w4cJW2G4YxEM44y1bgJ8o1SfRmami1DBSygj3gz
    7TqPteuxJAlm6/ylp5+RO8TKdszMzTRCHfZ0rOp8CbwXSaDM7LdQ+nZchtFh7371
    cCDLAW3d9g4hvZE1EnPspT1fs3pUV9npeqDA4CFSNup7PHVmhyAtTnSG1mC5Qac5
    2Q9OQ463UVVmnd7HgFAyfuokPA3Cz24fSCUQHWHja9T06KAd+V48eM+9wo3lUNJO
    FV1roSLmT4jMrC+znRsovhObjfI5HNZCR2yeiwnedPMt5c6OWEGr8vXvJ/4TW0oR
    S3knGIBw8/VsXIBT/LiQN6CPfKmnMKPycI33+g0oShdu1x9yc1kGg+Kr2r1uMRGw
    qFH6UcsD3RfGq22u8g+5jWBppZeCK78JphgqgrGQNfstcM2qeRiq7u63q2aXyj3n
    ep+ajP7hPcswnziS8TAMo61U7iiBSVcA7zwM9CJ3Rocon+p1emDBiygBMfmF9XZr
    LuLLnpWsEdxw8YfKm8V1EBHFPeFpNtQj5SpfYqwYPZ5cI8sApJ+fPlo5Ix84L9/D
    VJx1QsQyVudJ1x8VX3eUtCTrBgmwvQoH+uvpW151ys0N9HityBaAdPSW6SI/6bqM
    a1wUM0OZLmbmJndlODUgimy2bhxjNOUIfuX9gC3RN9U3D3B8aV5ZDSvUZWOrxQ==
    -----END CERTIFICATE-----
  2. DER

    Base64 解码 PEM 格式中间的内容,得到如下二进制数据,DER 是一种二进制编码格式。

    1
    30 82 04 aa 30 82 02 92 a0 03 02 01 02 02 02 10 01 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 78 31 0b 30 09 06 03 55 04 06 13 02 47 42 31 0e 30 0c 06 03 55 04 08 0c 05 43 68 69 6e 61 31 0d 30 0b 06 03 55 04 0a 0c 04 41 49 53 41 31 27 30 25 06 03 55 04 0b 0c 1e 41 49 53 41 20 4c 74 64 20 43 65 72 74 69 66 69 63 61 74 65 20 41 75 74 68 6f 72 69 74 79 31...
  3. X.509

    解码 DER 可以得到 X.509, X.509 利用 ASN.1 来描述其数据结构。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SEQUENCE {
    SEQUENCE {
    [0] {
    INTEGER 0x02 (2 decimal)
    }
    INTEGER 0x1001 (4097 decimal)
    SEQUENCE {
    OBJECTIDENTIFIER 1.2.840.113549.1.1.11 (sha256WithRSAEncryption)
    NULL
    }
    ...
    }
  4. ASN.1

    ASN.1 定义了一套描述数据的规则,ASN.1 与 DER 的关系,有点像 Unicode 和 UTF-8 的关系,ASN.1 只是一套描述规则,没有定义具体的编码方式,而 DER 是 ASN.1 最常用的编码方式;

    用 ANS.1 表示一个 Foo 协议

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    FooProtocol DEFINITIONS ::= BEGIN
    FooQuestion ::= SEQUENCE {
    trackingNumber INTEGER,
    question IA5String
    }

    FooAnswer ::= SEQUENCE {
    questionNumber INTEGER,
    answer BOOLEAN
    }

    END
  5. ASN.1, X.509, DER, PEM 关系示意图

0x3. Openssl 操作示例

  1. 生成 RSA 私钥

    1
    2
    3
    openssl genrsa -out private.pem 512

    # 注:为简单起见,使用 512 位的密钥;生产环境中请使用 2048 位密钥

    private.pem 是 PEM 格式,内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    -----BEGIN RSA PRIVATE KEY-----
    MIIBOwIBAAJBAKyymwzYcqw5MSHZFC2CoqctACyFdx4VuCo+mKiCgOW4JvMtcfhp
    XCrU5QeHaBvbsVP0Yvf/EyUTqM3XCwaM+eUCAwEAAQJAa+h2BYLBtGdQEexINV+p
    Lnhp4WfL1FqR5qOSU8inreFqeD+pOd/ZgdE+SmQfwIQwigiWIURlWgdxNxiXK8fy
    SQIhANW7ipg1Bqpq/XBRtXmMAlDL/gbzW1JO9hNcBiKgakWzAiEAztmf9zkriOQ4
    h2eSxy+QQKwDnJW1lCkLGLLCE9hBpgcCIQCes8YCpQURD6amexWMbkjd48r5MER0
    Bouz7lXj6kde/wIhAMT6NrwNpCh69F31QrAN2jfL1rChXEXYA+okKG8PbAy3AiB8
    hWCs2Qi+IB4uK1ZnQjE0KCmY5/DD4CCqZktkdBFZkw==
    -----END RSA PRIVATE KEY-----
  2. 提取公钥

    1
    openssl rsa -in private.pem -pubout -out pubkey.pem

    pubkey.pem 内容如下:

    1
    2
    3
    4
    -----BEGIN PUBLIC KEY-----
    MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKyymwzYcqw5MSHZFC2CoqctACyFdx4V
    uCo+mKiCgOW4JvMtcfhpXCrU5QeHaBvbsVP0Yvf/EyUTqM3XCwaM+eUCAwEAAQ==
    -----END PUBLIC KEY-----
  3. 提取 (n, e)

    1
    openssl rsa -inform PEM -text -noout -pubin < pubkey.pem
  4. 格式转换

    PEM -> DER

    1
    2
    3
    4
    5
    openssl rsa -in private.pem -outform DER -out private.der

    # 查看 DER
    xxd -l 16 -p private.der
    > 3082013b020100024100acb29b0cd872

    DER -> PEM

    1
    openssl rsa -in private.der -inform DER -out private1.pem
  5. 提取 ASN.1

    1
    2
    3
    4
    5
    6
    7
    8
    openssl asn1parse -in public.key

    ->
    0:d=0 hl=2 l= 92 cons: SEQUENCE
    2:d=1 hl=2 l= 13 cons: SEQUENCE
    4:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
    15:d=2 hl=2 l= 0 prim: NULL
    17:d=1 hl=2 l= 75 prim: BIT STRING

    提取 n (prim: INTEGER)

    1
    2
    3
    4
    5
    openssl asn1parse -strparse 17 -in pubkey.pem
    ->
    0:d=0 hl=2 l= 72 cons: SEQUENCE
    2:d=1 hl=2 l= 65 prim: INTEGER :ACB29B0CD872AC393121D9142D82A2A72D002C85771E15B82A3E98A88280E5B826F32D71F8695C2AD4E50787681BDBB153F462F7FF132513A8CDD70B068CF9E5
    69:d=1 hl=2 l= 3 prim: INTEGER :010001

参考