I've implemented a SOAP client in python with the zeep library. Some of the endpoints require client-side certificate authentication, thus the need to attach the certificate to the python requests's session.
After googling around, I've come up with:
from zeep import Client
from zeep.transports import Transport
from django.utils import timezone
import requests
......
session = requests.Session()
session.verify = False
session.cert= ('pat_to_cert.pem','path_to_privKey.pem')
transport = Transport(session=session)
....
client = Client(wsdl=wsdl, transport=transport)
send = getattr(service, service_name)
result = send(**data)
Debbugging the TLS handshake, the server issues a Certificate Request, but the client replies with an empty certificate. I've already checked the .pem files with openssl with no errors.
Is it possible that python's requests is not attaching the certificate because it does not recognize the server name? How can I enforce to use this certificate for every request?
In your code, you are setting session.verify = False that's why TLS verification is disabled.
what you need to do is to set:
session.verify = 'path/to/my/certificate.pem'
Also, Alternatively, instead of using session.verify you can use session.cert if you just want to use an TLS client certificate:
session.verify = True
session.cert = ('my_cert', 'my_key')
please check the documentation for more details: https://docs.python-zeep.org/en/master/transport.html
hope this helps
Related
I am making both server and client for an application, using the ACE library with OpenSSL. I am trying to get mutual authentication to work, o the server will only accept connections from trusted clients.
I have generated a CA key and cert, and used it to sign a server cert and a client cert (each with their own keys also). I seem to be loading the trusted store correctly, but I keep getting the error "peer did not return a certificate" during handshake.
Server side code:
ACE_SSL_Context *context = ACE_SSL_Context::instance();
context->set_mode(ACE_SSL_Context::SSLv23_server);
context->certificate("../ACE-server/server_cert.pem", SSL_FILETYPE_PEM);
context->private_key("../ACE-server/server_key.pem", SSL_FILETYPE_PEM);
if (context->load_trusted_ca("../ACE-server/trusted.pem", 0, false) == -1) {
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "load_trusted_ca"), -1);
}
if (context->have_trusted_ca() <= 0) {
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "have_trusted_ca"), -1);
}
Client side code:
ACE_SSL_Context *context = ACE_SSL_Context::instance();
context->set_mode(ACE_SSL_Context::SSLv23_client);
context->certificate("../ACE-client/client_cert.pem", SSL_FILETYPE_PEM);
context->private_key("../ACE-client/client_key.pem", SSL_FILETYPE_PEM);
I generated the certificates following these instructions: https://blog.codeship.com/how-to-set-up-mutual-tls-authentication/
And checking online, I found that if the .crt and .key files are readable, they should already be in .pem format and there is no need to convert them. So I just changed the extension and used them here.
Any help is appreciated!
My problem apparently was the same as seen here: OpenSSL client not sending client certificate
I was changing the SSL context after creating the SSL Socket. Now the mutual authentication works, but my client crashes when closing the connection. Though I don't know why that is yet.
I am trying to find example code on how to get this to work. Without having to specify any certificates on the client side. Does anyone have an example of how to do this?
All examples I have found online use SSL/TLS for authentication as well as transport security.
Yes.
You need to add an auth_mechanisms = PLAIN or AMQPPLAIN in rabbitmq.conf
Configure certificates in the server and client.
It isn't needed to use rabbitmq_auth_mechanism_ssl plugin
Using Java you need to create a KeyStore, KeyManagerFactory and TrustManagerFactory, and send your certificate.
Using Python you'll need to use ssl package and create a context and load a certificate chain and send to the server your certificate.
After configuring ssl as in the documentation, using Java create a factory, and set a user and a password. Using Python create a PlainCredentials.
In Python will be something like this:
import pika
import sys
import ssl
context = ssl.create_default_context(cafile="/home/userx/rabbitmq/certs/testca/ca.crt")
context.load_cert_chain("/home/userx/rabbitmq/certs/client/client_certificate.pem", "/home/userx/rabbitmq/certs/client/private_key.pem")
ssl_options = pika.SSLOptions(context, server_hostname="xrabbit")
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations('/home/userx/rabbitmq/certs/testca/ca.crt')
credentials = pika.PlainCredentials('user1', 'password%!xyz$328')
parameters = pika.ConnectionParameters('xrabbit',5671,'/',credentials, ssl_options=ssl_options)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
In Java something like this:
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream("/home/userx/rabbitmq/certs/client_keystore.pkcs12"), keyPassphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPassphrase);
char[] trustPassphrase = "rabbit".toCharArray();
KeyStore tks = KeyStore.getInstance("PKCS12");
tks.load(new FileInputStream("/home/userx/rabbitmq/certs/trust_store"), trustPassphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");tmf.init(tks);
SSLContext c = SSLContext.getInstance("TLSv1.3");
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("xrabbit");
factory.setPort(5671);
factory.setUsername("user1");
factory.setPassword("password$321xk!!44");
factory.setSaslConfig(DefaultSaslConfig.PLAIN);
factory.useSslProtocol(c);
factory.enableHostnameVerification();
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
Finally, use Wireshark to check the connection, only TLS packets should appear, if your client connection is using only plain text, will appear TLS packets from the server, but your client will send AMQP packets, if your server and client are using TLS you'll see only TLS packets.
Follow the official website documentation:
https://www.rabbitmq.com/ssl.html
You can find the configuration with and without client side configuration.
Using SoapUI 5.2.1 with the SSL client cert configured...
A python request to the endpoint like so
import requests
HOST = 'https://HOST'
CERT_FILE = 'CERT.crt'
KEY_FILE = 'KEY.key'
ping_response = requests.get(HOST, cert=(CERT_FILE, KEY_FILE))
print(ping_response)
works fine, but when I turned the cert/key into a PFX or a java keystore and load it into SoapUI like so
http://geekswithblogs.net/gvdmaaden/archive/2011/02/24/how-to-configure-soapui-with-client-certificate-authentication.aspx
I run a request and get a 400 Bad Request response with a body of "No required SSL certificate was sent"
It seems that the client cert is not being sent. Is there another step to configuring SoapUI for client auth? Do I need to specifically link it to the project or request somewhere?
I am trying to setup the certificate verification in opensips along with the blink sip client. I followed the tutorial:
https://github.com/antonraharja/book-opensips-101/blob/master/content/3.2.%20SIP%20TLS%20Secure%20Calling.mediawiki
My config look like so:
[opensips.cfg]
disable_tls = no
listen = tls:my_ip:5061
tls_verify_server= 0
tls_verify_client = 1
tls_require_client_certificate = 1
#tls_method = TLSv1
tls_method = SSLv23
tls_certificate = "/usr/local/etc/opensips/tls/server/server-cert.pem"
tls_private_key = "/usr/local/etc/opensips/tls/server/server-privkey.pem"
tls_ca_list = "/usr/local/etc/opensips/tls/server/server-calist.pem"
So i generated the rootCA and the server certificate. Then i took the server-calist.pem added the server-privkey.pem in there (otherwise blink sip client won't load it) and set it in client. I also set the server-calist.pem as a certificate authority in the blink. But when i try to login to my server i get:
Feb 4 21:02:42 user /usr/local/sbin/opensips[28065]: DBG:core:tcp_read_req: Using the global ( per process ) buff
Feb 4 21:02:42 user /usr/local/sbin/opensips[28065]: DBG:core:tls_update_fd: New fd is 17
Feb 4 21:02:42 user /usr/local/sbin/opensips[28065]: ERROR:core:tls_accept: New TLS connection from 130.85.9.114:48253 failed to accept: rejected by client
So i assume that the client doesn't accept the server certificate for some reason, although i have the "Verify server" checkbox turned off in my blink sip client! I think i have the wrong certificate authority file.
./user/user-cert.pem
./user/user-cert_req.pem
./user/user-privkey.pem
./user/user-calist.pem <- this 4 are for using opensips as a client i think
./rootCA/certs/01.pem
./rootCA/private/cakey.pem
./rootCA/cacert.pem
./server/server-privkey.pem
./server/server-calist.pem
./server/server-cert.pem
./server/server-cert_req.pem
./calist.pem
Can anybody help, did i do something wrong i the config or did i use the wrong certificate chain? What certificate exactly should be used by the client as a client cert, and ca authority cert?
Allright, i'm still not sure if it is working or not, because the authorization behaviour became weird, but after it's hanging for 5-6 minutes i get the success authorization, so this is a solution:
Generate rootCA:
opensipsctl tls rootCA
then edit server.conf file in your tls opensips folder and set the commonName = xxx.xxx.xxx.xxx where xxx.xxx.xxx.xxx is your server ip address. Other variables can be edited in any way. Generate the certificates signed by CA
opensipsctl tls userCERT server
This will produce 4 files. Download the server-calist.pem, server-cert.pem, server-privkey.pem. Open the server-privkey.pem, copy it's content and paste in the file server-cert.pem, before the actual certificate. If you are using blink, the produced server-cert.pem goes in the preferences->account->advanced. And server-calist.pem goes into the preferences->advanced. After that restart blink and after 5-6 minutes your account is gonna be logged in. But i'v observed a weird behaviour, if you run another copy of blink and try to log into the other existing account after your logged from the first one with the certificates, you can log in from other account without providing the certificates. So i don't know, but i think it's working.
P.S. I asked about the certificates in the opensips mailing list, but i guess they found my question too lame, so i didn't get the response. If you have the same problem and got better results or an answer from opensips support let me know please.
From CherryPy 3.0 and onwards, one-way SSL can be turned on simply by pointing to the server certificate and private key, like this:
import cherrypy
class HelloWorld(object):
def index(self):
return "Hello SSL World!"
index.exposed = True
cherrypy.server.ssl_certificate = "keys/server.crt"
cherrypy.server.ssl_private_key = "keys/server.crtkey"
cherrypy.quickstart(HelloWorld())
This enables clients to validate the server's authenticity. Does anyone know whether CherryPy supports 2-way ssl, e.g. where the server can also check client authenticity by validating a client certificate?
If yes, could anyone give an example how is that done? Or post a reference to an example?
It doesn't out of the box. You'd have to patch the wsgiserver to provide that feature. There is a ticket (and patches) in progress at http://www.cherrypy.org/ticket/1001.
I have been looking for the same thing. I know there are some patches on the CherryPy site.
I also found the following at CherryPy SSL Client Authentication. I haven't compared this vs the CherryPy patches but maybe the info will be helpful.
We recently needed to develop a quick
but resilient REST application and
found that CherryPy suited our needs
better than other Python networking
frameworks, like Twisted.
Unfortunately, its simplicity lacked a
key feature we needed, Server/Client
SSL certificate validation. Therefore
we spent a few hours writing a few
quick modifications to the current
release, 3.1.2. The following code
snippets are the modifications we
made:
cherrypy/_cpserver.py
## -55,7 +55,6 ## instance = None ssl_certificate = None ssl_private_key
= None
+ ssl_ca_certificate = None nodelay = True
def __init__(self):
cherrypy/wsgiserver/__init__.py
## -1480,6 +1480,7 ##
# Paths to certificate and private key files ssl_certificate = None ssl_private_key = None
+ ssl_ca_certificate = None
def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None, max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
## -1619,7 +1620,9 ##
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if self.nodelay: self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- if self.ssl_certificate and self.ssl_private_key:
+ if self.ssl_certificate and self.ssl_private_key and \
+ self.ssl_ca_certificate:
+ if SSL is None: raise ImportError("You must install pyOpenSSL to use HTTPS.")
## -1627,6 +1630,11 ## ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.use_privatekey_file(self.ssl_private_key) ctx.use_certificate_file(self.ssl_certificate)
+ x509 = crypto.load_certificate(crypto.FILETYPE_PEM,
+ open(self.ssl_ca_certificate).read())
+ store = ctx.get_cert_store()
+ store.add_cert(x509)
+ ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, lambda *x:True) self.socket = SSLConnection(ctx, self.socket) self.populate_ssl_environ()
The above patches require the
inclusion of a new configuration
option inside of the CherryPy server
configuration,
server.ssl_ca_certificate. This
option identifies the certificate
authority file that connecting clients
will be validated against, if the
client does not present a valid client
certificate it will close the
connection immediately.
Our solution has advantages and
disadvantages, the primary advantage
being if the connecting client doesn’t
present a valid certificate it’s
connection is immediately closed.
This is good for security concerns as
it does not permit the client any
access into the CherryPy application
stack. However, since the restriction
is done at the socket level the
CherryPy application can never see the
client connecting and hence the
solution is somewhat inflexible.
An optimal solution would allow the
client to connect to the CherryPy
socket and send the client certificate
up into the application stack. Then a
custom CherryPy Tool would validate
the certificate inside of the
application stack and close the
connection if necessary; unfortunately
because of the structure of CherryPy’s
pyOpenSSL implementation it is
difficult to retrieve the client
certificate inside of the application
stack.
Of course the patches above should
only be used at your own risk. If you
come up with a better solution please
let us know.
If the current version of CherryPy does not support client certificate verification, it is possible to configure CherryPy to listen to 127.0.0.1:80, install HAProxy to listen to 443 and verify client side certificates and to forward traffic to 127.0.0.1:80
HAProxy is simple, light, fast and reliable.
An example of HAProxy configuration