Rekvirent3

The rekvirent3 API allows communication with reseptformidleren using JWE/JWS as an alternative to WS-Security. The API supports the same message types as the base rekvirent API, however some older message versions are not supported.

To provide mutual certificate binding with JWE wrapped JWS we utilize the x5c claim(https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.6) of the JWS. This MUST be a list containing only the senders certificate. Note that sender in this context is whomever created the JWS. The JWS MUST also be signed with the private key matching the public key of the provided certificate.

For encryption the sender MUST use the public key of the recipient to encrypt the symmetric key. The JWE MUST specify the kid (https://www.rfc-editor.org/rfc/rfc7516#section-4.1.6) used to encrypt.

The kid MUST be the Base64Url encoding of the SHA-256 of the JWK thumbprint. The thumbprint must be on the format defined by RFC7638

Process

Request

  1. Create KITH payload(out-of-scope)
  2. Create a JWS
    • payload: base64 encoded kith
    • cty: application/xml
    • x5c: your X509 certificate, must be the same used to sign the message. The returned JWE will be encrypted using the public key of this certificate
  3. Create a JWE
  4. Prepare HTTP request
    • headers:
      • Content-Type: application/jwt
      • Authorization: DPoP <access_token>
      • DPoP: <proof>

Response

The response follows the same format as the request, with inverted certificates.

The figure below details how to handle the response codes and content-types. Note that RF does not respect the accept  header. In the general case a JWE is returned. For errors that occur before or during authentication or JWE/JWS parsing, a json response is returned. The json payload contains a simple message describing the cause.

{ "message": "an explanation of what went wrong" }

graph TD  
  
response((response))
check_http_status{check-http-status}  
check_content_type{check-content-type}  

response --> check_http_status
check_http_status -->|401,application/json| auth_failure
check_http_status -->|5xx| check_content_type  
check_http_status -->|200,application/jwt| handle_ok_response  
check_http_status -->|others| undefined_behaviour  
  
check_content_type -->|application/json| raw_error  
check_content_type -->|application/jwt| handle_apprec_error
	handle_apprec_error["`
		handle-apprec-error:
		1. JWE/JWS unpack
		2. Decode Apprec
	    3. Handle`"]

Sample implementation

Below is a sample implementation. The implementation is written in java using Nimbus for JWT functionality. Key and certificate material is not provided, the reader should be able to infer the relevant values from the provided sample. Note this sample is not functional, some edits have been made to improve readability.


  public static createRequestPayload() { 
    final RSAKey senderPrivateKey;
    final X509Certificate senderCertificate;
    final X509Certificate recipientCertificate;
	
    final byte[] signedKith = signKith(kithXml);
	// Note: Payload is just a type wrapper used by nimbus
    final Payload payload = new Payload(
        Base64.getEncoder().encode(signedKith));

    try {
      final JWSObject jws = createJWS(payload, senderPrivateKey, senderCertificate);
      final JWEObject jwe = createJWE(jws, recipientCertificate);
      return jwe.serialize();
    } catch (Exception e) {
      throw new RuntimeException("Error creating JWE object: " + e.getMessage(), e);
    }
  }

  private static JWSObject createJWS(
      Payload payload,
      RSAKey senderPrivateKey,
      X509Certificate senderCertificate) throws Exception {

    JWSSigner signer = new RSASSASigner(senderPrivateKey);

    List<String> x5c = new ArrayList<>();
    x5c.add(Base64.getEncoder().encodeToString(senderCertificate.getEncoded()));

    JWSObject jwsObject = new JWSObject(
        new JWSHeader.Builder(JWS_SIGNATURE_ALGORITHM) // e.g. RS256
            .x509CertChain(x5c)
            .contentType("application/xml")
            .build(),
        payload);
    jwsObject.sign(signer);
    return jwsObject;
  }

    private static JWEObject createJWE(
      JWSObject jwsObject,
      X509Certificate recipientCertificate)
      throws Exception {

    RSAKey encryptionKey = new RSAKey.Builder((RSAPublicKey) recipientCertificate.getPublicKey())
        .keyIDFromThumbprint()
        .build();

    JWEEncrypter encrypter = new RSAEncrypter(encryptionKey);
    JWEObject jweObject = new JWEObject(
        new JWEHeader.Builder(JWE_ENCRYPTION_ALGORITHM, JWE_ENCRYPTION_METHOD) // e.g. RSA_OAEP_256, A256GCM
            .keyID(encryptionKey.getKeyID())
            .contentType("JWT")
            .build(),
        new Payload(jwsObject.serialize()));
    jweObject.encrypt(encrypter);

    return jweObject;
  }

Søk i Utviklerportalen

Søket er fullført!