I am having problems making ssl connections with IDEA-CBC-SHA on python 2.7 / Win XP.
This is the code:
ciphers = "IDEA-CBC-SHA"
ssl_sock = ssl.wrap_socket(self.sock,
keyfile = keyfile,
certfile = certfile,
ciphers = ciphers)
ssl_sock.connect((address, port))
And this is the result:
SSLError: _ssl.c:319: No cipher can be selected.
When I query openssl, I see IDEA-CBC-SHA as one of the listed ciphers
OpenSSL> ciphers
DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DES-CBC3-MD5:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:IDEA-CBC-SHA:IDEA-CBC-MD5:RC2-CBC-MD5:RC4-SHA:RC4-MD5:RC4-MD5:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:DES-CBC-MD5:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5:EXP-RC4-MD5:EXP-RC4-MD5
I've tested with other ciphers (DES-CBC3-SHA ,RC4-SHA, AES256-SHA, AES128-SHA), and they all worked fine.
Any idea why my ssl connection might be failing for this specific cipher?
Is there some way to disable (and then enable) ciphers?
Thanks!
Any idea why my ssl connection might be failing for this specific cipher?
Perhaps the server you are connecting to does not support IDEA. A packet capture would confirm this.
EDIT: In an ssl connection, the client suggests a list of cipher options it is willing to use. The server selects one of the options from that list that the server finds acceptable. If the server does not like any options the client proposed, then the connection will fail, because the server is unable to select a cipher suite.
Related
I am writing a python socket server with ssl and I am encountering certificate unknown error during ssl handshake.
I have created private key and certificate with openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes command on my own.
This server is intended to run in intranet(under wifi) in my PC, and users will contact my PC IPaddress with their browser. Hence I have not registered this certificate with any CA. and I don't think its mandatory in my case.
Below more details..
echoserver.py
import socket
import ssl
import threading
class echoserver:
def __init__(self,i,p):
self.ip=i
self.port=p
def handler(self,c,a):
msg=c.recv(1024)
c.send(msg)
def serve(self):
echoserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
echoserver = ssl.wrap_socket(echoserver, keyfile='keys/key.pem', certfile='keys/cert.pem', server_side=True)
echoserver.bind((self.ip, self.port))
echoserver.listen()
while True:
(c,a)=echoserver.accept()
threading.Thread(target=self.handler, args=(c,a)).start()
es=echoserver('192.168.43.124',443) #My PC's ip assigned under wifi network
es.serve()
#Connecting from mobile phone within same network as https://192.163.43.124
Error in server during ssl handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:1108)
What I tried
Adding cert_reqs=ssl.CERT_NONE and ca_certs="/location/to/keys" parameters in wrap_socket function.
Doesn't seems to work. I assume these options are for client side.
Adding do_handshake_on_connect=False in wrap_socket function
In Chrome, When connected server throws same error and thread/connection closed with exception. and chrome seems to send same connection request immediately again, and the second request works flawlessly !!.
In firefox, First connection closed with same error and there is no second request.
Assigning common name in certificate same as IP address
Not working.
Checked certificate_unknown error in ietf specification here. It gives no clue except this explanation certificate_unknown: Some other (unspecified) issue arose in processing the certificate, rendering it unacceptable.
One other thing I noted is, if I use built-in ThreadedHTTPServer in the same way as below, It works beautifully, without any issues I mentioned above.
httpd = self.ThreadedHTTPServer((self.ip, self.port), self.handler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='keys/key.pem', certfile='keys/cert.pem', server_side=True)
I am not sure why this happens and how should I proceed with this. and not sure how built-in server modules works fine.
Appreciate any leads. Thanks.
Below Python builtin HTTPServer works fine with ssl, not showing any error. Not sure how?
import ssl
from http.server import HTTPServer, BaseHTTPRequestHandler
class requesthandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type","text/html")
self.end_headers()
self.wfile.write("<html><body>It works</body></html>".encode('utf8'))
httpd = HTTPServer(('192.168.43.124', 443), requesthandler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='keys/key.pem', certfile='keys/cert.pem', server_side=True)
httpd.serve_forever()
ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:1108)
This means the client (browser) does not trust your certificate since it is issued by an unknown entity. If you want to use self-signed certificates you have to explicitly import these as trusted for all clients you want to use.
There is no way around this. The certificate in TLS is to make sure that the connection is done with the expected server and not some man in the middle claiming to be the expected server. If a client would trust arbitrary certificates then it would also trust certificates created by a man in the middle attacker.
Below Python builtin HTTPServer works fine with ssl, not showing any error. Not sure how?
The browser will still complain.
The only difference is that the server captures the exception and thus will not crash but continue. You can do the same in your code:
while True:
try:
(c,a)=echoserver.accept()
threading.Thread(target=self.handler, args=(c,a)).start()
except:
pass # ignore error
I'm implementing an IMAP proxy which securely communicates with a client.However, I have a problem when handshaking.
The code of my proxy is:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((host, port))
ssock, addr = self.sock.accept()
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
self.conn_client = context.wrap_socket(ssock)
And I receive the error:
ssl.SSLError: [SSL: UNEXPECTED_MESSAGE] unexpected message (_ssl.c:833)
The code of my tests is:
M = imaplib.IMAP4_SSL(IP_PROXY)
And I receive the error:
ssl.SSLError: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:777)
However, when the code of the proxy is:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((host, port))
ssock, addr = self.sock.accept()
self.conn_client = ssl.wrap_socket(ssock, certfile=CERT, server_side= True)
It correctly works but I don't want to use certificate.
Thank you
It correctly works but I don't want to use certificate.
SSL/TLS is almost everywhere used with a certificate to make sure that the client is talking to the expected server and not to some man in the middle. If you don't want to use a certificate you need to either use a different kind of authentication (like PSK) or use no authentication at all ("anonymous authentication" - very bad idea).
In any way you would need to set the relevant ciphers to enable this alternative authentication on both client and server. This can be done with the ciphers attribute to wrap_socket on the server side and in your client code it could probably be done by constructed a SSLContext with the necessary ciphers and using the ssl_context argument to specific the context to be used in IMAP4_SSL.
But this is only for your specific Python based IMAP client. Don't expect that you will be able to configure commonly used IMAP clients like Thunderbird or Outlook to be usable with a server without certificates. And like I said, it is a bad idea in the first place.
I'm using Python 2.4.4 and OpenSSL 0.9.8k (not by choice)
I've referred to the documentation: https://docs.python.org/release/2.4.4/lib/module-socket.html
and to pretty much every mention of "openSSL" and "python" on the internet, and I haven't found a solution to my problem.
I'm simply writing a test program to initiate an SSL connection. Here is the code:
server
#!/usr/bin/python
import socket
import _ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 4433))
s.listen(5)
while True:
client, address = s.accept()
ssl_client = socket.ssl(client,
keyfile='keyfile',
certfile='certfile')
print "Connection: ", address
data = ssl_client.read(1024)
if data:
print "received data: ", data
ssl_client.write(data + " Hello, World!")
del ssl_client
client.close()
client
#!/usr/bin/python
import socket
import _ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('host', 4433))
ssl_s = socket.ssl(s,
keyfile='keyfile',
certfile='certfile')
print 'writing ', ssl_s.write("Hello, World!"), ' bytes to ssl stream'
data = ssl_s.read(1024)
del ssl_s
s.close()
print "received data: ", data
Some notes about this code - keyfile and certfile are paths to my actual key and cert file. Those arguments are not the issue. The hostnames are also not the issue. I'm aware that the port used is 4433 - in our requirements, we're meant to use a generic port, not 443. I was unaware that it was possible to use SSL over a different port, but regardless, even when I use 443 I get the exact same error.
I can run the server fine, and then when I run the client, I get the following error on the wrap_socket lines for both client and server:
error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
I've read it's due to using a non-443 port, but again, using 443 didn't fix things. I've read it could be a protocol mismatch, but the client and the server are both defaulting to SSL2.3. We're meant to use TLS1.2 as per our requirements, but the docs don't seem to have any information on how to set the SSL protocol version. I'm unsure if that's related to my issue. Please keep in mind I'm not here to open a dialogue regarding to use of outdated SSL and Python versions.
socket.ssl is only able to initiate a SSL connection and the given optional cert and key are for use of client certificates. socket.ssl is not able to be used on the server side and it looks like python 2.4.4 does not offer this feature in any of the core modules at all. In later versions of python you can use the ssl module for this but 2.4.4 does not seem to have this.
I'm writing some software that is supposed to acquire information from SSL-secured web page. Below there's piece of code I use to connect to server.
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = ssl.wrap_socket (
s,
ca_certs = '/home/stilz/Desktop/Certyfikaty/GLOWNE_CA.cer',
cert_reqs = ssl.CERT_REQUIRED,
ssl_version = ssl.PROTOCOL_SSLv3,
)
ssl_sock.connect ((HOST, PORT))
However, this doesn't work. It throws exception with message "Handshake alert failed". I captured some TCP packets that come out of my script and also corresponding packets from Internet Explorer and figured out that my script doesn't send certificate at all (server returns something like "Fatal: no certificate supplied") while IE sends it normally. As far as I know file ca.cer is x509 certificate (beginning with "-----BEGIN CERTIFICATE-----").
Please help me and tell what I'm doing wrong. If I've supplied to few information, please let me know.
Regards
First of all, you need to determine if you need to authenticate yourself on the server (certificate is sent to the server only in this case) or you need to validate server's authenticity (in which case the certificate is not sent to the server).
Now about issues in your code:
Case 1: you don't need to authenticate on the server. In this case you don't need to specify your certificate and nothing is sent to the server.
Case 2: you need to authenticate yourself on the server. In that case you need to provide your certificate and your private key file in keyfile and certfile parameters. Only then your certificate is sent to the server (and the private key is used in the handshake).
I guess that your have case 1 in fact. So first of all you need to check if the server provides a valid certificate by connecting to it with a web browser and inspecting site's certificate chain. It can happen that the site sends its certificate but omits intermediate CA certificates.
In any case I'd like to remind about the discussion about certificates in Python docs which I suggest you re-read.
If the server requests (and requires) a certificate to be sent by the client, you need to supply ssl.wrap_socket with the path to your certificate (certfile) and its matching private key (keyfile). The ca_certs parameter is only used for the client to verify the server's certificate against known CA certificates, it has nothing to do with sending a client-certificate.
You may need to export your client-certificate and private key from IE (and then convert them to PEM format).
What's the easiest way to connect to a SMTP server that supports STARTTLS and get its server SSL certificate? I know it can be done using openssl with something like this
openssl s_client -starttls smtp -crlf -connect 192.168.0.1:25
How can I do it from within Python and I don't want to call openssl and parse its output. I looked at M2Crypto which is an openssl wrapper, but as far as I can tell that doesn't support starttls. An example of how to do it with a Python library would be very much appreciated.
This returns a certificate in binary format (DER-encoded):
import socket, ssl
s = socket.socket()
s.connect(("host", 25))
s.send("STARTTLS\n")
s.recv(1000)
ss = ssl.wrap_socket(s)
certificate_der = ss.getpeercert(True)
This is jus to give you an idea, error handling, etc. is required of course. If you want to decode the information from the certificate you either have to prodivde a certificate authorities bundle/directory for acceptable CAs (getpeercert() will return a meaningfull dict in this case), or use a more capable ssl library, M2Crypto for example.
You could try something like:
import ssl
cert = ssl.get_server_certificate(('imap.gmail.com',993))
to get server's certificate
As I can't comment abbot answer, just remark that depending on the server config you may need to send an EHLO before STARTTLS:
import socket, ssl
hostname = 'test.com'
port = 25
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
sock.recv(1000)
sock.send(b'EHLO\nSTARTTLS\n')
sock.recv(1000)
with context.wrap_socket(sock, server_hostname=hostname) as sslsock:
der_cert = sslsock.getpeercert(True)
smtplib provides the starttls() method which should deal with all issues:
http://docs.python.org/library/smtplib.html