14

我很难使用 EXPORT 级密码运行 M2Crypto SSLServer。

LOW/MEDIUM/HIGH 等级密码可以正常工作,但 EXPORT 不会。此外,当 OpenSSL 从命令行以服务器模式运行时,它可以毫无问题地接受 EXPORT 级密码。

所以,要么我遗漏了什么,要么 M2Crypto 模块有问题。任何帮助表示赞赏。

使用的 Python 代码 ( ssl-server.py) 如下所示:

import M2Crypto
import socket

CERTFILE = "dummy_cert.pem"
KEYFILE = "dummy_key.pem"
PROTOCOL = "sslv3"
HOST = "0.0.0.0"
PORT = 4433

def main():
    print "[i] Initializing context ..."
    ctx = M2Crypto.SSL.Context(protocol=PROTOCOL, weak_crypto=True)
    ctx.load_cert_chain(certchainfile=CERTFILE, keyfile=KEYFILE)
    ctx.set_options(M2Crypto.m2.SSL_OP_ALL)
    ctx.set_cipher_list("ALL")

    print "[i] Initializing socket ..."
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((HOST, PORT))
    sock.listen(1)
    conn, addr = sock.accept()

    print "[i] SSL handshake ..."
    ssl_conn = M2Crypto.SSL.Connection(ctx=ctx, sock=conn)
    ssl_conn.setup_ssl()
    try:
        ssl_conn_res = ssl_conn.accept_ssl()
    except Exception, ex:
        print "[x] SSL connection failed: '%s'" % str(ex)
    else:
        if ssl_conn_res == 1:
            print "[i] SSL connection accepted"
        else:
            print "[x] SSL handshake failed: '%s'" % ssl_conn.ssl_get_error(ssl_conn_res)

if __name__ == "__main__":
    main()

症状是:

$ uname -a
Linux XYZ 2.6.38-15-generic #59-Ubuntu SMP Fri Apr 27 16:03:32 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=11.04
DISTRIB_CODENAME=natty
DISTRIB_DESCRIPTION="Ubuntu 11.04"

$ python -c "import M2Crypto;print M2Crypto.version_info"
(0, 20, 1)

$ openssl version
OpenSSL 0.9.8o 01 Jun 2010

1) NOT OK
SERVER (terminal 1): $ python ssl-server.py
CLIENT (terminal 2): $ openssl s_client -connect localhost:4433 -cipher EXPORT
CONNECTED(00000003)
28131:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:602:

2) OK
SERVER (terminal 1): $ openssl s_server -cert dummy_cert.pem -key dummy_key.pem -ssl3 -no_tls1 -no_ssl2 -cipher EXPORT
CLIENT (terminal 2): $ openssl s_client -connect localhost:4433 -cipher EXPORT
CONNECTED(00000003)
depth=0 C = BE, CN = www.example.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = BE, CN = www.example.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 C = BE, CN = www.example.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/C=BE/CN=www.example.com
   i:/C=BE/CN=test-ca
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=/C=BE/CN=www.example.com
issuer=/C=BE/CN=test-ca
---
No client certificate CA names sent
---
SSL handshake has read 1141 bytes and written 242 bytes
---
New, TLSv1/SSLv3, Cipher is EXP-EDH-RSA-DES-CBC-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: zlib compression
Expansion: zlib compression
SSL-Session:
    Protocol  : SSLv3
    Cipher    : EXP-EDH-RSA-DES-CBC-SHA
    Session-ID: B052D5D5A436F9A0B9D3FB24F2E32A8A06A0B6828230621C4CFAEB82A0A9AE0C
    Session-ID-ctx: 
    Master-Key:     47F6E3720D06518B961FE389F13BCDE42C37F703099ABBB9B3DA35383C420F519D4F4773D35E470CF6FF7BB243B29069
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Compression: 1 (zlib compression)
    Start Time: 1340644713
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---

a的内容dummy_cert.pem如下:

-----BEGIN CERTIFICATE-----
MIICkTCCAfqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJCRTEQ
MA4GA1UEAxMHdGVzdC1jYTAeFw0xMjA1MDYwODQyNDlaFw0yMjA1MDMwODQyNDla
MCcxCzAJBgNVBAYTAkJFMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wgZ8wDQYJ
KoZIhvcNAQEBBQADgY0AMIGJAoGBAL7OBv9wRwtNjN984XSy22/rw6tHM6Lq/Ccf
NoHKbqwC+PsxgmgJJiGBGewrzBR42toqHJi7EjHhuvrgqV9s2duPQBAANh7tzY1h
6VekrwhIIt4o1h0F2KB16VXA8s918d+8pRGt2T11GUh/QT3m9yY1VzqdIBeAfklC
ET6ncPK/AgMBAAGjgdQwgdEwCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBkAw
KwYJYIZIAYb4QgENBB4WHFRpbnlDQSBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYD
VR0OBBYEFNGQArEZPKprJTn7A64qEFfl0m4xME8GA1UdIwRIMEaAFFuITOUJlGrJ
9lKufs8cm1MpwXrroSOkITAfMQswCQYDVQQGEwJCRTEQMA4GA1UEAxMHdGVzdC1j
YYIJALimgW7YUgdrMAkGA1UdEgQCMAAwCQYDVR0RBAIwADANBgkqhkiG9w0BAQUF
AAOBgQDWh8A0eBxI9XHy68xdjFsk2oerJeV6qqlcmtPZgz3GlarRcWcKsRJOyLLL
dCOe7tY5isWQAoLt6XALzDWjbQkTJnxBaKHif1MIikuajaYKT7LA1MvFn50Qrm6n
f9hG7gvdTpm1rlPcs0qibp1vJVubkU51mT6JT4UnLfeVIjtL7Q==
-----END CERTIFICATE-----

a的内容dummy_key.pem如下:

-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQC+zgb/cEcLTYzffOF0sttv68OrRzOi6vwnHzaBym6sAvj7MYJo
CSYhgRnsK8wUeNraKhyYuxIx4br64KlfbNnbj0AQADYe7c2NYelXpK8ISCLeKNYd
BdigdelVwPLPdfHfvKURrdk9dRlIf0E95vcmNVc6nSAXgH5JQhE+p3DyvwIDAQAB
AoGBAIZldIRkP4Z0n2+j9OJQQUS6Wl7AjlyJDAc6cxhE0GOUzG+S1foVx6f92ZaC
2wLoha75zp691fkQuLWRnXu7nk9QwxQdOppKijIPHdL2cYtUc9UCedN5rExjpcOP
4Hjwf17YOxK2J0zzmG1djTBB47BKGUedSQ7E1QxGcrESS2XxAkEA+6ey2jy8etWi
QmCdJJIxXwKRVHCmt5LVwj+IOk/u3sr1AGfBm7spKGU3boCiFt4FmjGMax7B9r/e
zPaMb34guwJBAMIZX7Vv5gfjvWtgp6pyE/UkjRSOKBpuy9gyiqtLBJwehj/qsBqr
O6tFmjMFiudVusnVSrEFGAPLV52xf0U4580CQQDkEQ1UH2spX2dYBLslo6A+3NLc
1eMhx18WVgGd50cyfnkfzuh1vF8GjwR3jvhXBQvKvFDn284pU6YV1vNbL9F1AkEA
o2CwSwyRV3q+6i9Fchbr7aCCkBbIctdoBeclCeHvU2nuHsbwzMHtS9EeZmv365kh
zNoYMMDU4fy7FyVct2ua0QJASXtIwYKZ2CAP+lAQqfh+knRRqtqdLt4Lt0mpML5m
UtsECS8frKeF3mynXfsyRkvC8F2WFiJVJ3+D+y3zYNGlZg==
-----END RSA PRIVATE KEY-----

更新:在低级别握手数据​​包似乎是相同的,除了该random[32]字段使这更加奇怪。

ssldump -a -A -H -i lo可以在这里找到这两种情况的SSL 转储 ( ):

http://pastebin.com/YuC7d8zg(不正常的情况)

http://pastebin.com/U6YGQmv9(OK案例)

4

1 回答 1

5

我需要对 python 脚本进行以下两个调整,以使其与导出密码套件一起使用:

PROTOCOL = "sslv23"
...
    print "[i] Initializing context ..."
    ctx = M2Crypto.SSL.Context(protocol=PROTOCOL, weak_crypto=True)
    ctx.load_cert_chain(certchainfile=CERTFILE, keyfile=KEYFILE)
    ctx.set_options(M2Crypto.m2.SSL_OP_ALL)
    ctx.set_tmp_rsa(M2Crypto.RSA.gen_key(512, 65537))
    ctx.set_cipher_list("ALL")

那是:

  1. 使用 SSLv23 作为协议标识符(SSLv2/v3 兼容模式)。不知道为什么在这种情况下需要它,但它似乎不起作用。
  2. 使用 . 在上下文上设置一个临时的、短暂的 RSA 密钥set_tmp_rsa()。这是必需的,因为对于导出密码,提供的(1024 位)RSA 密钥仅用于身份验证(签名),而临时的、出口受损的 512 位 RSA 密钥用于保密(加密)。OpenSSL 要求您在上下文中设置此密钥(请参阅SSL_set_tmp_rsa() 的文档)。

奇怪的是,它还可以在仅 SSLv2 模式下工作(在测试时使用-ssl2on openssl s_client),而无需设置临时 RSA 密钥(在脚本中调用set_tmp_rsa注释掉)。我不知道为什么。

通常,一些密码套件需要将特殊密钥添加到上下文中,例如使用 DH(组参数)或 ECDH(曲线)的套件。要准确了解每个密码套件的用途,openssl ciphers -v可能会很有见地,例如:

% openssl ciphers -v EXPORT
EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=RSA  Enc=DES(40)   Mac=SHA1 export
EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=DSS  Enc=DES(40)   Mac=SHA1 export
EXP-ADH-DES-CBC-SHA     SSLv3 Kx=DH(512)  Au=None Enc=DES(40)   Mac=SHA1 export
EXP-DES-CBC-SHA         SSLv3 Kx=RSA(512) Au=RSA  Enc=DES(40)   Mac=SHA1 export
EXP-RC2-CBC-MD5         SSLv3 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
EXP-RC2-CBC-MD5         SSLv2 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
EXP-ADH-RC4-MD5         SSLv3 Kx=DH(512)  Au=None Enc=RC4(40)   Mac=MD5  export
EXP-RC4-MD5             SSLv3 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export
EXP-RC4-MD5             SSLv2 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export

针对有关 DSS 密码套件的问题进行编辑:

DSS/DSA 密码套件需要 DH 参数,当然还有基于 DSS/DSA 的服务器证书,而不是(仅)一个 RSA 证书。这不仅适用于导出密码套件,而且适用于所有使用 DSS/DSA 验证真实性的套件。DSS/DSA 在设计上只能用于签名,不能用于加密,以允许出口到不受信任的国家。因为 DSS/DSA 只能用于签名,所以它需要一个短暂的 Diffie-Hellman 密钥交换来建立一个共享会话密钥。这就是密码套件中的 EDH 所代表的含义。要设置 DH 参数,您将使用 OpenSSL SSL_set_tmp_dh() API 的 M2Crypto 等效项。

请注意,OpenSSL 允许将 RSA 和 DSA/DSS 证书/密钥对加载到相同的 SSL 上下文中。

于 2012-06-26T11:27:28.703 回答