Connect2id server 7.14 supports encrypted request objects

Posted 2019-07-16

We are delighted to announce support for encrypted request objects (JARs) in Connect2id server 7.14.

1. Encrypted request objects

OAuth 2.0 clients and OpenID relying parties can now submit authorisation requests to the server which parameters are kept confidential from the browser and end-user. The authorisation requests can be directly encrypted with JSON Web Encryption (JWE), or after signing them with JWS.

1.1 JWE algorithms

The following standard JWE algorithms are supported:

  • RSA encryption with RSA-OAEP-256, RSA-OAEP and RSA1_5. Note that use of RSA-PKCS1 v1.5 is no longer recommended and RSA-OAEP-256 should be used instead of RSA-OAEP.

  • ECDH encryption with ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW and ECDH-ES+A256KW.

  • AES 128, 192 and 256 bit encryption (dir) with a symmetric key derived from the client secret.

Two new configuration properties were introduced to set the enabled JWE algorithms and content encryption methods:

If the two configuration properties aren't set the Connect2id server will not accept encrypted request objects.

1.2 Server JWK set

If you intend to support public key encrypted request objects update the server JWK set to include the required RSA and EC encryption keys.

The public encryption keys will be published together with the public signing keys (for JWT validation), so clients that intend to submit RSA or ECDH encrypted authorisation requests can download them.

The server JWK set generator was updated to support creation and rotation of RSA and EC (P-256, P-384 and P-521 curve) encryption keys (v1.9).

Example EC key pair with P-256 curve marked for encryption use:

{
  "kty" : "EC",
  "crv" : "P-256",
  "use" : "enc",
  "kid" : "1yFA",
  "x"   : "_-aKZeuwWDv4v89dPGdKtpOuOepc_0qDZDhcv3omzX0",
  "y"   : "Gc5b7muOqbi4QvYJO24a4IqQoOY1pPM69DcpI605Vmw",
  "d"   : "lFj2hl_0MDs7D3yyTgU6LedcJ7NUZAs6noGzhZszsRA"
}

If only direct (dir) AES encryption based on client secrets is going to be used there is no need to generate and publish public RSA and EC encryption keys.

1.3 Client registration

Clients that intend to use encrypted request objects should declare that in their registration. Clients may also submit encrypted requests without explicitly registering for that, however, the registration gives them the opportunity to have the JWE algorithm parameters checked by the server.

Example client registration for RSA-OAEP-256 public key encryption with A128GCM content encryption:

POST /c2id/clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris"                 : [ "https://client.example.org/callback" ],
  "jwks_uri"                      : "https://client.example.org/jwks.json",
  "request_object_encryption_alg" : "RSA-OAEP-256",
  "request_object_encryption_enc" : "A128GCM"
}

Example client registration for dir AES 128 bit encryption with a key derived from the client secret.

POST /c2id/clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris"                 : [ "https://client.example.org/callback" ],
  "jwks_uri"                      : "https://client.example.org/jwks.json",
  "request_object_encryption_alg" : "dir",
  "request_object_encryption_enc" : "A128GCM"
}

1.4 Making encrypted requests

In order to submit an encrypted request object the OAuth 2.0 client needs to download the server JWK set and extract a public encryption keys from it that matches the desired JWE algorithm.

The request parameters are then encoded as claims into a JWT which is encrypted.

The following example using the open source OAuth 2.0 / OpenID Connect SDK that we maintain for the community shows how to do that, starting from the OpenID provider URL to discover all necessary endpoints and parameters.

import java.net.URI;
import java.util.List;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jwt.*;
import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.client.*;
import com.nimbusds.oauth2.sdk.http.*;
import com.nimbusds.oauth2.sdk.id.*;
import com.nimbusds.oauth2.sdk.token.*;
import com.nimbusds.openid.connect.sdk.*;
import com.nimbusds.openid.connect.sdk.op.*;

// Need OP issuer URL and access token for the registration as minimum
Issuer opIssuer = new Issuer("https://demo.c2id.com/c2id");
BearerAccessToken regEndpointToken = new BearerAccessToken("ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6");

// Download OpenID provider metadata and JWK set
OIDCProviderMetadata opMetadata = OIDCProviderMetadata.resolve(opIssuer);
JWKSet opJWKSet = JWKSet.load(opMetadata.getJWKSetURI().toURL());

// Will use RSA-OAEP-256 and A128GCM encryption
assert opMetadata.getRequestObjectJWEAlgs().contains(JWEAlgorithm.RSA_OAEP_256);
assert opMetadata.getRequestObjectJWEEncs().contains(EncryptionMethod.A128GCM);

// Register client
ClientMetadata clientMetadata = new ClientMetadata();
clientMetadata.setRedirectionURI(URI.create("https://example.com/cb"));
clientMetadata.setRequestObjectJWEAlg(JWEAlgorithm.RSA_OAEP_256);
clientMetadata.setRequestObjectJWEEnc(EncryptionMethod.A128GCM);
clientMetadata.applyDefaults();

HTTPResponse httpResponse = new ClientRegistrationRequest(
    opMetadata.getRegistrationEndpointURI(),
    clientMetadata,
    regEndpointToken)
    .toHTTPRequest()
    .send();

ClientRegistrationResponse regResponse = ClientRegistrationResponse.parse(httpResponse);

if (! regResponse.indicatesSuccess()) {
    System.err.println(regResponse.toErrorResponse().getErrorObject());
    return;
}

ClientInformation clientInfo = regResponse.toSuccessResponse().getClientInformation();

assert clientInfo.getMetadata().getRequestObjectJWEAlg().equals(JWEAlgorithm.RSA_OAEP_256);
assert clientInfo.getMetadata().getRequestObjectJWEEnc().equals(EncryptionMethod.A128GCM);

// Select public RSA encryption key from OP JWK set
List<JWK> rsaJWKs = new JWKSelector(new JWKMatcher.Builder()
    .keyType(KeyType.RSA)
    .keyUse(KeyUse.ENCRYPTION)
    .build())
    .select(opJWKSet);

if (rsaJWKs.isEmpty()) {
    System.err.println("No RSA encryption key(s) found in OP JWK set");
    return;
}

// Create encrypted OpenID auth request
RSAKey rsaJWK = (RSAKey)rsaJWKs.get(0); // use the first encryption key

EncryptedJWT jar = new EncryptedJWT(
    new JWEHeader.Builder(
        clientInfo.getMetadata().getRequestObjectJWEAlg(),
        clientInfo.getMetadata().getRequestObjectJWEEnc())
        .keyID(rsaJWK.getKeyID())
        .build(),
    new AuthenticationRequest.Builder(
        new ResponseType("code"),
        new Scope("openid"),
        clientInfo.getID(),
        clientInfo.getMetadata().getRedirectionURI())
        .state(new State())
        .build()
        .toJWTClaimsSet());
jar.encrypt(new RSAEncrypter(rsaJWK));

AuthenticationRequest authRequest = new AuthenticationRequest.Builder(jar)
    .endpointURI(opMetadata.getAuthorizationEndpointURI())
    .build();

// Output the OpenID auth request
System.out.println(authRequest.toURI());

Learn more about request objects and their use in our excellent article.

2. Other features

The Connect2id server SDK was updated to v4.5 and now exposes an additional method in the ClaimsSourceRequestContext to find out how the sourced OpenID claims are going to be delivered - at the UserInfo endpoint or included in the ID token.

3. Resolved issues

The 7.14 release fixes a number of bugs related to request object processing, also a significant bug that prevented correct loading of JWK sets configured via the "jose.jwkSet" Java system property. Deployments that use this method to configure the server keys (instead of the regular WEB-INF/jwkSet.json) should update to 7.14.

There is more information in the release notes below.

Download

To download a ZIP package of Connect2id server 7.14:

https://connect2id.com/assets/products/server/download/7.14/Connect2id-server.zip

SHA-256: b4ce85678ee218e615aba0198d0d7649551887dcaa5a7f82e538f836caf3114a

As WAR package only:

https://connect2id.com/assets/products/server/download/7.14/c2id.war

SHA-256: c58b40906c6baa8e3369b2a7687fcbd02b20aedb4cabae64807984352db108e0

Questions?

Contact Connect2id support.


Release notes

7.14 (2019-07-15)

General

  • Support for encrypted (JWE) request objects passed with the optional OAuth 2.0 request or request_uri authorisation request parameter. Supported are RSA (RSA-OAEP-256, RSA-OAEP, RSA1_5) and ECDH (ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW) public key encryption as well as shared key encryption (dir) with an AES key derived from the client's secret.

    Clients can obtain the public encryption keys (with use=enc) from the Connect2id server JWK set endpoint.

    Clients must include their client_id as top-level authorisation request parameter when submitting request objects encrypted with an AES key derived from the client's secret, to enable the Connect2id server to lookup the secret.

    The JWK set generator for the Connect2id server was updated to support public encryption keys, see https://bitbucket.org/connect2id/server-jwkset-gen

    Processing of encrypted request objects conforms with the "OpenID Connect 1.0" and "The OAuth 2.0 Authorization Framework: JWT Secured Authorization Request (JAR)" (draft-ietf-oauth-jwsreq-19) specifications.

Configuration

  • /WEB-INF/jwkSet.json

    • Includes public RSA (2048 bit) and EC (P-256, P-384 and P-521) JSON Web Keys (JWK) with key use set to encryption (use=enc) for OAuth 2.0 clients to encrypt request objects to the Connect2id server. The presence of public encryption JWKs in the set is optional. Rotation is supported by prefixing new public encryption keys to the set (clients should use the first encryption key that matches the desired JWE algorithm).
  • /WEB-INF/oidcProvider.properties

    • op.authz.requestJWEAlgs -- New optional configuration property listing the accepted JWE algorithms for encrypted OAuth 2.0 authorisation requests passed with the optional request_uri or request parameter. The default value is none.

      The following standard JWE algorithms are supported:

      • RSA-OAEP-256
      • RSA-OAEP (use no longer recommended)
      • RSA1_5 (use no longer recommended)
      • ECDH-ES
      • ECDH-ES+A128KW
      • ECDH-ES+A192KW
      • ECDH-ES+A256KW
      • dir
    • op.authz.requestJWEEncs -- New optional configuration property listing the accepted JWE content encryption methods for encrypted OAuth 2.0 authorisation requests passed with the optional request_uri or request parameter. The default value is none.

      The following standard JWE methods are supported:

      • A128CBC-HS256
      • A192CBC-HS384
      • A256CBC-HS512
      • A128GCM
      • A192GCM
      • A256GCM

SPI

  • com.nimbusds.openid.connect.provider.spi.claims.AdvancedClaimsSource

    • Adds a new getClaimsTransport() method to the ClaimsSourceRequestContext to indicate how the OpenID claims are retrieved by the relying party. Returns "USERINFO" for the UserInfo endpoint, "ID_TOKEN" for including the claims in the issued ID token, and null if not applicable (the claims source SPI is invoked for another purpose, for example in a TokenEncoderContext).

Resolved issues

  • Fixes a bug which prevented loading of Connect2id server keys overridden or passed via the "jose.jwkSet" Java system property. Deployments that rely on loading the server JWK set via the "jose.jwkSet" Java system property must upgrade. The bug did not affect the multi-tenant Connect2id server edition (issue server/471).

  • OAuth 2.0 clients not explicitly registered for "request_object_signing_alg" must be able to use any supported JWS algorithm for signed request objects (JAR), provided the client has registered the necessary key material (public key or client secret) (issue server/469).

  • Remote JWK set (jwks_uri) sourcing errors when processing signed request objects should result in invalid_request_object error, not HTTP 500 (issue server/474).

  • When processing signed request objects a failed client JWK to Java key conversion should result in invalid_request_object error, not HTTP 500.

  • When serving UserInfo requests the "openid" scope value becomes required for the access tokens. Previously the UserInfo endpoint only checked that the access token permitted release of one or more OpenID claims. The OpenID scope values "profile", "email", "address" and "phone" will continue to be ignored in order to comply with data minimisation principles (issue server/473).

  • Updates the SQL DB connector to output a more detailed stack trace when parsing a corrupt JSON field in a SQL record.

Dependency changes

  • Upgrades to com.nimbusds:c2id-server-sdk:4.5

  • Upgrades to com.nimbusds:nimbus-jose-jwt:7.4

  • Updates to com.nimbusds:nimbus-jwkset-loader:4.2

  • Updates to com.nimbusds:oidc-session-store:12.0.1

  • Updates to com.nimbusds:infinispan-cachestore-sql:3.1.3