Accessing a NetHSM using the REST API

This tutorial demonstrates how to access the NetHMS via REST API. The interface is documented here ,and its specification is available as RAML and as OpenAPI (Swagger).

Before we start, we store the host name of the NetHSM instance in the NETHSM_HOST environment variable. You can use the public NetHSM demo instance nethsmdemo.nitrokey.com or run a local demo instance using the NetHSM docker image, see the Development and Testing section of the NetHSM documentation.

$ export NETHSM_HOST="localhost:8443"

Note

If you use a NetHSM demo instance with a self-signed certificate, for example using the Docker image, you will have to use the –insecure/-k option for curl to skip the certificate check.

First, let’s see what we have here:

$ curl -i -w '\n' https://$NETHSM_HOST/api/v1/info
HTTP/1.1 200 OK
content-length: 45
content-type: application/json
date: Mon, 25 Jan 2021 21:00:27 GMT
etag: "7bab62510e05c332735624bc7a585a30"
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

{"vendor":"Nitrokey GmbH","product":"NetHSM"}

Note

The -i/–include option causes curl to print the HTTP status code and the response headers. The -w ‘n’/–write-out ‘n’ option adds a newline after the response body.

See what the device’s status is:

$ curl -i -w '\n' https://$NETHSM_HOST/api/v1/health/state
HTTP/1.1 200 OK
cache-control: no-cache
content-length: 25
content-type: application/json
date: Mon, 25 Jan 2021 20:57:32 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

{"state":"Unprovisioned"}

Initialization

A new NetHSM needs to be provisioned first with passphrases and the current time. The Admin Passphrase is the Administrator’s passphrase, which is the superuser of the NetHSM. The Unlock Passphrase is used to encrypt NetHSM’s confidential data store.

Note

The NetHSM demo instance at nethsmdemo.nitrokey.com is already provisioned.

$ curl -i -w '\n' -X POST https://$NETHSM_HOST/api/v1/provision \
    -H "content-type: application/json" \
    -d "{ adminPassphrase: \"adminPassphrase\", unlockPassphrase: \"unlockPassphrase\", \
    systemTime: \"$(date --utc -Iseconds)\"}"
HTTP/1.1 204 No Content
cache-control: no-cache
content-type: application/json
date: Wed, 11 Nov 2020 16:35:44 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

NetHSM can be used in Attended Boot mode and Unattended Boot mode.

  • In Attended Boot mode, the Unlock Passphrase needs to be entered during each start, which is used to encrypt the data store. For security reasons, this mode is recommended.

  • In Unattended Boot mode no Unlock Passphrase is required, therefore the NetHSM can start unattended and the data store is stored unencrypted. Use this mode if your availability requirements can’t be fulfilled with Attended Boot mode.

Retrieve the current mode:

$ curl -i -w '\n' -u admin:adminPassphrase \
    https://$NETHSM_HOST/api/v1/config/unattended-boot
HTTP/1.1 200 OK
content-length: 16
content-type: application/json
date: Wed, 21 Apr 2021 10:20:55 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

{"status":"off"}

Switch to Unattended Boot mode:

$ curl -i -w '\n' -u admin:adminPassphrase -X PUT -H "content-type: application/json" \
    https://$NETHSM_HOST/api/v1/config/unattended-boot -d "{ status: \"on\"}"
HTTP/1.1 204 No Content
content-type: application/json
date: Wed, 21 Apr 2021 10:24:25 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

Or switch back to Attended Boot mode:

$ curl -i -w '\n' -u admin:adminPassphrase -X PUT -H "content-type: application/json" \
    https://$NETHSM_HOST/api/v1/config/unattended-boot -d "{ status: \"off\"}"
HTTP/1.1 204 No Content
content-type: application/json
date: Wed, 21 Apr 2021 10:24:53 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

User Management

Roles

Separation of duties can be implemented by using the available Roles. Each user account configured on the NetHSM has one of the following Roles assigned to it. Following is a high-level description of the operations allowed by individual Roles, for endpoint-specific details please refer to the REST API documentation.

  • R-Administrator: A user account with this Role has access to all operations provided by the REST API, except for key usage operations, i.e. message signing and decryption.

  • R-Operator: A user account with this Role has access to all key usage operations, a read-only subset of key management operations and user management operations allowing changes to their own account only.

  • R-Metrics: A user account with this Role has access to read-only metrics operations only.

  • R-Backup: A user account with this Role has access to the operations required to initiate a system backup only.

Note: In a future releases, additional Roles may be introduced.

Create a User

Now create a new user with the operator role that can be used to sign and decrypt data. Note that the NetHSM assigns a random user ID if we don’t specify it.

$ curl -i -w '\n' -u admin:adminPassphrase \
    "https://$NETHSM_HOST/api/v1/users/operator" -X PUT \
    -H "content-type: application/json" -d "{\"realName\": \"Jane User\", \
    \"role\": \"Operator\", \"passphrase\": \"opPassphrase\"}"
HTTP/1.1 201 Created
content-length: 0
content-type: application/json
date: Wed, 21 Apr 2021 10:25:27 GMT
location: /api/v1/users/operator
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

Key Management

The NetHSM supports RSA, ED25519 and ECDSA keys. When creating a key, you have to select both the key algorithm and the key mechanisms to use. RSA keys can be used for decryption (with the modes raw, PKCS#1 and OAEP with MD5, SHA1, SHA224, SHA256, SHA384 or SHA512) and for signatures (with the modes PKCS#1 and PSS with MD5, SHA1, SHA224, SHA256, SHA384 or SHA512). The other algorithms only support the signature mechanism.

For a complete list of available key algorithms and key mechanisms, see the API documentation for the KeyAlgorithm and KeyMechanism types.

Generate Keys

In this section, we want to use an RSA key to decrypt data using PKCS#1 and to sign data with PSS using SHA256. So let’s generate a new key on the NetHSM. Make sure to use the RSA algorithm and to select the RSA_Signature_PSS_SHA256 and RSA_Decryption_PKCS1 key mechanisms. If you don’t specify a key ID, the NetHSM will generate a random ID for the new key.

$ curl -i -w '\n' -u admin:adminPassphrase -X POST \
    https://$NETHSM_HOST/api/v1/keys/generate -H "content-type: application/json" \
    -d "{ \"mechanisms\": [ \"RSA_Signature_PSS_SHA256\", \"RSA_Decryption_PKCS1\" ], \
    \"algorithm\": \"RSA\",  \"length\": 2048,  \"id\": \"myFirstKey\"}"
HTTP/1.1 201 Created
cache-control: no-cache
content-length: 0
content-type: application/json
date: Tue, 26 Jan 2021 05:54:09 GMT
location: /api/v1/keys/0ead0d9dd849cecf845c
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

Import Keys

Instead of generating a key on the NetHSM, you can also import existing private keys into the NetHSM:

$ curl -i -w '\n' -u admin:adminPassphrase -X PUT \
    https://$NETHSM_HOST/api/v1/keys/mySecondKey -H "content-type: application/json" \
    -d "{ \"mechanisms\": [ \"RSA_Signature_PSS_SHA256\", \"RSA_Decryption_PKCS1\" ], \
    \"algorithm\": \"RSA\",  \"key\": {\"primeP\": \"AOnWFZ+JrI/xOXJU04uYCZOiPVUWd6CSbVseEYrYQYxc7dVroePshz29tc+VEOUP5T0O8lXMEkjFAwjW6C9QTAsPyl6jwyOQluMRIkdN4/7BAg3HAMuGd7VmkGyYrnZWW54sLWp1JD6XJG33kF+9OSar9ETPoVyBgK5punfiUFEL\", \"primeQ\": \"ANT1kWDdP9hZoFKT49dwdM/S+3ZDnxQa7kZk9p+JKU5RaU9e8pS2GOJljHwkES1FH6CUGeIaUi81tRKe2XZhe/163sEyMcxkaaRbBbTc1v6ZDKILFKKt4eX7LAQfhL/iFlgi6pcyUM8QDrm1QeFgGz11ChM0JuQw1WwkX06lg8iv\", \"publicExponent\": \"AQAB\"}}"
HTTP/1.1 204 No Content
content-type: application/json
date: Wed, 21 Apr 2021 10:37:23 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

List Keys

To make sure that the key has been created and has the correct algorithm and mechanism settings, we can query all keys on the NetHSM:

$ curl -i -w '\n' -u admin:adminPassphrase https://$NETHSM_HOST/api/v1/keys
HTTP/1.1 200 OK
content-length: 39
content-type: application/json
date: Tue, 26 Jan 2021 05:56:24 GMT
etag: "34353234366432333063663739313939346635316666343937333564653434333937613237626139"
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

[{"key":"myFirstKey"},{"key":"mySecondKey"}]

Show Key Details

We can also query the public key of the generated key pair:

$ curl -s -w '\n' -u admin:adminPassphrase https://$NETHSM_HOST/api/v1/keys/myFirstKey
{"mechanisms":["RSA_Decryption_PKCS1","RSA_Signature_PSS_SHA256"],"algorithm":"RSA","modulus":"td583uBYRfO7qtvPoQF7liUh8gq3zckCk9LpCfblx2S0HdOvButfD4TyH4EMiZj3NhEoq18BZhqhxTL22UyNJwYJd2tCF4EbgTaj/Z3LeCPoGN5LjadFCsYriPeHsdnuLmTK6KsmTAP/CWJ+u3LesU5bCGWbDnPjv2WaLTeiMuNw1347gj1drft8jFA9SmOFjZxM9pq2Hk1nQSYpeAPCnigC7hLwAWgzKqVQv/J7VVWat3ke/jOrxFiRDFIeC3qxtBs6T7GYwqmsxkxgqKDljTAH4qMrC9vgVbbFPffe8UgmtDfvQ0ghP57b3HYZDON90MJ2qrU944E74g+ua6unTw==","publicExponent":"AQAB","operations":0}

To be able to use the key with OpenSSL, we export it as a PEM file and store it as public.pem:

$ curl -u operator:opPassphrase -X GET \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/public.pem -o public.pem

We can inspect the key with OpenSSL and use it for encryption or signature verification (as described in the next section):

openssl rsa -in public.pem -pubin -text
RSA Public-Key: (2048 bit)
Modulus:
    00:c3:56:f5:09:cc:a9:3e:ca:16:2e:fb:d2:8b:9d:
    a9:33:5a:87:8f:3f:7a:bb:8a:3d:62:9b:5d:56:84:
    95:97:bb:97:f0:77:e2:c8:59:f2:b5:c6:b7:f5:b3:
    76:69:a3:e8:f6:b7:35:f4:3c:52:6d:3c:a0:b6:a1:
    e4:1a:32:05:1d:51:68:21:7d:fc:53:69:ec:bc:0b:
    a0:db:63:b2:0e:47:00:03:4d:98:1f:ab:c0:7b:2e:
    3c:8f:b6:36:ff:f0:db:80:26:f0:a6:af:30:2f:7b:
    16:fd:5c:db:0f:2c:54:8a:26:2b:db:3d:78:49:4b:
    7b:d1:60:ea:a7:f0:b4:5e:fc:33:ff:57:f8:83:fd:
    12:64:8f:29:d1:94:96:9a:15:18:5d:04:ca:1c:29:
    44:ad:42:31:c5:80:38:4c:eb:3b:b8:7e:17:27:5c:
    69:a8:88:44:ea:d1:82:64:fe:51:31:47:97:a7:a9:
    87:c3:13:c9:00:7a:b9:fb:6f:cc:66:4c:07:d7:68:
    fa:78:68:9a:e7:87:1e:94:c6:27:92:5f:f2:7d:11:
    44:11:b5:39:35:59:2c:cd:f9:4f:59:e3:56:93:1f:
    94:20:fd:6b:23:0d:15:e6:4e:bb:84:a8:a5:0d:9f:
    1c:90:ab:a8:10:04:50:12:c1:80:02:94:85:78:df:
    d6:b3
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1b1CcypPsoWLvvSi52p
M1qHjz96u4o9YptdVoSVl7uX8HfiyFnytca39bN2aaPo9rc19DxSbTygtqHkGjIF
HVFoIX38U2nsvAug22OyDkcAA02YH6vAey48j7Y2//DbgCbwpq8wL3sW/VzbDyxU
iiYr2z14SUt70WDqp/C0Xvwz/1f4g/0SZI8p0ZSWmhUYXQTKHClErUIxxYA4TOs7
uH4XJ1xpqIhE6tGCZP5RMUeXp6mHwxPJAHq5+2/MZkwH12j6eGia54celMYnkl/y
fRFEEbU5NVkszflPWeNWkx+UIP1rIw0V5k67hKilDZ8ckKuoEARQEsGAApSFeN/W
swIDAQAB
-----END PUBLIC KEY-----

Key Certificates

It is possible to set and query certificates for the keys stored on a NetHSM instance:

$ curl -i -w '\n' -u admin:adminPassphrase -X PUT \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/cert -H "content-type: application/x-pem-file" \
    --data-binary @/tmp/cert.pem
HTTP/1.1 201 Created
content-length: 0
content-type: text/html
date: Thu, 20 May 2021 19:15:39 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language
$ curl -s -w '\n' -u operator:opPassphrase -X GET \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/cert > /tmp/cert.pem
$ curl -i -w '\n' -u admin:adminPassphrase -X DELETE \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/cert
HTTP/1.1 204 No Content
content-type: text/html
date: Thu, 20 May 2021 19:14:45 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

Key Certificate Signing Requests

The NetHSM supports generating Certificate Signing Requests (CSR) for the stored keys:

$ curl -s -w '\n' -u operator:opPassphrase -X POST \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/csr.pem -H "content-type: application/json" \
    -d "{ \"countryName\": \"DE\", \"stateOrProvinceName\": \"BE\", \
    \"localityName\": \"Berlin\", \"organizationName\": \"ACME\", \
    \"organizationalUnitName\": \"IT\", \"commonName\": \"example.com\", \
    \"emailAddress\": \"it@example.com\" }" > /tmp/cert.pem

Key Operations

Decryption

We can encrypt data for the key stored on the NetHSM using OpenSSL. (public.pem is the public key file that we created in the Show Key Details section.)

$ echo 'NetHSM rulez!' | OpenSSL rsautl -encrypt -inkey public.pem -pubin | base64 > data.crypt

Now we can use the NetHSM to decrypt the data:

$ curl -s -u operator:opPassphrase -X POST \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/decrypt -H "content-type: application/json" \
    -d "{ \"mode\": \"PKCS1\", \"encrypted\": \"$(cat data.crypt)\"}" | \
    jq -r .decrypted | base64 -d
NetHSM rulez!

Signing

Similarly, we can sign data using the key on the NetHSM. For RSA and ECDSA, we have to calculate a digest first:

$ echo 'NetHSM rulez!' > data
openssl dgst -sha256 -binary data | base64 > data.digest

Then we can create a signature from this digest using the NetHSM:

$ curl -s -u operator:opPassphrase -X POST \
    https://$NETHSM_HOST/api/v1/keys/myFirstKey/sign -H "content-type: application/json" \
    -d "{ \"mode\": \"PSS_SHA256\", \"message\": \"$(cat data.digest)\"}" | \
    jq -r .signature | base64 -d > data.sig

And then use OpenSSL to verify the signature:

openssl dgst -sha256 -verify public.pem -signature data.sig \
-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 data
Verified OK

Backups

It is possible to create a backup of the NetHSM that captures both the configuration and the stored keys. In order to create a backup, you first have to set a backup passphrase that is used to encrypt the backup file:

$ curl -i -w '\n' -u admin:adminPassphrase -X PUT \
    https://$NETHSM_HOST/api/v1/config/backup-passphrase -H "content-type: application/json" \
    -d "{\"passphrase\": \"backupencryptionkey\"}"
HTTP/2 204
server: nginx/1.14.2
date: Sat, 08 May 2021 10:26:36 GMT
cache-control: no-cache
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-frame-options: DENY
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-permitted-cross-domain-policies: none

Now you have to create a user with the R-Backup role:

$ curl -i -w '\n' -u admin:adminPassphrase -X PUT \
    https://$NETHSM_HOST/api/v1/users/backup -H "content-type: application/json" \
    -d "{\"realName\": \"Backup User\", \"role\": \"Backup\", \
    \"passphrase\": \"backupPassphrase\"}"
HTTP/2 201
server: nginx/1.14.2
date: Sat, 08 May 2021 10:30:45 GMT
content-type: application/json
content-length: 0
location: /api/v1/users/backup
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-frame-options: DENY
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-permitted-cross-domain-policies: none

Then can you generate the backup and write it to a file:

$ curl -s -u backup:backupPassphrase -X POST \
    https://$NETHSM_HOST/api/v1/system/backup > /tmp/nethsm-backup

This backup file can be restored on an unprovisioned NetHSM instance:

$ curl -i -X POST \
   "https://$NETHSM_HOST/api/v1/system/restore?backupPassphrase=backupencryptionkey&systemTime=$(date --utc +"%Y-%m-%dT%H:%M:%SZ")" \
   --data-binary @/tmp/nethsm-backup
HTTP/1.1 204 No Content
cache-control: no-cache
content-type: application/json
date: Sat, 08 May 2021 10:59:19 GMT
vary: Accept, Accept-Encoding, Accept-Charset, Accept-Language

Updates

Updates for the NetHSM can be installed in a two-step process. First you have to upload the update image to the NetHSM. The image is then checked and validated. If the validation is successful, the release notes for the update are returned by the NetHSM:

$ curl -i -w '\n' -u admin:adminPassphrase -X POST  \
    https://$NETHSM_HOST/api/v1/system/update --data-binary "@/tmp/nethsm-update.img.cpio"

If you want to continue with the installation, you can now commit the update:

$ curl -i -w '\n' -u admin:adminPassphrase -X POST  \
    https://$NETHSM_HOST/api/v1/system/commit-update

Alternatively, you can cancel the update:

$ curl -i -w '\n' -u admin:adminPassphrase -X POST  \
    https://$NETHSM_HOST/api/v1/system/cancel-update