[NitroKey HSM] How to use on POST HTTPS as client-side certificate?

Hi,

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?

I’d like to use python3 and I’d like to use requests module as it is written here:
https://requests.readthedocs.io/en/master/user/advanced/#client-side-certificates

Thanks
Bye

Hi @beps!

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:

Thanks a lot for your answer!

If I would not use python, how could I use the NitroKey by command line?
For example with curl?

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:

  • pkcs11
  • smartcard
  • openssl
  • opensc
  • curl / python (etc.)

See this OpenSC/Using-pkcs11-tool-and-OpenSSL wiki page as well.

I hope this helps.

PS Have you looked into all links I have sent initially? They are not marked as visited on my side.

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?

You need to construct it by hand I believe, e.g. as you would have accessing a file on a computer. See RFC examples.

Hi all,

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')