I’m working on project where a software client needs to POST some data to a specific url using HTTPS protocol.
The webserver needs to verify the client certificate using TLS (two-way authentication).
The client private key is inside the NitroKey HSM.
How can I use the NitroKey private key during the connection to webserver?
It should be doable with OpenSSL and OpenSC. I am not sure whether it’s possible with requests package - that depends whether you can pass custom OpenSSL configuration.
I did not found exact answer for you, but following should help you do so:
For curl, see the --engine and -E, --cert <certificate[:password]> switches in its manual page. Excerpt:
If curl is built against OpenSSL library, and the engine pkcs11 is available, then a PKCS#11 URI (RFC 7512) can be used to specify a certificate located in a PKCS#11 device. A string beginning with “pkcs11:” will be interpreted as a PKCS#11 URI. If a PKCS#11 URI is provided, then the --engine option will be set as “pkcs11” if none was provided and the --cert-type option will be set as “ENG” if none was provided.
As long as OpenSSL is supported and the engine is configurable it should be possible with any tool / library.
I do not think we have any documentation for this in general unfortunately. Perhaps OpenSC discussion list would help you too (1)(2). For further searches I recommend looking for terms like following the conjointly:
Thanks a lot!
Honestly, after I read your answer, I realized that the python way doesn’t seem to be well known so, for the moment, I would like to understand the command line feasibility.
After establishing the feasibility I will go into the python code.
About OpenSSL, I’ve already configured its configuration file and I’m able to use it to encrypt/decrypt a text message using NitroKey.
About “curl”, I saw that it need the PKCS#11 URI. Do you know where I can see it?
just to close my ticket.
I’ve found a solution using python and Nitrokey and now it works: I can use a private key (id=20) and certificate (id=10), both stored on NitroKey, to do a client side authentication on HTTPS connection.
The “requests” library does not support natively PKCS#11 protocol so I use “M2Crypto” library connected to “requests” with M2HttpsAdapter found here: m2requests.py
Here a code snippet:
#!/usr/bin/python3
import json
import requests
from requests import Session
from m2requests import M2HttpsAdapter
# Disable SubjectAltNameWarning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.SecurityWarning)
# url
url = 'https://postman-echo.com/post'
# TLS settings
ca_chain = '/etc/ssl/certs/ca-certificates.crt'
# Send data
payload = json.dumps({'data':'mycustomdatavalue'})
headers = {'content-type': 'application/json'}
print('sending data to SERVER:', payload)
# Creating Session
request = Session()
request.mount("https://", M2HttpsAdapter())
# PKCS#11 URI; REF: https://tools.ietf.org/html/rfc7512
request.cert=("pkcs11:type=cert;id=%10", "pkcs11:type=private;id=%20;pin-value=648219")
request.verify=ca_chain
request.headers=headers
r = request.post(url, data=payload)
print('SERVER response status code: {}'.format(r.status_code))
if (r.status_code == 200):
print(r.raw.data)
else:
print('ERROR')