Server JSON Web Key (JWK) set

The Connect2id server needs to be supplied with a set of cryptographic keys to secure the issued tokens and other objects:

  • Access and ID token signing keys -- Public / private key pairs for signing the issued access and ID tokens:

    • RSA key pair of size 2048 bits (note on allowing weak keys).
    • EC key pair with P-256 curve.
    • EC key pair with P-384 curve.
    • EC key pair with P-521 curve.
    • Ed key pair with Ed25519 curve.

    Each key must specify a unique key ID ("kid") and its use must be set to "sig" (signature). The private RSA and EC keys may be stored in a PKCS#11 compliant HSM. The public keys will be published so that clients can download them in order to validate the tokens.

  • Request object encryption keys -- Public / private keys pairs for letting clients encrypt request objects (JAR) to the Connect2id server (may be stored in a PKCS#11 compliant HSM):

    • RSA key pair of size 2048 bits.
    • EC key pair with P-256 curve.
    • EC key pair with P-384 curve.
    • EC key pair with P-521 curve.

    Each key must specify a unique key ID ("kid") and its use must be set to "enc" (encryption). The public keys will be published so that clients can download them in order to encrypt request objects.

  • Access token encryption key -- Optional AES key for applying encryption over the signed access tokens (JWT), in order to provide confidentiality of the token content while in transit. This AES key must be shared securely and out-of-band with all servers which are expected to consume encrypted access tokens. This key must also specify a unique key ID ("kid"). Its use must be set to "enc" (encryption). The supported AES key sizes are 128, 192 and 256 bits.

    If the JWT-encoded access tokens are not going to be encrypted this key can be omitted.

  • Secret HMAC key -- Secret 256-bit key for applying HMAC-SHA-256 protection to the issued session identifiers, authorisation codes, identifier-based access tokens and PAR URIs. This key must have a key ID ("kid") set to "hmac" and its use must be set to "sig" (signature).

  • Refresh token encryption key -- Secret 256-bit key for encrypting refresh token metadata and authenticating the entire refresh token. This key must have a key ID ("kid") set to "refersh-token-encrypt" and its use must be set to "enc" (encryption). Since v8.0.

  • End-user ID encryption key -- Secret 256-bit key for encrypting pairwise subject identifiers with AES in SIV mode. This key must have a key ID ("kid") set to "subject-encrypt" and its use must be set to "enc" (encryption).

Server JWK sets

The main server keys are stored in JSON Web Key Set (JWK set) format in the following file:

WEB-INF/jwkSet.json

The JWK set can be alternatively passed via a jose.jwkSet Java system property. The property value is the JSON representation of the JWK set. Applying additional BASE64URL encoding to the JSON string is recommended, for safe passing of the value in the shell (otherwise all special characters in the JSON must be escaped):

-Djose.jwkSet=eyAia2V5cyIgOiBbIHsgImt0eSIgOiAiUlNBIiwNCiAgICAgICAgICAgICAgIC...

The external configuration guide has tips for setting system properties from environment variables, local files and other locations.

Important

Before you put a Connect server in production you must generate a new JWK set and put it in place of the sample JWK set that comes with the original installation package.

The private and secret keys must be kept secure at all times, and must never be disclosed to other parties!

How to generate a new JWK set

Use the Connect2id JWK generator (download link), by invoking it with the following command line arguments:

java -jar jwkset-gen.jar jwkSet.json

Sample console output:

JWK set generator v1.13 for Connect2id server v6.x+
[1] Generated new signing RSA 2048 bit key with ID K4TU
[2] Generated new signing EC P-256 key with ID BeWg
[3] Generated new signing EC P-384 key with ID b9wV
[4] Generated new signing EC P-521 key with ID CfMy
[5] Generated new signing Ed25519 key with ID Y1Lu
[6] Generated new encryption RSA 2048 bit key with ID 4cxj
[7] Generated new encryption EC P-256 key with ID pOgU
[8] Generated new encryption EC P-384 key with ID 2Bql
[9] Generated new encryption EC P-521 key with ID PFYo
[10] Generated new encryption AES 128 bit key with ID Bokz
[11] Generated new HMAC SHA 256 bit key with ID hmac
[12] Generated new subject encryption AES SIV 256 bit key with ID subject-encrypt
[13] Generated new refresh token encryption AES SIV 256 bit key with ID refresh-token-encrypt

Replace the sample WEB-INF/jwkSet.json file, then restart the server.

If you are passing the JWK set via the jose.jwkSet Java system property on the command line, enable the -b64 option to BASE64URL-encode the JSON (saves the need to escape all special JSON characters in the shell):

java -jar jwkset-gen.jar -b64 jwkSet.json.b64

The Connect2id server performs a check of the JWK set during startup. If a key is found to be missing or non-compliant, the server will log an error message and abort on the spot.

JWK roll-over

To facilitate rollover of the keys used to sign or encrypt the issued tokens, generate a new JWK for each key type, with a new unique identifier ("kid"), and prefix the JWK to the existing JWK set.

The Connect2id server picks the first suitable JWK in the set when it needs to sign or encrypt a token. The remaining public keys in the set will still be published (so clients can still access them to validate tokens secured with an outdated key), but will otherwise not be used by the server.

{
  "keys": [
    { ... place new key here ... },
    { ... old key ... },
    { ... old key ... }
  ]
}

Important: The HMAC-SHA key (kid : hmac) and the subject encryption key (kid : subject-encrypt) must not be updated!

The easiest way to generate a new signing and encryption JWKs and prefix it to an existing JWK set file is to use the JWK generator. The first argument is the existing JWK set file, tne second one the new file with the updated JWK set:

java -jar jwkset-gen.jar jwkSet.json updatedJWKSet.json

Sample console output:

JWK set generator v1.13 for Connect2id server v6.x+
[1] Generated new signing RSA 2048 bit key with ID LODW
[2] Generated new signing EC P-256 key with ID 38xb
[3] Generated new signing EC P-384 key with ID hMvw
[4] Generated new signing EC P-521 key with ID Pzua
[5] Generated new signing Ed25519 key with ID KJTC
[6] Generated new encryption RSA 2048 bit key with ID 9SHE
[7] Generated new encryption EC P-256 key with ID nIvz
[8] Generated new encryption EC P-384 key with ID ZRTL
[9] Generated new encryption EC P-521 key with ID RMx3
[10] Generated new encryption AES 128 bit key with ID mxHh
[11] Prefixed newly generated keys to existing JWK set

To roll-over to the new keys, replace the old WEB-INF/jwkSet.json file, then restart the server.

If you are passing the JWK set via the jose.jwkSet Java system property on the command line, enable the -b64 option to BASE64URL-encode the JSON (saves the need to escape all special JSON characters in the shell):

java -jar -b64 jwkset-gen.jar jwkSet.json updatedJWKSet.json.b64

Tips

The jq utility can be used to extract selected keys from the set.

To extract a JWK with a given kid (key ID), e.g. "subject-encrypt":

cat jwkSet.json | jq '.keys[] | select(.kid=="subject-encrypt")'

To extract the Ed25519 signing key(s):

cat jwkSet.json | jq '.keys[] | select(.kty=="OKP" and .crv=="Ed25519" and .use=="sig")'

To extract the shared encryption key(s) for JWT-encoded access tokens:

cat jwkSet.json | jq '.keys[] | select(.kty=="oct" and .use=="enc" and .kid!="subject-encrypt" and .kid!="refresh-token-encrypt")'

PKIX

An X.509 certificate chain included in a server RSA or EC key (as x5c JWK parameter) will now be exposed in the published public key at the jwks.json endpoint and in the x5c JWT header parameter of JWTs signed with it (ID tokens, self-contained access tokens, etc).

The X.509 certificate chain allows OAuth 2.0 clients to perform PKIX validation of the published key and hence tokens signed with it. Note that the Connect2id server will not perform PKIX validation on a configured JWK if the key includes a certificate chain. Including an "x5c" header in a JWT can also easily multiply its size.

Since v7.15.

Weak 1024 bit RSA keys

The Connect2id server expects to be supplied with 2048 bit RSA keys and if a weaker key is detected it will about startup with an error.

FATAL MAIN - [SE1030] Found weak RSA key(s) shorter than 2048 bits with IDs: [CXup]

To set the Connect2id server up with one more more weak 1024 bit RSA keys, for purposes of migration or key roll-over, edit the following configuration file

WEB-INF/jose.properties

and set the jose.allowWeakKeys property to true. The default value is false.

jose.allowWeakKeys = true

This configuration can also be passed as a Java system property:

-Djose.allowWeakKeys=true

If weak RSA keys are allowed and detected in the JWK set, the Connect2id server will log a warning at startup.

WARN MAIN - [SE1030] Found weak RSA key(s) shorter than 2048 bits with IDs: [CXup]

Since v7.12.

Sample JWK set

{ "keys" : [ { "kty" : "RSA",
               "use" : "sig",
               "kid" : "CXup",
               "n"   : "hrwD-lc-IwzwidCANmy4qsiZk11yp9kHykOuP0yOnwi36VomYTQVEzZXgh2sDJpGgAutdQudgwLoV8tVSsTG9SQHgJjH9Pd_9V4Ab6PANyZNG6DSeiq1QfiFlEP6Obt0JbRB3W7X2vkxOVaNoWrYskZodxU2V0ogeVL_LkcCGAyNu2jdx3j0DjJatNVk7ystNxb9RfHhJGgpiIkO5S3QiSIVhbBKaJHcZHPF1vq9g0JMGuUCI-OTSVg6XBkTLEGw1C_R73WD_oVEBfdXbXnLukoLHBS11p3OxU7f4rfxA_f_72_UwmWGJnsqS3iahbms3FkvqoL9x_Vj3GhuJSf97Q",
               "e"   : "AQAB",
               "d"   : "bmpuqB4PIhJcndRs_i0jOXKjyQzwBXXq2GuWxPEsgFBYx7fFdCuGifQiytMeSEW2OQFY6W7XaqJbXneYMmoI0qTwMQcD91FNX_vlR5he0dNlpZqqYsvVN3c_oT4ENoPUr4GF6L4Jz74gBOlVsE8rvw3MVqrfmbF543ONBJPUt3d1TjKwaZQlgPji-ycGg_P7K-dKxpyfQsC8xMmVmiAF4QQtnUa9vMgiChiO8-6VzGm2yWWyIUVRLxSohrbSNFhqF2zeWXePAw0_nzeZh3IDIMS5ABo92Pry4N3X-X7v_7nf8MGngK4duQ_1UkkLk-3u0I3tk_glsarDN0tYhzPwAQ" },
             { "kty" : "EC",
               "crv" : "P-256",
               "use" : "sig",
               "kid" : "yGvt",
               "d"   : "XnnhYQD6olmXKNQ2mBQ-ZOHEMUpYENnvGDNU3z9VVZ0",
               "x"   : "pvgdqM3RCshljmuCF1D2Ez1w5ei5k7-bpimWLPNeEHI",
               "y"   : "JSmUhbUTqiFclVLEdw6dz038F7Whw4URobjXbAReDuM" },
             { "kty" : "EC",
               "crv" : "P-384",
               "use" : "sig",
               "kid" : "9nHY",
               "d"   : "3zS7ECyMqZlENI9Xk6TqptEbZtoso3LmO4Hc9zs-VytU3Sgd8yHw2uUePAkGv_Fu",
               "x"   : "JPKhjhE0Bj579Mgj3Cn3ERGA8fKVYoGOaV9BPKhtnEobphf8w4GSeigMesL-038W",
               "y"   : "UbJa1QRX7fo9LxSlh7FOH5ABT5lEtiQeQUcX9BW0bpJFlEVGqwec80tYLdOIl59M" },
             { "kty" : "EC",
               "crv" : "P-521",
               "use" : "sig",
               "kid" : "tVzS",
               "x"   : "AZgkRHlIyNQJlPIwTWdHqouw41k9dS3GJO04BDEnJnd_Dd1owlCn9SMXA-JuXINn4slwbG4wcECbctXb2cvdGtmn",
               "y"   : "AdBC6N9lpupzfzcIY3JLIuc8y8MnzV-ItmzHQcC5lYWMTbuM9NU_FlvINeVo8g6i4YZms2xFB-B0VVdaoF9kUswC",
               "d"   : "AAnqLI9s0-hKAXtp0mXQHKoPBMDsnhgeh6HQP-1ScEVMl9-7WcJm2m_msXPyfT0O9Xbh4UDn9wdAi9bqt_4qEEjy" },
             { "kty" : "OKP",
               "crv" : "Ed25519",
               "use" : "sig",
               "kid" : "27zV",
               "x"   : "0I6olrZGYml7JGusuKJW9G7D0DZ9UormSady9kR7V4Q",
               "d"   : "tYXIC35n-nNoVwZ5Rck02ndqFLyYcC8fNwhVFJjWB3c" },
             { "kty" : "RSA",
               "use" : "enc",
               "kid" : "IHMc",
               "n"   : "lLrhwERiPmq7XOz6Rwk8q4ey_OGcL4P56Ip01mzKMUfysIwo-nUdwDI_9ntYohpvqiTjnrtZOENhhoqne5M4hqpSfBMmCWSvWL_3wa8FanRWd6lPgGdKJ1a3vV0gLxnCbmdho1CSuSszV4736WkjdDhLcXSRN1kWwWbok94FdPD_egCyBY3cwhvuRzmUgE8LDh-VnNRh1BYc7e9yEMublza8qJpW-N5ljHEU0on08X-lsyl4djEac74H7taDcmtchPLYZy0-ZIxgLmosQ2aYIt6xycfPYsm5x9CGetUqhClpLLaTcyTGq_pH4ECdZtkYHcYJM-3q-XDZTqB6wUaggw",
               "e"   : "AQAB",
               "d"   : "N_IEMRqICgqD5_SMQGRNGgi1X0JOSeFPBBXw1See9uKle5t9XpjnVACS5tiHApMHJe0yYeb_LJbL_JvzXByIyr8Ov_VD_YyOGMg9HfIEC4Mvc1uQuDAiSKHqA6UgEheSd40TwSbxyg1iBrGUt4wA9hqm5kp-xV8RnDZljhmZ296nVPNNW3aXrqq2FPFn00s2Rh6gJbSTWhg6qQxTSVOO1n601TbWQGlP6mlXdIqXyzlwqwwOCcQIW88ws2jLmY3Hr4Le8nxL20xBACMYjR-9bO0senxbYUcew6GGscyiPe7I5X3P9cpZcRNeERIzsmtin1swvsyCK2cUUCtGpLpN4Q" },
             {
               "kty" : "EC",
               "crv" : "P-256",
               "use" : "enc",
               "kid" : "1yFA",
               "x"   : "_-aKZeuwWDv4v89dPGdKtpOuOepc_0qDZDhcv3omzX0",
               "y"   : "Gc5b7muOqbi4QvYJO24a4IqQoOY1pPM69DcpI605Vmw",
               "d"   : "lFj2hl_0MDs7D3yyTgU6LedcJ7NUZAs6noGzhZszsRA" },
             {
               "kty" : "EC",
               "crv" : "P-384",
               "use" : "enc",
               "kid" : "TqZ6",
               "x"   : "3Ex0yUSLvhaOriP8U78kZEEJXxkC0oQmwo1zHTe_nhgKx2YPS97-qmDdRMkByxJ9",
               "y"   : "MCosrhjIYP4lkoan45MxAZE3QB6IKau5nZHpQ_qDXH8jgcIo2l3M8wdN6iI08kcW",
               "d"   : "W4OifZsTcoIBwBteTM_8fwNKu7xFVlJEzVS-9YfJJK_QenjbedvcqTfzyiwh1b9F" },
             {
               "kty" : "EC",
               "crv" : "P-521",
               "use" : "enc",
               "kid" : "h38C",
               "x"   : "AVMBSexPHgq536pZQjN6Si1HAdUdfiW4xrdYzNHR2A9z4zovnKi5xrQ9hWX8QUs4ejVQ3bE9ufhOYL3D7oTwx9Jb",
               "y"   : "AeMeo858k_6ktxNhlpxBSwGL2hmTI1nBeGi2ZrMVl2qzdjOFf-AVFRSsE9DhAD9sWVUrGrzwONbfmqwIlgbjeH7L",
               "d"   : "AJGiS9ovRl2PrJz8ZSKokMaGXk-nJObJPtPiISPSxFJe1PHJWpEXollGAAYTI8DSiyO4gi7BHGq6T5JGB_zS2TqU" },
             { "kty" : "oct",
               "use" : "enc",
               "kid" : "5C93",
               "k"   : "MaLXergNZ0bec14LDJkXTQ" },
             { "kty" : "oct",
               "use" : "sig",
               "kid" : "hmac",
               "k"   : "m5JZeVoU9lBV6y-d2jNelbjrxwosYjrSGg4STHLLm4g" },
             { "kty" : "oct",
               "use" : "enc",
               "kid" : "subject-encrypt",
               "k"   : "QA4js08rUQsZfEoEoxu6LGgJgbHdmPG08XCKYSJTNJ0" },
             { "kty" : "oct",
               "use" : "enc",
               "kid" : "refresh-token-encrypt",
               "k"   : "pNzHVtVWJ8oluOGvesrmLgyVEVCkT6Os5f8e2PFEK9Y" } ] }

Hardware Security Module (HSM) for signing tokens

The Connect2id server can use PKCS#11 compliant HSMs to sign the issued ID and self-contained (JWT) access tokens.

The JWK set utilised by the Connect2id server can be composed of HSM-based keys as well as plain file-based keys.

HSM configuration

To enable HSM support edit the configuration properties in the following file:

WEB-INF/jose.properties

pkcs11.enable

Enables / disables PKCS#11 HSM support. HSM support is normally disabled, to enable it set the property to true.

pkcs11.enable = false

pkcs11.configFile

The location of the Sun PKCS#11 provider configuration:

pkcs11.configFile = /WEB-INF/hsm.cfg

This configuration specifies the driver to load for the HSM device, a slot number for it (as multiple HSM devices may be attached), plus additional attributes. These are explained in the Sun PKCS#11 provider documentation. The manual of your HSM device should also provide information.

Sample hsm.cfg:

name = NitroKeyHSM
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
slotListIndex = 1
attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = {
  CKA_SIGN = true
}

pkcs11.password

The password (PIN) required to unlock the HSM.

pkcs11.password = 648219

Any configuration file property can be overridden via a Java system property, e.g. by setting the optional -D argument at JVM startup:

-Dpkcs11.password=123456

Generating keys on the HSM

The HSM must be provisioned with the required keys before it can be used by the Connect2id server.

  • For signing tokens with an RSA key, provision one or more RSA keys on the HSM. The RSA keys must be 1024 or 2048 bits long.

  • For signing tokens with an EC key, provision one or more EC keys with curve P-256 (for JWS algorithm ES256), P-384 (for ES384) and / or P-521 (for ES512). Note that some HSM devices have limited EC support, so make sure you check this with the manufacturer.

  • Each private key must be given a unique alias (identifier).

  • Each private key must be paired with an X.509 certificate. The certificate can be self-signed, or signed by a CA. Its not-before and not-after attributes delimit the time during which the private key will be used for signing by the Connect2id server. When the certificate of the currently selected private key expires, the Connect2id server will automatically roll over to the next available valid key. If no such key is found on the HSM, the Connect2id server will log an error, and continue signing tokens with an existing key (to prevent service downtime).

    ERROR [SE2000] Couldn't find signing PKCS#11 key with a X.509 certificate that is valid at this time instant, using first available key. Consider adding new key(s) to the PKCS#11 store!
    
  • The certificate validity windows for each key type should overlap by a little, so the Connect2id server can smoothly roll over from an expiring key to the next, and no SE2000 errors get logged.

  • The public RSA and EC keys from the HSM will be published in JWK format by the Connect2id server. Their X.509 certificates will not be included in the JWK x5c parameter.

  • Make sure the HSM can maintain an RSA or EC signing rate that matches the usage requirements of the IdP service.

Debugging HSM issues

The Connect2id server logs the loading of the HSM device and which keys in it are selected for signing. Keys that don't match the server requirements, in terms of key type, use or size, will be omitted.

INFO MAIN - [SE0001] JOSE configuration: PKCS#11 enabled: true
INFO MAIN - [SE0002] JOSE configuration: PKCS#11 configuration file: /WEB-INF/hsm.cfg
INFO MAIN - [SE0003] JOSE configuration: PKCS#11 password: true
INFO MAIN - [SE1001] Loaded JWK set file with 7 keys: /WEB-INF/jwkSet.json
INFO MAIN - [SE1006] Loaded PKCS#11 provider SunPKCS11-NitroKeyHSM
INFO MAIN - [SE1007] Loaded PKCS#11 key store with 2 entries
INFO MAIN - [SE1009] Extracted JWK set with 2 keys from PKCS#11 key store SunPKCS11-NitroKeyHSM
DEBUG MAIN - [SE1010] Assuming signature key use for RSA PKCS#11 JWK with ID 1
DEBUG MAIN - [SE1010] Assuming signature key use for RSA PKCS#11 JWK with ID 2
INFO MAIN - [SE1008] Loaded JWK set:
INFO MAIN - [SE3000] [1] JWK type=RSA id=1 private=true use=sig size=2048 pkcs#11=true nbf=2017-01-30T11:47:41Z exp=2017-02-28T11:47:41Z
INFO MAIN - [SE3000] [2] JWK type=RSA id=2 private=true use=sig size=2048 pkcs#11=true nbf=2017-01-30T11:51:23Z exp=2017-02-28T11:51:23Z
INFO MAIN - [SE3000] [3] JWK type=RSA id=CXup private=true use=sig size=2048 pkcs#11=false 
INFO MAIN - [SE3000] [4] JWK type=EC id=yGvt private=true use=sig size=256 pkcs#11=false 
INFO MAIN - [SE3000] [5] JWK type=EC id=9nHY private=true use=sig size=384 pkcs#11=false 
INFO MAIN - [SE3000] [6] JWK type=EC id=tVzS private=true use=sig size=521 pkcs#11=false 
INFO MAIN - [SE3000] [7] JWK type=oct id=5C93 use=enc size=128 pkcs#11=false 
INFO MAIN - [SE3000] [8] JWK type=oct id=hmac use=sig size=256 pkcs#11=false 
INFO MAIN - [SE3000] [9] JWK type=oct id=subject-encrypt use=enc size=256 pkcs#11=false 

Assistance

If you need help with setting up your JWK set, get in touch with Connect2id support.