英文:
How to get the currently used cipher suite of a website?
问题
你想要一个获取目标主机(例如:stackoverflow.com)当前使用的密码套件的程序。通常,你可以使用openssl命令来实现:openssl s_client -connect stackoverflow.com:443
。
输出结果如下:
CONNECTED(00000005)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = *.stackexchange.com
verify return:1
---
Certificate chain
0 s:CN = *.stackexchange.com
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
subject=CN = *.stackexchange.com
issuer=C = US, O = Let's Encrypt, CN = R3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 5138 bytes and written 360 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: 27AFEC2CF0888EFFABF09081F331BA6B64FC5CD59FF8BD4A396CC0228E459EA6
Session-ID-ctx:
Master-Key: 23F30C3F4FA581F3D1ACDC4B001859B8908469C03FEB4C26A9B34876DC13576A15B26260C7B00FB108DBF91CA16AC55E
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 7200 (seconds)
TLS session ticket:
0000 - 06 ba da fe 3e 7f 04 6c-61 ee 97 f5 07 6a 9a 21 ....>..la....j.!
0010 - e5 90 2c 8e c5 20 a2 fa-8c 2e 49 57 5e 55 4c f8 ..,.. ....IW^UL.
0020 - b8 ac fa 34 8e 98 d0 76-90 76 cf b2 74 82 37 f0 ...4...v.v..t.7.
0030 - b4 c2 1a d3 0e b6 f2 b3-4b 93 ec 2e ed 58 4d c8 ........K....XM.
0040 - cd c9 63 ad 46 3e c9 77-1a 9f 5d c9 41 61 1b 56 ..c.F>.w..].Aa.V
0050 - f4 d2 d0 f4 15 5e ad f6-e8 dd 00 11 74 4c 89 d8 .....^......tL..
0060 - b2 7b 0c e5 d6 17 e4 9f-41 5e 2c 02 cd c5 74 20 .{......A^,...t
0070 - 82 ea 5f dc 52 bc 0a c7-69 13 50 a3 78 cd 0c 94 .._.R...i.P.x...
0080 - 0c aa ad 33 b6 b0 26 63-20 6b ae 2e 1c 75 ef 79 ...3..&c k...u.y
0090 - fc ee 54 a4 4f 86 d2 a8-72 83 c3 d2 1e 78 5d 8b ..T.O...r....x].
00a0 - 3e b1 e2 b8 bb 5d b5 b3-01 3b 3d 27 5d ba 40 1c >....]...;='].@.
00b0 - bd 11 2e 92 96 c5 ab 48-10 ac 47 e7 b0 db 79 d0 .......H..G...y.
Start Time: 1646821102
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes
---
而ECDHE-RSA-AES128-GCM-SHA256正是我想要的结果。我想编写一个使用Go语言的程序,能够给出与openssl s_client -connect stackoverflow.com:443
命令相同的输出结果。
以下是我的Go程序,但输出的密码套件似乎与openssl s_client -connect stackoverflow.com:443
命令的结果不同。
package main
import (
"crypto/tls"
"fmt"
"net"
"os"
)
var (
targetHost, tlsVersion string
TLS12Ciphers = []uint16{
tls.TLS_RSA_WITH_RC4_128_SHA,
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
TLS13Ciphers = []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
}
)
func showError(message string) {
fmt.Println(message)
os.Exit(0)
}
func supportedCiphers(targetHost string) []uint16 {
var ciphersLists, supportedCiphers []uint16
var tlsMinVer, tlsMaxVer int
if tlsVersion == "1.2" {
ciphersLists = TLS12Ciphers
tlsMinVer = tls.VersionTLS10
tlsMaxVer = tls.VersionTLS12
} else if tlsVersion == "1.3" {
ciphersLists = TLS13Ciphers
tlsMinVer = tls.VersionTLS13
tlsMaxVer = tls.VersionTLS13
} else {
showError("Invalid TLS version!")
}
for _, cipherSuite := range ciphersLists {
tlsConfigs := &tls.Config{
ServerName: targetHost,
CipherSuites: []uint16{cipherSuite},
MinVersion: uint16(tlsMinVer),
MaxVersion: uint16(tlsMaxVer),
}
conn, err := net.Dial("tcp", targetHost+":443")
if err != nil {
showError("Error when connecting to target server!")
}
tlsClient := tls.Client(conn, tlsConfigs)
tlsClient.Handshake()
tlsClient.Close()
if tlsClient.ConnectionState().CipherSuite == cipherSuite {
supportedCiphers = append(supportedCiphers, cipherSuite)
}
}
return supportedCiphers
}
func main() {
targetHost = os.Args[1]
tlsVersion = os.Args[2]
fmt.Println("Supported TLS " + tlsVersion + " ciphers")
for _, cipherSuite := range supportedCiphers(targetHost) {
fmt.Printf(tls.CipherSuiteName(cipherSuite) + "\n")
}
}
请问如何编写一个Go程序,能够获取目标网站当前使用的密码套件,并给出与openssl s_client -connect stackoverflow.com:443
命令相同的输出结果?
英文:
I want to get a cipher suite that currently used of any target host such as: stackoverflow.com. Normally, I would use an openssl command for this: openssl s_client -connect stackoverflow.com:443
Output:
CONNECTED(00000005)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = *.stackexchange.com
verify return:1
---
Certificate chain
0 s:CN = *.stackexchange.com
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
subject=CN = *.stackexchange.com
issuer=C = US, O = Let's Encrypt, CN = R3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 5138 bytes and written 360 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: 27AFEC2CF0888EFFABF09081F331BA6B64FC5CD59FF8BD4A396CC0228E459EA6
Session-ID-ctx:
Master-Key: 23F30C3F4FA581F3D1ACDC4B001859B8908469C03FEB4C26A9B34876DC13576A15B26260C7B00FB108DBF91CA16AC55E
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 7200 (seconds)
TLS session ticket:
0000 - 06 ba da fe 3e 7f 04 6c-61 ee 97 f5 07 6a 9a 21 ....>..la....j.!
0010 - e5 90 2c 8e c5 20 a2 fa-8c 2e 49 57 5e 55 4c f8 ..,.. ....IW^UL.
0020 - b8 ac fa 34 8e 98 d0 76-90 76 cf b2 74 82 37 f0 ...4...v.v..t.7.
0030 - b4 c2 1a d3 0e b6 f2 b3-4b 93 ec 2e ed 58 4d c8 ........K....XM.
0040 - cd c9 63 ad 46 3e c9 77-1a 9f 5d c9 41 61 1b 56 ..c.F>.w..].Aa.V
0050 - f4 d2 d0 f4 15 5e ad f6-e8 dd 00 11 74 4c 89 d8 .....^......tL..
0060 - b2 7b 0c e5 d6 17 e4 9f-41 5e 2c 02 cd c5 74 20 .{......A^,...t
0070 - 82 ea 5f dc 52 bc 0a c7-69 13 50 a3 78 cd 0c 94 .._.R...i.P.x...
0080 - 0c aa ad 33 b6 b0 26 63-20 6b ae 2e 1c 75 ef 79 ...3..&c k...u.y
0090 - fc ee 54 a4 4f 86 d2 a8-72 83 c3 d2 1e 78 5d 8b ..T.O...r....x].
00a0 - 3e b1 e2 b8 bb 5d b5 b3-01 3b 3d 27 5d ba 40 1c >....]...;='].@.
00b0 - bd 11 2e 92 96 c5 ab 48-10 ac 47 e7 b0 db 79 d0 .......H..G...y.
Start Time: 1646821102
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes
---
And ECDHE-RSA-AES128-GCM-SHA256 is exactly the result I wanted. And I want to make a program that give the same output written in Go:
Input: the target host string
Output: the currently used cipher suite of that host
This is my Go program, but the output cipher suite doesn't seem to be the same as the openssl s_client -connect stackoverflow.com:443
command.
package main
import (
"crypto/tls"
"fmt"
"net"
"os"
)
var (
targetHost, tlsVersion string
TLS12Ciphers = []uint16{
tls.TLS_RSA_WITH_RC4_128_SHA,
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
TLS13Ciphers = []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
}
)
func showError(message string) {
fmt.Println(message)
os.Exit(0)
}
func supportedCiphers(targetHost string) []uint16 {
var ciphersLists, supportedCiphers []uint16
var tlsMinVer, tlsMaxVer int
if tlsVersion == "1.2" {
ciphersLists = TLS12Ciphers
tlsMinVer = tls.VersionTLS10
tlsMaxVer = tls.VersionTLS12
} else if tlsVersion == "1.3" {
ciphersLists = TLS13Ciphers
tlsMinVer = tls.VersionTLS13
tlsMaxVer = tls.VersionTLS13
} else {
showError("Invalid TLS version!")
}
for _, cipherSuite := range ciphersLists {
tlsConfigs := &tls.Config{
ServerName: targetHost,
CipherSuites: []uint16{cipherSuite},
MinVersion: uint16(tlsMinVer),
MaxVersion: uint16(tlsMaxVer),
}
conn, err := net.Dial("tcp", targetHost+":443")
if err != nil {
showError("Error when connecting to target server!")
}
tlsClient := tls.Client(conn, tlsConfigs)
tlsClient.Handshake()
tlsClient.Close()
if tlsClient.ConnectionState().CipherSuite == cipherSuite {
supportedCiphers = append(supportedCiphers, cipherSuite)
}
}
return supportedCiphers
}
func main() {
targetHost = os.Args[1]
tlsVersion = os.Args[2]
fmt.Println("Supported TLS " + tlsVersion + " ciphers")
for _, cipherSuite := range supportedCiphers(targetHost) {
fmt.Printf(tls.CipherSuiteName(cipherSuite) + "\n")
}
}
How can I make a Go program that get the currently used cipher suite of a target website and give the same output as the openssl s_client -connect stackoverflow.com:443
command?
答案1
得分: 1
目标网站的当前使用的密码套件是不明确的。没有"当前使用的密码套件":使用的密码是根据客户端和服务器根据它们宣布的偏好进行协商的。Go客户端有不同的偏好,因此会协商出不同的密码。请注意,OpenSSL也是如此:如果更改了OpenSSL的偏好设置,那么OpenSSL也会协商出不同的密码。
如果你想让你的Go代码"产生与openssl命令相同的输出",你需要调整Go的偏好设置、OpenSSL的偏好设置或两者兼而有之。例如,在你的Go代码中使用相同的密码(不宣布可用的ECDHE-RSA-AES128-GCM-SHA256)。
英文:
> the currently used cipher suite of a target website
is ill defined. There is no "currently used cipher suite": Which cipher is used is negotiated between the client and the server based on their announced preferences. The Go client has different preferences and thus negotiates a different cipher. Note that the same is true for OpenSSL: Ich you change your OpenSSL preferences then openssl will negotiate a different cipher too.
If you want to make your Go code "give the same output as the openssl [...] command" you will have to tweak the Go preferences, the OpenSSL preferences or both. E.g. by using the same ciphers in your Go code (which doesn't announce ECDHE-RSA-AES128-GCM-SHA256 as available).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论