最後更新: 2020-02-10
證書 - OpenSSL Class
#!/bin/usr/env python import ssl import M2Crypto import OpenSSL # Get SSL # The call will attempt to validate the server certificate against that set of root certificates, # and will fail if the validation attempt fails. cert = ssl.get_server_certificate(('www.google.com', 443)) # M2Crypto x509 = M2Crypto.X509.load_cert_string(cert) print x509.get_subject().as_text() # Output # 'C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com' # OpenSSL x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) print x509.get_subject().get_components() # Output #[('C', 'US'), # ('ST', 'California'), # ('L', 'Mountain View'), # ('O', 'Google Inc'), # ('CN', 'www.google.com')]
P.S.
以上 Example 有機會出現以下 Error, 原因係 TLS 用戶端不支援 SNI
OU=No SNI provided; please fix your client., CN=invalid2.invalid
設定 SNI
獲得證書
行用 class ssl.SSLContext(protocol) 去實現
hostname = "www.google.com"
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
conn = ssl.create_connection((hostname, 443))
sock = context.wrap_socket(conn, server_hostname=hostname)
cert = ssl.DER_cert_to_PEM_cert(sock.getpeercert(True))
x509 = M2Crypto.X509.load_cert_string(cert)
print x509.get_not_after().get_datetime()
PROTOCOL_* constants defined in this module.
ssl.PROTOCOL_TLS
Selects the highest protocol version that both the client and server support.
Despite the name, this option can select “TLS”
SSL HTTP Connection
mySSL_v1.py
#!/usr/bin/env python # vim: sts=4:ts=4:sw=4:paste:et import socket, ssl, pprint ServerName = "datahunter.org" #context = ssl.create_default_context() context = ssl.SSLContext(ssl.PROTOCOL_TLS) context.verify_mode = ssl.CERT_NONE s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_sock = context.wrap_socket(s, server_hostname=ServerName) ssl_sock.connect((ServerName, 443)) #ssl_sock.sendall("POST / HTTP/1.1\r\n") ssl_sock.sendall("POST /tim.php HTTP/1.1\r\n") ssl_sock.sendall("Host: " + ServerName + "\r\n") ssl_sock.sendall("Content-Type: text/plain" + "\r\n") #ssl_sock.sendall("Content-Length: 8" + "\r\n") #ssl_sock.sendall("mytest: 1" + "\r\n") ssl_sock.sendall("\r\n") ssl_sock.sendall("testtest" + "\r\n") ssl_sock.sendall("\r\n") pprint.pprint(ssl_sock.recv(4096).split("\r\n")) ssl_sock.close()
只能收到 Header, 沒有收到 Body !!
P.S.
1) 設定 SSL 連線
context = ssl.SSLContext(ssl.PROTOCOL_TLS) context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = True context.load_default_certs()
SSLContext.verify_mode
Whether to try to verify other peers’ certificates and how to behave if verification fails.
This attribute must be one of ssl.CERT_NONE, ssl.CERT_OPTIONAL or ssl.CERT_REQUIRED.
2) sendall()
Unlike send(), sendall() method continues to send data from string until
either all data has been sent or an error occurs.
None is returned on success. On error, an exception is raised
close()
releases the resource associated with a connection but does not necessarily close the connection immediately.
If you want to close the connection in a timely fashion, call shutdown() before close().
3) socket.recv(bufsize[, flags])
The maximum amount of data to be received at once is specified by bufsize.(Default: 0)
只收到 Header, 但沒有 Body 的情況
Even if you read only a few bytes from a SSL socket
it needs to read the full SSL record which contains the encrypted data,
decrypt the full record and then it can return the few bytes you've requested.
The ssl_socket.revc(RECV_BUFFER) will at least read as much data from the underlying TCP connection as it needs to have a full SSL record.
Then it will decrypt the SSL record and return at most RECV_BUFFER bytes of decrypted data.
Fix: mySSL_v2.py
... pprint.pprint(ssl_sock.recv(4096).split("\r\n"))
ssl_socket.pending()
It will tell you if there is still unread decrypt data in the SSL socket.
It will not check if there are data available at the underlying TCP socket.
If there are data still in the SSL socket the next ssl_socket.recv(...) will return from these data
but will not try to read more data from the underlying TCP socket.
Only if there are no more decrypted but unread data are available in the SSL socket
a recv will read more from the underlying TCP socket
(in this case pending will return false so you will never try to read more data.)
* SSL need to be treated like a data stream and not like a message protocol (same for TCP).
This means you cannot assume that the message gets read in full and
that it will be returned in full or that it is least already in full in the SSL object.
Instead you either need to know the size of the response up-front (like prefixing the response with a length) or
need to have some clear marker that the response has ended and read until this marker.
UNSUPPORTED_PROTOCOL
ssl.SSLError: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:727)
- ssl.PROTOCOL_TLS
- ssl.PROTOCOL_TLSv1
- ssl.PROTOCOL_TLSv1_1
- ssl.PROTOCOL_TLSv1_2
由 "ssl.PROTOCOL_TLS" 改成 "ssl.PROTOCOL_TLSv1"
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
M2Crypto
m2crypto - Python wrapper for the OpenSSL library
pip
pip install m2crypto
# Debain
apt-get install python-m2crypto
x509
x509.get_subject().as_text() x509.get_not_after().get_datetime()