Looking for a convenient way to securely retrieve digital X.509 certificates for secure communication, authentication, digital signature, or encryption/decryption? In this tutorial you learn four different ways to issue certificates for IT services, users, clients, and IoT devices.

The tutorial is based on se.SAM™ N200 crypto appliance with se.SAM™ PKI software option. The following building blocks are featured:

Certificate Building Blocks

Certificate Building Blocks

(1) CA administrator issues a signing request

In this first use case, a CA administrator will issue an open signing request manually in the N200 admin GUI. The signing request could be initiated by REST API or the administrator himself creating a signing request in N200 admin GUI.

Depending on the distribution method defined in the signing request (in this case, template “IoT-Template-2022”) the generated X.509 certificate and optional the P12/PFX file including the private key will be distributed by e-mail, or REST-API or made available as download option in the N200 admin GUI.

se.SAM(TM) PKI Signing

se.SAM PKI Signing Request

After a second the signing request is processed and a X.509v3 certificate is available for implementation.

(2) CA administrator straight generates and signs a certificate

Administrator also have the option to skip the signing request step and straight generate and sign a certificate. Again, a certificate template is mandatory for this step.

se.SAM PKI Certificate Signing Request by Admin

se.SAM PKI Certificate Signing Request by Admin

As an administrator you find other management actions beside of issuing certificates. These actions are distribute or download certificates and P12/PFX key files, as well as revoke certificates, re-activate (revoked) certificates, copy certificates to new unsigned data sets, and delete certificates.

(3) Submit a signing request by REST API

Based on the ruleset and granted CA roles, clients may submit Certificate Signing Requests (CSR) according to RFC 2986 to se.SAM™ PKI. In a second step the client can request certificate issuing by REST API, or an CA/RO administrator will sign the CSR.

Especially for IoT clients or other clients not capable of building the complex ASN1 structure of a CSR we offer a documented JSON structure holding all relevant CSR data. As this JSON REST API request does not follow RFC 2986 we call it a “Pseudo CSR”.

Within the CSR process you typically generate the public/private key pair on client side and send the public key within the CSR. In the pseudo-CSR process, you have both option:

  1. Generate a public/private key pair on client-side and send the public key within the CSR request
  2. Don’t provide a public key in your CSR request and the CA will generate the key pair according to the certificate template for you

The first option to submit an RFC 2986 CSR is possible by REST API command ‘loadcsr’. The REST API command requires two parameters: ‘template’, the given name of a certificate template and ‘csr_dump’, the base64 encoded RFC 2986 CSR. The reply will be identical to the example below.

Enclosed you find a Python script how to use the pseudo-CSR API. In the ‘request_data’ you find the optional ‘public_key’ information.

#!/usr/bin/python3
import requests
# disable curl TLS warnings - NOT  recommended for production!
import urllib3
urllib3.disable_warnings()
import json

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
#from cryptography import x509
#from cryptography.x509.oid import NameOID

# Generate our key
key = rsa.generate_private_key(public_exponent=65537, key_size=2048,)
# Write our key to disk for safe keeping
passphrase = b"passphrase!"
with open("key.pem", "wb") as f:
    f.write(key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.BestAvailableEncryption(passphrase),
    ))

# Extract public key
public_key_pem = key.public_key().public_bytes(
   encoding=serialization.Encoding.PEM,
   format=serialization.PublicFormat.SubjectPublicKeyInfo
)

# Request the certificate using issuepseudocsr command
url = 'https://192.168.178.63/sesampki/web/postv1'
headers = { 'Authorization': 'Basic YWRtaW46YWRtaW4=' } # Base64 admin:admin

count = 1   # simulate generation of multiple certificates by adding value
for i in range(count):
    request_data = {
        'name': "This Cert "+str(i),
        'CN': "My Common Name", 'GN': "My Givenname", 'SN': "My Surname",
        'O': "My Organisation", 'OU': "My Organisational Unit",
        'C': "My City", 'ST': "My State", 'L': "My Location",
        'DNS': "host.domain.com", 'E': "mymail@domain.com",
        #'public_key': public_key_pem.decode('utf-8')
        }
    payload = {'command': "issuepseudocsr", 'template': "Email-Template-2022",
           'request_data': json.dumps(request_data)}
    response = requests.request("POST", url, headers=headers, data=payload, verify=False)
    jsonresult = json.loads(response.text)
    if response.status_code != 200 or jsonresult["result"] == "ST_FF":
        print("REST API HTTP or Value Error in loop #%d" % i)
        break

if response.status_code == 200:
    print(response.text)
else:
    print(response.status_code)
    print(response.text)

This is a typical result of the REST API request:

{ "command": "issuepseudocsr", 
  "result": "284628736323256650699441533467945761475917836847", 
  "x509_cert": "-----BEGIN CERTIFICATE-----\nMIIFPzCCBCegAwIBAgIUMdsxpxL94856cCsPD2+XXl3g8i8wDQYJKoZIhvcNAQEL\nBQAwfDEaMBgGA1UEAwwRSW9UIElzc3VlIENBIDIwMjIxFTATBgNVBAoMDHNlbWF0\n 
   … \n+aFC\n-----END CERTIFICATE-----\n" 
}

The JSON return value is a well formatted text message, you can use any JSON library to extract the ‘x509_cert’ and optionally ‘p12_data’ in the CSR return.

(4) Directly issuing certificates through REST API

Instead of submitting a CSR and initiate a second step to issue the certificate from the CSR, you can directly issue a certificate by giving a template name and provide data like common name, DNS addresses, email addresses, etc. for the certificate.

Passing a client defined passphrase allows you to encrypt the server generated p12 file with that passphrase, before storing this sensitive information in its database.

Enclosed a sample program in Python how to generate a certificate using ‘gencert’ command:

#!/usr/bin/python3
import requests
# disable curl TLS warnings - NOT  recommended for production!
import urllib3
urllib3.disable_warnings()

# Request the certificate using gencert command
passphrase = "passphrase!"
url = 'https://192.168.178.63/sesampki/web/postv1'
headers = { 'Authorization': 'Basic YWRtaW46YWRtaW4=' } # Base64 admin:admin
payload = {
        'command': "gencert", 'template': "Email-Template-2022",
        'CN': "Arnie S.", 'GN': "Arnie", 'SN': "S.",
        'O': "My Organisation", "OU": "My Organisational Unit",
        'L': "Munich",
        'p12_pass': passphrase
        }
response = requests.request("POST", url, headers=headers, data=payload, verify=False)
if response.status_code != 200:
    print(response.status_code)
    print(response.text)
else:                     # print response on HTTP status 200
    print(response.text)

The result of ‘gencert’ is the certificate’s serial number in addition to the P12/PFX file data and the generated X.509v3 certificate in PEM format. As JSON can’t transport binary data the P12/PFX data need to be base64 decoded to a binary file on the client:

{
"command": "gencert", 
"result": "664622425054585941723673407387692580443999745183", 
"p12_data": MIIGMQIBAzCCBfsGCSqGSIb3DQEHAaCCBewEggXoMIIF5DCCBLcGCSqGSIb3DQEH\nBqCCBKgwggSkAgEAMIIEnQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMwDgQIL3/K\n
…
\nRrsvDPv7MC0wITAJBgUrDgMCGgUABBSfWAw2JRLuZJynPIhIbodrcATBdAQIbtiI\nFgcoYT0=" ",
"x509_cert": "-----BEGIN CERTIFICATE-----\nMIID8zCCAtugAwIBAgIUdGqzRTQk2md4Nz+f2IWZ6ESItJ8wDQYJKoZIhvcNAQEL\n
…
\nMEGk/REe+Q==\n-----END CERTIFICATE-----\n"
}

The JSON return value is a well formatted text message, you can use any JSON library to extract the ‘x509_cert’ and optionally ‘p12_data’ in the CSR return.

Performance considerations

  • 100x Pseude-CSR mit BP256 (RSA-IssuingCA)
  • 100x Pseude-CSR mit RSA2048 (RSA-IssuingCA)
  • 100x Pseude-CSR mit RSA4096 (RSA-IssuingCA)
  • 100x Pseude-CSR mit RSA4096 (RSA-IssuingCA)
  • 100x Pseude-CSR mit NIST-P256 (RSA-IssuingCA)
  • ~ 2m12 sec
  • ~ 2m32 sec
  • ~ 4m28 sec
  • ~ 4m28 sec
  • ~ 2m29 sec

(5) Directly issuing certificates through REST API

Last, but not least you can use Node-RED to issue a certificate through its integrated ‘http request’ node. Again, a set of JSON parameters is send by HTTP POST request to the POST URL of the HSM, e.g. https://192.168.178.63/sesampki/web/postv1

The Node-RED note ‘http request’ supports basic authentication, a perfect match for the se.SAM™ N200 Crypto Appliance.

Node R

See another detailed Crypto Corner article how to use Node-RED with the se.SAM™ N200 Crypto Appliance.

This simple sketch writes the certificate or P12/PFX data to a file only. Of course you can use any other Node-RED method to automate the certificate delivery including MQTT.

Keep an eye on:

We are happy to assist you in defining your way to issue certificates to any kind of devices.

Weitere Beiträge

HSM-Safe (Credentials, Personal Data, Business Secrets, Finance Data)