summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorminfrin <minfrin@13f79535-47bb-0310-9956-ffa450edef68>2018-09-01 19:42:30 +0000
committerminfrin <minfrin@13f79535-47bb-0310-9956-ffa450edef68>2018-09-01 19:42:30 +0000
commitbf0caa99b0c090fa378f4ae105f85e67219841a9 (patch)
tree94e5fc011e58f700a1fb26977614ce896bfb9d2e
parent7fd4cb5008723644deed190e46aeffd2b2ad7e6f (diff)
downloadlibapr-bf0caa99b0c090fa378f4ae105f85e67219841a9.tar.gz
Add header and tests for JOSE support. I need sleep.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1839838 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--include/apr_jose.h1139
-rw-r--r--test/testjose.c1423
2 files changed, 2562 insertions, 0 deletions
diff --git a/include/apr_jose.h b/include/apr_jose.h
new file mode 100644
index 000000000..7389d74ae
--- /dev/null
+++ b/include/apr_jose.h
@@ -0,0 +1,1139 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file apr_jose.h
+ * @brief APR-UTIL JSON Object Signing and Encryption Library
+ */
+#ifndef APR_JOSE_H
+#define APR_JOSE_H
+
+/**
+ * @defgroup APR_Util_JOSE JSON Object Signing and Encryption
+ * @ingroup APR_Util
+ * @{
+ *
+ * The JOSE (JSON Object Signing and Encryption) library allows the encoding
+ * and decoding of JWS (JSON Web Signature), JWE (JSON Web Encryption), JWK
+ * (JSON Web Key) and JWT (JSON Web Token) objects, encoded using compact
+ * encoding, JSON encoding, or flattened JSON encoding.
+ *
+ * The following RFCs are supported:
+ *
+ * - https://tools.ietf.org/html/rfc7515 - JSON Web Signature (JWS)
+ * - https://tools.ietf.org/html/rfc7516 - JSON Web Encryption (JWE)
+ * - https://tools.ietf.org/html/rfc7517 - JSON Web Key (JWK)
+ * - https://tools.ietf.org/html/rfc7519 - JSON Web Token (JWT)
+ *
+ * Encryption, decryption, signing and verification are implemented as
+ * callbacks to the caller's specification, and are not included.
+ *
+ * When decrypting or verifying, the caller MUST verify that the 'alg'
+ * algorithm parameter in the JOSE message matches the algorithm expected
+ * by the implementation.
+ *
+ * It is recommended that the apr_crypto library be used to implement the
+ * callbacks, however an alternatively crypto library of the caller's choice
+ * may be used instead.
+ */
+#include "apr.h"
+#include "apr_pools.h"
+#include "apu_errno.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_json.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @package Apache JOSE library
+ *
+ */
+
+/**
+ * HMAC using SHA-256
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_HS256 "HS256"
+
+/**
+ * HMAC using SHA-384
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_HS384 "HS384"
+
+/**
+ * HMAC using SHA-512
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_HS512 "HS512"
+
+/**
+ * RSASSA-PKCS1-v1_5 using SHA-256
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_RS256 "RS256"
+
+/**
+ * RSASSA-PKCS1-v1_5 using SHA-384
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_RS384 "RS384"
+
+/**
+ * RSASSA-PKCS1-v1_5 using SHA-512
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_RS512 "RS512"
+
+/**
+ * ECDSA using P-256 and SHA-256
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_ES256 "ES256"
+
+/**
+ * ECDSA using P-384 and SHA-384
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_ES384 "ES384"
+
+/**
+ * ECDSA using P-512 and SHA-512
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_ES512 "ES512"
+
+/**
+ * RSASSA-PSS using SHA-256 and MGF1 with SHA-256
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_PS256 "PS256"
+
+/**
+ * RSASSA-PSS using SHA-384 and MGF1 with SHA-384
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_PS384 "PS384"
+
+/**
+ * RSASSA-PSS using SHA-512 and MGF1 with SHA-512
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_PS512 "PS512"
+
+/**
+ * No digital signature or MAC performed
+ *
+ * https://tools.ietf.org/html/rfc7518#section-3.1
+ */
+#define APR_JOSE_JWA_NONE "none"
+
+/**
+ * "kty" (Key Type) Parameter
+ *
+ * https://tools.ietf.org/html/rfc7517#section-4.1
+ */
+#define APR_JOSE_JWK_KEY_TYPE "kty"
+
+/**
+ * "use" (Public Key Use) Parameter
+ *
+ * https://tools.ietf.org/html/rfc7517#section-4.2
+ */
+#define APR_JOSE_JWK_PUBLIC_KEY_USE "use"
+
+/**
+ * "key_ops" (Key Operations) Parameter
+ *
+ * https://tools.ietf.org/html/rfc7517#section-4.3
+ */
+#define APR_JOSE_JWK_KEY_OPERATIONS "key_ops"
+
+/**
+ * "keys" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7517#section-5.1
+ */
+#define APR_JOSE_JWK_KEYS "keys"
+
+/**
+ * "alg" (Algorithm) Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.1
+ * https://tools.ietf.org/html/rfc7516#section-4.1.1
+ * https://tools.ietf.org/html/rfc7517#section-4.4
+ */
+#define APR_JOSE_JWKSE_ALGORITHM "alg"
+
+/**
+ * "enc" (Encryption Algorithm) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-4.1.2
+ */
+#define APR_JOSE_JWE_ENCRYPTION "enc"
+
+/**
+ * "zip" (Compression Algorithm) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-4.1.3
+ */
+#define APR_JOSE_JWE_COMPRESSION "zip"
+
+/**
+ * "jku" (JWK Set URL) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.2
+ * https://tools.ietf.org/html/rfc7516#section-4.1.4
+ */
+#define APR_JOSE_JWSE_JWK_SET_URL "jku"
+
+/**
+ * "jwk" (JSON Web Key) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.3
+ * https://tools.ietf.org/html/rfc7516#section-4.1.5
+ */
+#define APR_JOSE_JWSE_JWK "jwk"
+
+/**
+ * "kid" (Key ID) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.4
+ * https://tools.ietf.org/html/rfc7516#section-4.1.6
+ */
+#define APR_JOSE_JWKSE_KEYID "kid"
+
+/**
+ * "x5u" (X.509 URL) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.5
+ * https://tools.ietf.org/html/rfc7516#section-4.1.7
+ */
+#define APR_JOSE_JWKSE_X509_URL "x5u"
+
+/**
+ * "x5c" (X.509 Certificate Chain) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.6
+ * https://tools.ietf.org/html/rfc7516#section-4.1.8
+ */
+#define APR_JOSE_JWKSE_X509_CHAIN "x5c"
+
+/**
+ * "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.7
+ * https://tools.ietf.org/html/rfc7516#section-4.1.9
+ */
+#define APR_JOSE_JWKSE_X509_SHA1_THUMBPRINT "x5t"
+
+/**
+ *"x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Header
+ * Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.8
+ * https://tools.ietf.org/html/rfc7516#section-4.1.10
+ */
+#define APR_JOSE_JWKSE_X509_SHA256_THUMBPRINT "x5t#S256"
+
+/**
+ * "typ" (Type) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.9
+ * https://tools.ietf.org/html/rfc7516#section-4.1.11
+ */
+#define APR_JOSE_JWSE_TYPE "typ"
+
+/**
+ * "cty" (Content Type) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.10
+ * https://tools.ietf.org/html/rfc7516#section-4.1.12
+ */
+#define APR_JOSE_JWSE_CONTENT_TYPE "cty"
+
+/**
+ * "crit" (Critical) Header Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-4.1.11
+ * https://tools.ietf.org/html/rfc7516#section-4.1.13
+ */
+#define APR_JOSE_JWSE_CRITICAL "crit"
+
+/**
+ * "payload" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-7.2.1
+ */
+#define APR_JOSE_JWS_PAYLOAD "payload"
+
+/**
+ * "signatures" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-7.2.1
+ */
+#define APR_JOSE_JWS_SIGNATURES "signatures"
+
+/**
+ * "protected" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-7.2.1
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWSE_PROTECTED "protected"
+
+/**
+ * "header" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-7.2.1
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWSE_HEADER "header"
+
+/**
+ * "signature" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7515#section-7.2.1
+ */
+#define APR_JOSE_JWS_SIGNATURE "signature"
+
+/**
+ * "unprotected" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_UNPROTECTED "unprotected"
+
+/**
+ * "ciphertext" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_CIPHERTEXT "ciphertext"
+
+/**
+ * "recipients" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_RECIPIENTS "recipients"
+
+/**
+ * "encrypted_key" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_EKEY "encrypted_key"
+
+/**
+ * "iv" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_IV "iv"
+
+/**
+ * "tag" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_TAG "tag"
+
+/**
+ * "aad" Parameter
+ *
+ * https://tools.ietf.org/html/rfc7516#section-7.2.1
+ */
+#define APR_JOSE_JWE_AAD "aad"
+
+/**
+ * "iss" (Issuer) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.1
+ */
+#define APR_JOSE_JWT_ISSUER "iss"
+
+/**
+ * "sub" (Subject) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.2
+ */
+#define APR_JOSE_JWT_SUBJECT "sub"
+
+/**
+ * "aud" (Audience) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.3
+ */
+#define APR_JOSE_JWT_AUDIENCE "aud"
+
+/**
+ * "exp" (Expiration Time) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.4
+ */
+#define APR_JOSE_JWT_EXPIRATION_TIME "exp"
+
+/**
+ * "nbf" (Not Before) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.5
+ */
+#define APR_JOSE_JWT_NOT_BEFORE "nbf"
+
+/**
+ * "iat" (Issued At) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.6
+ */
+#define APR_JOSE_JWT_ISSUED_AT "iat"
+
+/**
+ * "jti" (JWT ID) Claim
+ *
+ * https://tools.ietf.org/html/rfc7519#section-4.1.7
+ */
+#define APR_JOSE_JWT_ID "jti"
+
+/**
+ * "typ" (Type) Header Parameter representing a JWT
+ *
+ * https://tools.ietf.org/html/rfc7519#section-5.1
+ */
+#define APR_JOSE_JWSE_TYPE_JWT "JWT"
+
+/**
+ * Default options.
+ */
+#define APR_JOSE_FLAG_NONE 0
+
+/**
+ * Return the full JOSE structure, instead of innermost nested structure.
+ */
+#define APR_JOSE_FLAG_DECODE_ALL 1
+
+/**
+ * When verifying or decrypting, break out of processing.
+ *
+ * If the verification or decryption failed, processing will be aborted
+ * with the given error.
+ *
+ * If the verification or decryption succeeded, processing will be considered
+ * successful and will move on to the nested structure.
+ */
+#define APR_JOSE_FLAG_BREAK 2
+
+/**
+ * Forward declaration of the apr_jose_t structure.
+ */
+typedef struct apr_jose_t apr_jose_t;
+
+/**
+ * Enum that represents the type of JOSE object.
+ */
+typedef enum apr_jose_type_e {
+ /** No specific type. */
+ APR_JOSE_TYPE_NONE = 0,
+ /** JSON Web Key (JWK) */
+ APR_JOSE_TYPE_JWK = 1,
+ /** JSON Web Key Set (JWKS) */
+ APR_JOSE_TYPE_JWKS,
+ /** JSON Web Signature (JWS) - compact encoding */
+ APR_JOSE_TYPE_JWS,
+ /** JSON Web Signature (JWS) - JSON encoding */
+ APR_JOSE_TYPE_JWS_JSON,
+ /** JSON Web Encryption (JWE) - compact encoding */
+ APR_JOSE_TYPE_JWE,
+ /** JSON Web Encryption (JWE) - JSON encoding */
+ APR_JOSE_TYPE_JWE_JSON,
+ /** JSON Web Token (JWT) */
+ APR_JOSE_TYPE_JWT,
+ /** Generic binary data */
+ APR_JOSE_TYPE_DATA,
+ /** Generic text data */
+ APR_JOSE_TYPE_TEXT,
+ /** Generic JSON structure */
+ APR_JOSE_TYPE_JSON
+} apr_jose_type_e;
+
+/**
+ * Unsigned char data of a given length
+ */
+typedef struct apr_jose_data_t {
+ /** Pointer to the data */
+ const unsigned char *data;
+ /** Length of the data */
+ apr_size_t len;
+} apr_jose_data_t;
+
+/**
+ * Signed char data of a given length
+ */
+typedef struct apr_jose_text_t {
+ /** Pointer to the text */
+ const char *text;
+ /** Length of the text */
+ apr_size_t len;
+} apr_jose_text_t;
+
+/**
+ * JSON object
+ */
+typedef struct apr_jose_json_t {
+ /** Parsed JSON structure. */
+ apr_json_value_t *json;
+} apr_jose_json_t;
+
+/**
+ * A JSON web key
+ */
+typedef struct apr_jose_jwk_t {
+ /** Parsed JWK JSON structure */
+ apr_json_value_t *key;
+} apr_jose_jwk_t;
+
+/**
+ * A JSON web key set
+ */
+typedef struct apr_jose_jwks_t {
+ /** Parsed JWK set JSON structure containing a JSON array */
+ apr_json_value_t *keys;
+} apr_jose_jwks_t;
+
+/**
+ * A single signature within a a JSON web signature.
+ */
+typedef struct apr_jose_signature_t {
+ /** JWS Header */
+ apr_json_value_t *header;
+ /** JWS Protected Header */
+ apr_json_value_t *protected_header;
+ /** JWS Signature */
+ apr_jose_data_t sig;
+ /** Result of verification for this signature */
+ apr_status_t status;
+} apr_jose_signature_t;
+
+/**
+ * A JSON web signature
+ */
+typedef struct apr_jose_jws_t {
+ /** JWS Compact / Flattened Signature */
+ apr_jose_signature_t *signature;
+ /** JWS General Signatures */
+ apr_array_header_t *signatures;
+ /** JWS Payload */
+ apr_jose_t *payload;
+} apr_jose_jws_t;
+
+/**
+ * An encrypted payload within a a JSON web encryption.
+ */
+typedef struct apr_jose_encryption_t {
+ /** JWE Shared Header */
+ apr_json_value_t *unprotected;
+ /** JWE Protected Header */
+ apr_json_value_t *protected;
+ /** JWE Protected Header (basde64url) */
+ apr_jose_text_t protected64;
+ /** JWE Initialization Vector */
+ apr_jose_data_t iv;
+ /** JWE AAD */
+ apr_jose_data_t aad;
+ /** JWE AAD (base64url)*/
+ apr_jose_text_t aad64;
+ /** JWE Ciphertext */
+ apr_jose_data_t cipher;
+ /** JWE Authentication Tag */
+ apr_jose_data_t tag;
+} apr_jose_encryption_t;
+
+/**
+ * A single recipient within a a JSON web encryption.
+ */
+typedef struct apr_jose_recipient_t {
+ /** JWE Header */
+ apr_json_value_t *header;
+ /** JWE Encrypted Key */
+ apr_jose_data_t ekey;
+ /** Result of decryption for this recipient */
+ apr_status_t status;
+} apr_jose_recipient_t;
+
+/**
+ * A JSON web encryption
+ */
+typedef struct apr_jose_jwe_t {
+ /** JWE Compact / Flattened Recipient */
+ apr_jose_recipient_t *recipient;
+ /** JWE General Recipients */
+ apr_array_header_t *recipients;
+ /** JWE Encryption Parameters */
+ apr_jose_encryption_t *encryption;
+ /** JWE Payload */
+ apr_jose_t *payload;
+} apr_jose_jwe_t;
+
+/**
+ * A JSON web token
+ */
+typedef struct apr_jose_jwt_t {
+ /** Claims associated with the JWT. */
+ apr_json_value_t *claims;
+} apr_jose_jwt_t;
+
+/**
+ * One JOSE structure to rule them all.
+ */
+struct apr_jose_t {
+ /** pool used for allocation */
+ apr_pool_t *pool;
+ /** content type of this structure */
+ const char *typ;
+ /** content type of the payload */
+ const char *cty;
+ /** result of the operation */
+ apu_err_t result;
+ /** type of the value */
+ apr_jose_type_e type;
+ /** actual value, depending on the type */
+ union {
+ apr_jose_jwk_t *jwk;
+ apr_jose_jwks_t *jwks;
+ apr_jose_jws_t *jws;
+ apr_jose_jwe_t *jwe;
+ apr_jose_jwt_t *jwt;
+ apr_jose_data_t *data;
+ apr_jose_text_t *text;
+ apr_jose_json_t *json;
+ } jose;
+};
+
+/**
+ * Callbacks for encryption, decryption, signing and verifying.
+ */
+typedef struct apr_jose_cb_t {
+ /**
+ * Callback that encrypts the content of the bucket brigade bb based
+ * on the parameters provided by the jwe->protected_header, and writes
+ * the resulting encrypted key to recipient->ekey, the initialisation vector
+ * to encryption->iv, the additional authentication data to encryption->aad, the
+ * cipher text to encryption->cipher, and the tag to encryption->tag.
+ *
+ * The encrypt function is expected to perform some or all of the
+ * following steps:
+ *
+ * 1. Determine the Key Management Mode employed by the algorithm used
+ * to determine the Content Encryption Key value. (This is the
+ * algorithm recorded in the "alg" (algorithm) Header Parameter of
+ * the resulting JWE.)
+ *
+ * 2. When Key Wrapping, Key Encryption, or Key Agreement with Key
+ * Wrapping are employed, generate a random CEK value. See RFC
+ * 4086 [RFC4086] for considerations on generating random values.
+ * The CEK MUST have a length equal to that required for the
+ * content encryption algorithm.
+ *
+ * 3. When Direct Key Agreement or Key Agreement with Key Wrapping are
+ * employed, use the key agreement algorithm to compute the value
+ * of the agreed upon key. When Direct Key Agreement is employed,
+ * let the CEK be the agreed upon key. When Key Agreement with Key
+ * Wrapping is employed, the agreed upon key will be used to wrap
+ * the CEK.
+ *
+ * 4. When Key Wrapping, Key Encryption, or Key Agreement with Key
+ * Wrapping are employed, encrypt the CEK to the recipient and let
+ * the result be the JWE Encrypted Key.
+ *
+ * 5. When Direct Key Agreement or Direct Encryption are employed, let
+ * the JWE Encrypted Key be the empty octet sequence.
+ *
+ * 6. When Direct Encryption is employed, let the CEK be the shared
+ * symmetric key.
+ *
+ * 8. If the JWE JSON Serialization is being used, repeat this process
+ * (steps 1-7) for each recipient.
+ *
+ * 9. Generate a random JWE Initialization Vector of the correct size
+ * for the content encryption algorithm (if required for the
+ * algorithm); otherwise, let the JWE Initialization Vector be the
+ * empty octet sequence.
+ *
+ * 11. If a "zip" parameter was included, compress the plaintext using
+ * the specified compression algorithm and let M be the octet
+ * sequence representing the compressed plaintext; otherwise, let M
+ * be the octet sequence representing the plaintext.
+ *
+ * 12. Create the JSON object(s) containing the desired set of Header
+ * Parameters, which together comprise the JOSE Header: one or more
+ * of the JWE Protected Header, the JWE Shared Unprotected Header,
+ * and the JWE Per-Recipient Unprotected Header.
+ *
+ * 13. Compute the Encoded Protected Header value BASE64URL(UTF8(JWE
+ * Protected Header)). If the JWE Protected Header is not present
+ * (which can only happen when using the JWE JSON Serialization and
+ * no "protected" member is present), let this value be the empty
+ * string.
+ *
+ * 14. Let the Additional Authenticated Data encryption parameter be
+ * ASCII(Encoded Protected Header). However, if a JWE AAD value is
+ * present (which can only be the case when using the JWE JSON
+ * Serialization), instead let the Additional Authenticated Data
+ * encryption parameter be ASCII(Encoded Protected Header || '.' ||
+ * BASE64URL(JWE AAD)).
+ *
+ * 15. Encrypt M using the CEK, the JWE Initialization Vector, and the
+ * Additional Authenticated Data value using the specified content
+ * encryption algorithm to create the JWE Ciphertext value and the
+ * JWE Authentication Tag (which is the Authentication Tag output
+ * from the encryption operation).
+ *
+ * @param bb Brigade containing data to be encrypted.
+ * @param jose The JOSE structure.
+ * @param recipient Structure containing details of the recipient of
+ * this message.
+ * @param encryption Structure to be filled out by the callback
+ * containing the encrypted message.
+ * @param ctx A context.
+ * @param pool The pool to use.
+ * @return APR_SUCCESS if encrypted successfully, APR_ENOTIMPL if
+ * encryption is not supported, or any other suitable error. The
+ * jose->result structure may be filled out with further details of
+ * any error.
+ */
+ apr_status_t (*encrypt)(apr_bucket_brigade *bb, apr_jose_t *jose,
+ apr_jose_recipient_t *recipient, apr_jose_encryption_t *encryption,
+ void *ctx, apr_pool_t *pool);
+ /**
+ * Callback that decrypts the ciphertext based
+ * on the parameters provided by the recipient and encryption parameters, and writes
+ * the resulting decrypted value to the bucket brigade. Base64url versions of the
+ * protected header and the aad are provided as part of the JWE decryption
+ * mechanism.
+ *
+ * For security reasons, this callback MUST verify that the algorithm
+ * present in the JWE matches the algorithm expected by the decoder.
+ *
+ * The decrypt function is expected to perform some or all of the
+ * following steps:
+ *
+ * 6. Determine the Key Management Mode employed by the algorithm
+ * specified by the "alg" (algorithm) Header Parameter.
+ *
+ * 7. Verify that the JWE uses a key known to the recipient.
+ *
+ * 8. When Direct Key Agreement or Key Agreement with Key Wrapping are
+ * employed, use the key agreement algorithm to compute the value
+ * of the agreed upon key. When Direct Key Agreement is employed,
+ * let the CEK be the agreed upon key. When Key Agreement with Key
+ * Wrapping is employed, the agreed upon key will be used to
+ * decrypt the JWE Encrypted Key.
+ *
+ * 9. When Key Wrapping, Key Encryption, or Key Agreement with Key
+ * Wrapping are employed, decrypt the JWE Encrypted Key to produce
+ * the CEK. The CEK MUST have a length equal to that required for
+ * the content encryption algorithm. Note that when there are
+ * multiple recipients, each recipient will only be able to decrypt
+ * JWE Encrypted Key values that were encrypted to a key in that
+ * recipient's possession. It is therefore normal to only be able
+ * to decrypt one of the per-recipient JWE Encrypted Key values to
+ * obtain the CEK value. Also, see Section 11.5 for security
+ * considerations on mitigating timing attacks.
+ *
+ * 10. When Direct Key Agreement or Direct Encryption are employed,
+ * verify that the JWE Encrypted Key value is an empty octet
+ * sequence.
+ *
+ * 11. When Direct Encryption is employed, let the CEK be the shared
+ * symmetric key.
+ *
+ * 12. Record whether the CEK could be successfully determined for this
+ * recipient or not.
+ *
+ * 13. If the JWE JSON Serialization is being used, repeat this process
+ * (steps 4-12) for each recipient contained in the representation.
+ *
+ * 14. Compute the Encoded Protected Header value BASE64URL(UTF8(JWE
+ * Protected Header)). If the JWE Protected Header is not present
+ * (which can only happen when using the JWE JSON Serialization and
+ * no "protected" member is present), let this value be the empty
+ * string.
+ *
+ * 15. Let the Additional Authenticated Data encryption parameter be
+ * ASCII(Encoded Protected Header). However, if a JWE AAD value is
+ * present (which can only be the case when using the JWE JSON
+ * Serialization), instead let the Additional Authenticated Data
+ * encryption parameter be ASCII(Encoded Protected Header || '.' ||
+ * BASE64URL(JWE AAD)).
+ *
+ * 16. Decrypt the JWE Ciphertext using the CEK, the JWE Initialization
+ * Vector, the Additional Authenticated Data value, and the JWE
+ * Authentication Tag (which is the Authentication Tag input to the
+ * calculation) using the specified content encryption algorithm,
+ * returning the decrypted plaintext and validating the JWE
+ * Authentication Tag in the manner specified for the algorithm,
+ * rejecting the input without emitting any decrypted output if the
+ * JWE Authentication Tag is incorrect.
+ *
+ * 17. If a "zip" parameter was included, uncompress the decrypted
+ * plaintext using the specified compression algorithm.
+ *
+ * @param bb Brigade where decrypted data is to be written.
+ * @param jose The JOSE structure.
+ * @param recipient Structure containing details of the recipient of
+ * this message, to be used to decrypt the message.
+ * @param encryption Structure containing the encrypted message.
+ * @param header The JOSE protected header.
+ * @param p64 The JOSE protected header in original BASE64URL format,
+ * for use during decryption.
+ * @param aad64 The JOSE additional authenticated data in original
+ * BASE64URL format, for use during decryption.
+ * @param ctx A context.
+ * @param dflags A pointer to a flag. Set to APR_JOSE_FLAG_NONE for
+ * decryption to continue to the next recipient in the JWE, or
+ * APR_JOSE_FLAG_BREAK to stop decrypting further recipients.
+ * @param pool The pool to use.
+ * @return APR_SUCCESS if decrypted successfully, APR_ENOTIMPL if
+ * decryption is not supported, or any other suitable error. The
+ * jose->result structure may be filled out with further details of
+ * any error.
+ */
+ apr_status_t (*decrypt)(apr_bucket_brigade *bb, apr_jose_t *jose,
+ apr_jose_recipient_t *recipient, apr_jose_encryption_t *encryption,
+ apr_json_value_t *header, apr_jose_text_t *ph64,
+ apr_jose_text_t *aad64, void *ctx, int *dflags, apr_pool_t *pool);
+ /**
+ * Callback that signs the content of the bucket brigade bb based
+ * on the parameters provided by the signature protected header, and writes
+ * the resulting binary signature to signature->sig.
+ *
+ * The sign function is expected to perform some or all of the
+ * following steps:
+ *
+ * 5. Compute the JWS Signature in the manner defined for the
+ * particular algorithm being used over the JWS Signing Input
+ * ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' ||
+ * BASE64URL(JWS Payload)). The "alg" (algorithm) Header Parameter
+ * MUST be present in the JOSE Header, with the algorithm value
+ * accurately representing the algorithm used to construct the JWS
+ * Signature.
+ *
+ * @param bb Brigade containing data to be signed.
+ * @param jose The JOSE structure.
+ * @param signature Structure to be filled out by the callback
+ * containing the signature of the message.
+ * @param ctx A context.
+ * @param pool The pool to use.
+ * @return APR_SUCCESS if signed successfully, APR_ENOTIMPL if
+ * signing is not supported, or any other suitable error. The
+ * jose->result structure may be filled out with further details of
+ * any error.
+ */
+ apr_status_t (*sign)(apr_bucket_brigade *bb, apr_jose_t *jose,
+ apr_jose_signature_t *signature, void *ctx, apr_pool_t *pool);
+ /**
+ * Callback that verifies the content of the bucket brigade bb based
+ * on the parameters provided by the signature protected header and
+ * signature->sig.
+ *
+ * For security reasons, this callback MUST verify that the algorithm
+ * present in the JWS matches the algorithm expected by the decoder.
+ *
+ * The verify function is expected to perform some or all of the
+ * following steps:
+ *
+ * 8. Validate the JWS Signature against the JWS Signing Input
+ * ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' ||
+ * BASE64URL(JWS Payload)) in the manner defined for the algorithm
+ * being used, which MUST be accurately represented by the value of
+ * the "alg" (algorithm) Header Parameter, which MUST be present.
+ * See Section 10.6 for security considerations on algorithm
+ * validation. Record whether the validation succeeded or not.
+ *
+ * 9. If the JWS JSON Serialization is being used, repeat this process
+ * (steps 4-8) for each digital signature or MAC value contained in
+ * the representation.
+ *
+ * 10. If none of the validations in step 9 succeeded, then the JWS MUST
+ * be considered invalid. Otherwise, in the JWS JSON Serialization
+ * case, return a result to the application indicating which of the
+ * validations succeeded and failed. In the JWS Compact
+ * Serialization case, the result can simply indicate whether or not
+ * the JWS was successfully validated.
+ *
+ * @param bb Brigade containing data to be verified.
+ * @param jose The JOSE structure.
+ * @param signature Structure containing the signature to be verified.
+ * @param ctx A context.
+ * @param dflags A pointer to a flag. Set to APR_JOSE_FLAG_NONE for
+ * verification to continue to the next recipient in the JWE, or
+ * APR_JOSE_FLAG_BREAK to stop verifying further recipients.
+ * @param pool The pool to use.
+ * @return APR_SUCCESS if verified successfully, APR_ENOTIMPL if
+ * verification is not supported, or any other suitable error. The
+ * jose->result structure may be filled out with further details of
+ * any error.
+ */
+ apr_status_t (*verify)(apr_bucket_brigade *bb, apr_jose_t *jose,
+ apr_jose_signature_t *signature, void *ctx, int *vflags,
+ apr_pool_t *pool);
+ /** Context to be passed to the callback. */
+ void *ctx;
+} apr_jose_cb_t;
+
+/**
+ * @brief Get the result of the last operation on the jose. If the result
+ * is NULL, the operation was successful.
+ * @param jose - context pointer
+ * @return The apu_err_t is returned.
+ */
+APR_DECLARE(apu_err_t *) apr_jose_error(apr_jose_t *jose);
+
+/**
+ * Make a generic JOSE structure.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param type the type of structure to create.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_make(apr_jose_t **jose, apr_jose_type_e type,
+ apr_pool_t *pool);
+
+/**
+ * Make a JSON Web Key for encoding or decoding.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param key the json representing the key. May be NULL.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jwk_make(apr_jose_t **jose,
+ apr_json_value_t *key, apr_pool_t *pool);
+
+/**
+ * Make a JSON Web Key Set.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param keys the array of keys in JSON format. May be NULL.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jwks_make(apr_jose_t **jose,
+ apr_json_value_t *keys, apr_pool_t *pool);
+
+/**
+ * Make a signature structure for JWS.
+ *
+ * @param signature the result.
+ * @param header the unprotected header.
+ * @param protected the protected header.
+ * @param pool the pool to use.
+ */
+APR_DECLARE(apr_status_t) apr_jose_signature_make(
+ apr_jose_signature_t **signature, apr_json_value_t *header,
+ apr_json_value_t *protected, apr_pool_t *pool);
+
+/**
+ * Make a recipient structure for JWE.
+ *
+ * @param recipient the result.
+ * @param unprotected the unprotected header.
+ * @param pool the pool to use.
+ */
+APR_DECLARE(apr_status_t) apr_jose_recipient_make(apr_jose_recipient_t **recipient,
+ apr_json_value_t *unprotected, apr_pool_t *pool);
+
+/**
+ * Make an encryption structure for JWE.
+ *
+ * @param encryption the result.
+ * @param unprotected the unprotected shared header.
+ * @param protected the protected header.
+ * @param pool the pool to use.
+ */
+APR_DECLARE(apr_status_t) apr_jose_encryption_make(apr_jose_encryption_t **encryption,
+ apr_json_value_t *unprotected, apr_json_value_t *protected,
+ apr_pool_t *pool);
+
+/**
+ * Make a compact encoded JWE.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param recipient the recipient for compact / flattened JWE.
+ * @param recipients the recipients array for general JWE.
+ * @param encryption the encryption structure.
+ * @param payload the JOSE payload to encrypt.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jwe_make(apr_jose_t **jose,
+ apr_jose_recipient_t *recipient, apr_array_header_t *recipients,
+ apr_jose_encryption_t *encryption, apr_jose_t *payload,
+ apr_pool_t *pool);
+
+/**
+ * Make a JSON encoded JWE.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param recipient the recipient for compact / flattened JWE.
+ * @param recipients the recipients array for general JWE.
+ * @param encryption the encryption structure.
+ * @param payload the JOSE payload to encrypt.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jwe_json_make(apr_jose_t **jose,
+ apr_jose_recipient_t *recipient,
+ apr_array_header_t *recipients, apr_jose_encryption_t *encryption,
+ apr_jose_t *payload, apr_pool_t *pool);
+
+/**
+ * Make a compact encoded JWS.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param signature the header / protected header / signature used with compact or flattened syntax. May be NULL.
+ * @param signatures array of header / protected header / signature used with general JSON syntax.
+ * @param payload the payload to be wrapped by this JWS.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jws_make(apr_jose_t **jose,
+ apr_jose_signature_t *signature, apr_array_header_t *signatures,
+ apr_jose_t *payload, apr_pool_t *pool);
+
+/**
+ * Make a JSON encoded JWS.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param signature the header / protected header / signature used with compact or flattened syntax. May be NULL.
+ * @param signatures array of header / protected header / signature used with general JSON syntax.
+ * @param payload the payload to be wrapped by this JWS.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jws_json_make(apr_jose_t **jose,
+ apr_jose_signature_t *signature, apr_array_header_t *signatures,
+ apr_jose_t *payload, apr_pool_t *pool);
+
+/**
+ * Make a JWT claims payload.
+ *
+ * To create a useful JWT, this payload needs to be wrapped in a JWS
+ * or JWE (or both), as required by the caller.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param claims the claims to sign.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_jwt_make(apr_jose_t **jose,
+ apr_json_value_t *claims, apr_pool_t *pool);
+
+/**
+ * Make a data buffer for encoding from the given data and length.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param typ the content type of this data.
+ * @param in the plaintext to sign.
+ * @param inlen length of the plaintext.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_data_make(apr_jose_t **jose, const char *typ,
+ const unsigned char *in, apr_size_t inlen, apr_pool_t *pool);
+
+/**
+ * Make a UTF-8 text buffer for encoding from the given string
+ * and length.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param cty the content type.
+ * @param in the UTF-8 encoded text string.
+ * @param inlen length of the UTF-8 encoded text string.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_text_make(apr_jose_t **jose, const char *cty,
+ const char *in, apr_size_t inlen, apr_pool_t *pool);
+
+/**
+ * Make a json structure for encoding.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param cty the content type.
+ * @param json the json object to add.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_json_make(apr_jose_t **jose, const char *cty,
+ apr_json_value_t *json, apr_pool_t *pool);
+
+/**
+ * Sign or encrypt the apr_jose_t, and write it to the brigade.
+ * @param brigade brigade the result will be appended to.
+ * @param flush The flush function to use if the brigade is full
+ * @param ctx The structure to pass to the flush function
+ * @param jose the JOSE to encode.
+ * @param cb callbacks for sign and encrypt.
+ * @param pool pool to be used.
+ * @return APR_SUCCESS is returned if encoding was successful, otherwise
+ * an APR status code, along with an apu_err_t with an explanation
+ * allocated from jose->pool.
+ */
+APR_DECLARE(apr_status_t) apr_jose_encode(apr_bucket_brigade *brigade,
+ apr_brigade_flush flush, void *ctx, apr_jose_t *jose,
+ apr_jose_cb_t *cb, apr_pool_t *pool);
+
+/**
+ * Decode, decrypt and verify the utf8-encoded JOSE string into apr_jose_t.
+ *
+ * The JOSE structure may be nested to the given limit.
+ * @param jose If jose points at NULL, a JOSE structure will be
+ * created. If the jose pointer is not NULL, the structure will
+ * be reused.
+ * @param typ content type of this object.
+ * @param brigade the JOSE structure to decode.
+ * @param cb callbacks for verify and decrypt.
+ * @param level depth limit of JOSE and JSON nesting.
+ * @param flags APR_JOSE_FLAG_NONE to return payload only. APR_JOSE_FLAG_DECODE_ALL
+ * to return the full JWS/JWE structure.
+ * @param pool pool used to allocate the result from.
+ */
+APR_DECLARE(apr_status_t) apr_jose_decode(apr_jose_t **jose, const char *typ,
+ apr_bucket_brigade *brigade, apr_jose_cb_t *cb, int level, int flags,
+ apr_pool_t *pool);
+
+
+#ifdef __cplusplus
+}
+#endif
+/** @} */
+#endif /* APR_JOSE_H */
diff --git a/test/testjose.c b/test/testjose.c
new file mode 100644
index 000000000..411b7c5d0
--- /dev/null
+++ b/test/testjose.c
@@ -0,0 +1,1423 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_jose.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+
+static apr_status_t sign_cb(apr_bucket_brigade *bb, apr_jose_t *jose,
+ apr_jose_signature_t *signature, void *ctx, apr_pool_t *pool)
+{
+ abts_case *tc = ctx;
+ apr_json_kv_t *alg = NULL;
+
+ if (signature) {
+ apr_json_value_t *ph = signature->protected_header;
+
+ ABTS_INT_EQUAL(tc, APR_JSON_OBJECT, ph->type);
+
+ if (ph->type == APR_JSON_OBJECT) {
+ alg = apr_json_object_get(ph, APR_JOSE_JWKSE_ALGORITHM,
+ APR_JSON_VALUE_STRING);
+ }
+ }
+
+ if (alg) {
+
+ ABTS_INT_EQUAL(tc, APR_JSON_STRING, alg->v->type);
+
+ /* unsecured jws/jwt */
+ if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "none",
+ alg->v->value.string.len)) {
+
+ signature->sig.data = (unsigned const char *) "";
+ signature->sig.len = 0;
+
+ return APR_SUCCESS;
+ }
+
+ /* hs256 jws - https://tools.ietf.org/html/rfc7515#appendix-A.1 */
+ else if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "HS256",
+ alg->v->value.string.len)) {
+
+ const unsigned char hs256[] = { 116, 24, 223, 180, 151, 153, 224,
+ 37, 79, 250, 96, 125, 216, 173, 187, 186, 22, 212, 37, 77,
+ 105, 214, 191, 240, 91, 88, 5, 88, 83, 132, 141, 121 };
+ signature->sig.data = apr_pmemdup(p, hs256, sizeof(hs256));
+ signature->sig.len = sizeof(hs256);
+
+ return APR_SUCCESS;
+ }
+
+ /* rs256 jws - https://tools.ietf.org/html/rfc7515#appendix-A.2 */
+ else if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "RS256",
+ alg->v->value.string.len)) {
+
+ const unsigned char rs256[] = { 112, 46, 33, 137, 67, 232, 143, 209,
+ 30, 181, 216, 45, 191, 120, 69, 243, 65, 6, 174, 27, 129,
+ 255, 247, 115, 17, 22, 173, 209, 113, 125, 131, 101, 109,
+ 66, 10, 253, 60, 150, 238, 221, 115, 162, 102, 62, 81, 102,
+ 104, 123, 0, 11, 135, 34, 110, 1, 135, 237, 16, 115, 249,
+ 69, 229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232,
+ 198, 109, 219, 61, 184, 151, 91, 23, 208, 148, 2, 190, 237,
+ 213, 217, 217, 112, 7, 16, 141, 178, 129, 96, 213, 248, 4,
+ 12, 167, 68, 87, 98, 184, 31, 190, 127, 249, 217, 46, 10,
+ 231, 111, 36, 242, 91, 51, 187, 230, 244, 74, 230, 30, 177,
+ 4, 10, 203, 32, 4, 77, 62, 249, 18, 142, 212, 1, 48, 121,
+ 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129,
+ 253, 228, 141, 247, 127, 55, 45, 195, 139, 159, 175, 221,
+ 59, 239, 177, 139, 93, 163, 204, 60, 46, 176, 47, 158, 58,
+ 65, 214, 18, 202, 173, 21, 145, 18, 115, 160, 95, 35, 185,
+ 232, 56, 250, 175, 132, 157, 105, 132, 41, 239, 90, 30, 136,
+ 121, 130, 54, 195, 212, 14, 96, 69, 34, 165, 68, 200, 242,
+ 122, 122, 45, 184, 6, 99, 209, 108, 247, 202, 234, 86, 222,
+ 64, 92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90, 193,
+ 167, 72, 160, 112, 223, 200, 163, 42, 70, 149, 67, 208, 25,
+ 238, 251, 71 };
+ signature->sig.data = apr_pmemdup(p, rs256, sizeof(rs256));
+ signature->sig.len = sizeof(rs256);
+
+ return APR_SUCCESS;
+ }
+
+ /* es256 jws - https://tools.ietf.org/html/rfc7515#appendix-A.3 */
+ else if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "ES256",
+ alg->v->value.string.len)) {
+
+ const unsigned char es256[] = { 14, 209, 33, 83, 121, 99, 108, 72,
+ 60, 47, 127, 21, 88, 7, 212, 2, 163, 178, 40, 3, 58, 249,
+ 124, 126, 23, 129, 154, 195, 22, 158, 166, 101, 197, 10, 7,
+ 211, 140, 60, 112, 229, 216, 241, 45, 175, 8, 74, 84, 128,
+ 166, 101, 144, 197, 242, 147, 80, 154, 143, 63, 127, 138,
+ 131, 163, 84, 213 };
+ signature->sig.data = apr_pmemdup(p, es256, sizeof(es256));
+ signature->sig.len = sizeof(es256);
+
+ return APR_SUCCESS;
+ }
+
+ else {
+ apr_errprintf(&jose->result, jose->pool, NULL, 0,
+ "Header 'alg' not recognised: %.*s",
+ (int) alg->v->value.string.len, alg->v->value.string.p);
+ return APR_ENOTIMPL;
+ }
+
+ }
+
+ else {
+ apr_errprintf(&jose->result, jose->pool, NULL, 0,
+ "Header 'alg' missing");
+ return APR_ENOTIMPL;
+ }
+
+ return APR_ENOTIMPL;
+}
+
+static apr_status_t verify_cb(apr_bucket_brigade *bb,
+ apr_jose_t *jose, apr_jose_signature_t *signature, void *ctx,
+ int *vflags, apr_pool_t *pool)
+{
+ abts_case *tc = ctx;
+ apr_json_kv_t *alg = NULL;
+
+ *vflags = APR_JOSE_FLAG_NONE;
+
+ if (signature) {
+ apr_json_value_t *ph = signature->protected_header;
+
+ ABTS_INT_EQUAL(tc, APR_JSON_OBJECT, ph->type);
+
+ alg = apr_json_object_get(ph, APR_JOSE_JWKSE_ALGORITHM,
+ APR_JSON_VALUE_STRING);
+ }
+
+ if (alg) {
+
+ ABTS_INT_EQUAL(tc, APR_JSON_STRING, alg->v->type);
+
+ /* unsecured jws/jwt */
+ if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "none",
+ alg->v->value.string.len)) {
+
+ if (!memcmp(signature->sig.data, (unsigned const char *) "",
+ signature->sig.len)) {
+ return APR_SUCCESS;
+ }
+ }
+
+ /* hs256 jws - https://tools.ietf.org/html/rfc7515#appendix-A.1 */
+ else if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "HS256",
+ alg->v->value.string.len)) {
+
+ const unsigned char hs256[] = { 116, 24, 223, 180, 151, 153, 224,
+ 37, 79, 250, 96, 125, 216, 173, 187, 186, 22, 212, 37, 77,
+ 105, 214, 191, 240, 91, 88, 5, 88, 83, 132, 141, 121 };
+
+ if (!memcmp(signature->sig.data, hs256, sizeof(hs256))) {
+ return APR_SUCCESS;
+ }
+
+ }
+
+ /* rs256 jws - https://tools.ietf.org/html/rfc7515#appendix-A.2 */
+ else if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "RS256",
+ alg->v->value.string.len)) {
+
+ const unsigned char rs256[] = { 112, 46, 33, 137, 67, 232, 143, 209,
+ 30, 181, 216, 45, 191, 120, 69, 243, 65, 6, 174, 27, 129,
+ 255, 247, 115, 17, 22, 173, 209, 113, 125, 131, 101, 109,
+ 66, 10, 253, 60, 150, 238, 221, 115, 162, 102, 62, 81, 102,
+ 104, 123, 0, 11, 135, 34, 110, 1, 135, 237, 16, 115, 249,
+ 69, 229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232,
+ 198, 109, 219, 61, 184, 151, 91, 23, 208, 148, 2, 190, 237,
+ 213, 217, 217, 112, 7, 16, 141, 178, 129, 96, 213, 248, 4,
+ 12, 167, 68, 87, 98, 184, 31, 190, 127, 249, 217, 46, 10,
+ 231, 111, 36, 242, 91, 51, 187, 230, 244, 74, 230, 30, 177,
+ 4, 10, 203, 32, 4, 77, 62, 249, 18, 142, 212, 1, 48, 121,
+ 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129,
+ 253, 228, 141, 247, 127, 55, 45, 195, 139, 159, 175, 221,
+ 59, 239, 177, 139, 93, 163, 204, 60, 46, 176, 47, 158, 58,
+ 65, 214, 18, 202, 173, 21, 145, 18, 115, 160, 95, 35, 185,
+ 232, 56, 250, 175, 132, 157, 105, 132, 41, 239, 90, 30, 136,
+ 121, 130, 54, 195, 212, 14, 96, 69, 34, 165, 68, 200, 242,
+ 122, 122, 45, 184, 6, 99, 209, 108, 247, 202, 234, 86, 222,
+ 64, 92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90, 193,
+ 167, 72, 160, 112, 223, 200, 163, 42, 70, 149, 67, 208, 25,
+ 238, 251, 71 };
+
+ if (!memcmp(signature->sig.data, rs256, sizeof(rs256))) {
+ return APR_SUCCESS;
+ }
+
+ }
+
+ /* es256 jws - https://tools.ietf.org/html/rfc7515#appendix-A.3 */
+ else if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "ES256",
+ alg->v->value.string.len)) {
+
+ const unsigned char es256[] = { 14, 209, 33, 83, 121, 99, 108, 72,
+ 60, 47, 127, 21, 88, 7, 212, 2, 163, 178, 40, 3, 58, 249,
+ 124, 126, 23, 129, 154, 195, 22, 158, 166, 101, 197, 10, 7,
+ 211, 140, 60, 112, 229, 216, 241, 45, 175, 8, 74, 84, 128,
+ 166, 101, 144, 197, 242, 147, 80, 154, 143, 63, 127, 138,
+ 131, 163, 84, 213 };
+
+ if (!memcmp(signature->sig.data, es256, sizeof(es256))) {
+ return APR_SUCCESS;
+ }
+
+ return APR_SUCCESS;
+ }
+
+ else {
+ apr_errprintf(&jose->result, jose->pool, NULL, 0,
+ "Header 'alg' not recognised: %.*s",
+ (int) alg->v->value.string.len, alg->v->value.string.p);
+ return APR_ENOTIMPL;
+ }
+
+ }
+
+ else {
+ apr_errprintf(&jose->result, jose->pool, NULL, 0,
+ "Header 'alg' missing");
+ return APR_ENOTIMPL;
+ }
+
+ return APR_ENOTIMPL;
+}
+
+static apr_status_t encrypt_cb(apr_bucket_brigade *brigade, apr_jose_t *jose,
+ apr_jose_recipient_t *recipient, apr_jose_encryption_t *encryption,
+ void *ctx, apr_pool_t *p)
+{
+ abts_case *tc = ctx;
+ apr_json_value_t *protected_header;
+ apr_json_value_t *header;
+ apr_json_kv_t *alg = NULL;
+
+ if (encryption) {
+
+ if (encryption->protected) {
+
+ protected_header = encryption->protected;
+ if (protected_header) {
+
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+
+ apr_bucket_brigade *bb = apr_brigade_create(p,
+ brigade->bucket_alloc);
+
+ apr_json_encode(bb, NULL, NULL, protected_header,
+ APR_JSON_FLAGS_WHITESPACE, p);
+
+ apr_brigade_flatten(bb, buf, &len);
+
+ /* RSAES-OAEP and AES GCM jwe - https://tools.ietf.org/html/rfc7516#appendix-A.1 */
+ if (!strncmp("{\"alg\":\"RSA-OAEP\",\"enc\":\"A256GCM\"}", buf, len)) {
+
+ const unsigned char iv[] = { 227, 197, 117, 252, 2, 219, 233,
+ 68, 180, 225, 77, 219 };
+
+ const unsigned char aad[] = { 101, 121, 74, 104, 98, 71, 99,
+ 105, 79, 105, 74, 83, 85, 48, 69, 116, 84, 48, 70, 70,
+ 85, 67, 73, 115, 73, 109, 86, 117, 89, 121, 73, 54, 73,
+ 107, 69, 121, 78, 84, 90, 72, 81, 48, 48, 105, 102, 81 };
+
+ const unsigned char cipher[] = { 229, 236, 166, 241, 53, 191,
+ 115, 196, 174, 43, 73, 109, 39, 122, 233, 96, 140, 206,
+ 120, 52, 51, 237, 48, 11, 190, 219, 186, 80, 111, 104,
+ 50, 142, 47, 167, 59, 61, 181, 127, 196, 21, 40, 82,
+ 242, 32, 123, 143, 168, 226, 73, 216, 176, 144, 138,
+ 247, 106, 60, 16, 205, 160, 109, 64, 63, 192 };
+
+ const unsigned char tag[] = { 92, 80, 104, 49, 133, 25, 161,
+ 215, 173, 101, 219, 211, 136, 91, 210, 145 };
+
+ encryption->iv.data = apr_pmemdup(p, iv, sizeof(iv));
+ encryption->iv.len = sizeof(iv);
+
+ encryption->aad.data = apr_pmemdup(p, aad, sizeof(aad));
+ encryption->aad.len = sizeof(aad);
+
+ encryption->cipher.data = apr_pmemdup(p, cipher, sizeof(cipher));
+ encryption->cipher.len = sizeof(cipher);
+
+ encryption->tag.data = apr_pmemdup(p, tag, sizeof(tag));
+ encryption->tag.len = sizeof(tag);
+
+ }
+
+ /* RSAES-PKCS1-v1_5 - https://tools.ietf.org/html/rfc7516#appendix-A.2 */
+ else if (!strncmp("{\"alg\":\"RSA1_5\",\"enc\":\"A128CBC-HS256\"}", buf, len)) {
+
+ const unsigned char iv[] = { 3, 22, 60, 12, 43, 67, 104, 105,
+ 108, 108, 105, 99, 111, 116, 104, 101 };
+
+ const unsigned char cipher[] = { 40, 57, 83, 181, 119, 33, 133,
+ 148, 198, 185, 243, 24, 152, 230, 6, 75, 129, 223, 127,
+ 19, 210, 82, 183, 230, 168, 33, 215, 104, 143, 112, 56,
+ 102 };
+
+ const unsigned char tag[] = { 246, 17, 244, 190, 4, 95, 98, 3,
+ 231, 0, 115, 157, 242, 203, 100, 191 };
+
+ encryption->iv.data = apr_pmemdup(p, iv, sizeof(iv));
+ encryption->iv.len = sizeof(iv);
+
+ encryption->cipher.data = apr_pmemdup(p, cipher, sizeof(cipher));
+ encryption->cipher.len = sizeof(cipher);
+
+ encryption->tag.data = apr_pmemdup(p, tag, sizeof(tag));
+ encryption->tag.len = sizeof(tag);
+
+ }
+
+ /* A128KW A128CBC-HS256 - https://tools.ietf.org/html/rfc7516#appendix-A.3 */
+ else if (!strncmp("{\"alg\":\"A128KW\",\"enc\":\"A128CBC-HS256\"}", buf, len)) {
+
+ const unsigned char iv[] = { 3, 22, 60, 12, 43, 67, 104, 105,
+ 108, 108, 105, 99, 111, 116, 104, 101 };
+
+ const unsigned char cipher[] = { 40, 57, 83, 181, 119, 33, 133,
+ 148, 198, 185, 243, 24, 152, 230, 6, 75, 129, 223, 127,
+ 19, 210, 82, 183, 230, 168, 33, 215, 104, 143, 112, 56,
+ 102 };
+
+ const unsigned char tag[] = { 83, 73, 191, 98, 104, 205, 211,
+ 128, 201, 189, 199, 133, 32, 38, 194, 85 };
+
+ encryption->iv.data = apr_pmemdup(p, iv, sizeof(iv));
+ encryption->iv.len = sizeof(iv);
+
+ encryption->cipher.data = apr_pmemdup(p, cipher, sizeof(cipher));
+ encryption->cipher.len = sizeof(cipher);
+
+ encryption->tag.data = apr_pmemdup(p, tag, sizeof(tag));
+ encryption->tag.len = sizeof(tag);
+
+ }
+
+ /* General JWE JSON - https://tools.ietf.org/html/rfc7516#appendix-A.4 */
+ else if (!strncmp("{\"enc\":\"A128CBC-HS256\"}", buf, len)) {
+
+ const unsigned char iv[] = { 3, 22, 60, 12, 43, 67, 104, 105,
+ 108, 108, 105, 99, 111, 116, 104, 101 };
+
+ const unsigned char cipher[] = { 40, 57, 83, 181, 119, 33, 133,
+ 148, 198, 185, 243, 24, 152, 230, 6, 75, 129, 223, 127,
+ 19, 210, 82, 183, 230, 168, 33, 215, 104, 143, 112, 56,
+ 102 };
+
+ const unsigned char tag[] = { 51, 63, 149, 60, 252, 148,
+ 225, 25, 92, 185, 139, 245, 35, 2, 47, 207 };
+
+ encryption->iv.data = apr_pmemdup(p, iv, sizeof(iv));
+ encryption->iv.len = sizeof(iv);
+
+ encryption->cipher.data = apr_pmemdup(p, cipher, sizeof(cipher));
+ encryption->cipher.len = sizeof(cipher);
+
+ encryption->tag.data = apr_pmemdup(p, tag, sizeof(tag));
+ encryption->tag.len = sizeof(tag);
+
+ }
+
+ else {
+ apr_errprintf(&jose->result, jose->pool, NULL, 0,
+ "Protected header not recognised: %.*s", (int)len, buf);
+ return APR_ENOTIMPL;
+ }
+
+
+ }
+ }
+
+
+ if (recipient) {
+ header = recipient->header;
+ if (header) {
+
+ ABTS_INT_EQUAL(tc, APR_JSON_OBJECT, header->type);
+
+ alg = apr_json_object_get(header, APR_JOSE_JWKSE_ALGORITHM,
+ APR_JSON_VALUE_STRING);
+ }
+ }
+
+ if (!alg) {
+ protected_header = encryption->protected;
+ if (protected_header) {
+
+ ABTS_INT_EQUAL(tc, APR_JSON_OBJECT, protected_header->type);
+
+ alg = apr_json_object_get(protected_header,
+ APR_JOSE_JWKSE_ALGORITHM, APR_JSON_VALUE_STRING);
+ }
+ }
+
+ if (alg && recipient) {
+
+ ABTS_INT_EQUAL(tc, APR_JSON_STRING, alg->v->type);
+
+ /* RSAES-OAEP and AES GCM jwe - https://tools.ietf.org/html/rfc7516#appendix-A.1 */
+ if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "RSA-OAEP",
+ alg->v->value.string.len)) {
+
+ const unsigned char ekey[] = { 56, 163, 154, 192, 58, 53, 222,
+ 4, 105, 218, 136, 218, 29, 94, 203, 22, 150, 92, 129,
+ 94, 211, 232, 53, 89, 41, 60, 138, 56, 196, 216, 82, 98,
+ 168, 76, 37, 73, 70, 7, 36, 8, 191, 100, 136, 196, 244,
+ 220, 145, 158, 138, 155, 4, 117, 141, 230, 199, 247,
+ 173, 45, 182, 214, 74, 177, 107, 211, 153, 11, 205, 196,
+ 171, 226, 162, 128, 171, 182, 13, 237, 239, 99, 193, 4,
+ 91, 219, 121, 223, 107, 167, 61, 119, 228, 173, 156,
+ 137, 134, 200, 80, 219, 74, 253, 56, 185, 91, 177, 34,
+ 158, 89, 154, 205, 96, 55, 18, 138, 43, 96, 218, 215,
+ 128, 124, 75, 138, 243, 85, 25, 109, 117, 140, 26, 155,
+ 249, 67, 167, 149, 231, 100, 6, 41, 65, 214, 251, 232,
+ 87, 72, 40, 182, 149, 154, 168, 31, 193, 126, 215, 89,
+ 28, 111, 219, 125, 182, 139, 235, 195, 197, 23, 234, 55,
+ 58, 63, 180, 68, 202, 206, 149, 75, 205, 248, 176, 67,
+ 39, 178, 60, 98, 193, 32, 238, 122, 96, 158, 222, 57,
+ 183, 111, 210, 55, 188, 215, 206, 180, 166, 150, 166,
+ 106, 250, 55, 229, 72, 40, 69, 214, 216, 104, 23, 40,
+ 135, 212, 28, 127, 41, 80, 175, 174, 168, 115, 171, 197,
+ 89, 116, 92, 103, 246, 83, 216, 182, 176, 84, 37, 147,
+ 35, 45, 219, 172, 99, 226, 233, 73, 37, 124, 42, 72, 49,
+ 242, 35, 127, 184, 134, 117, 114, 135, 206 };
+
+ recipient->ekey.data = apr_pmemdup(p, ekey, sizeof(ekey));
+ recipient->ekey.len = sizeof(ekey);
+
+ return APR_SUCCESS;
+ }
+
+ /* RSAES-PKCS1-v1_5 - https://tools.ietf.org/html/rfc7516#appendix-A.2 */
+ if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "RSA1_5",
+ alg->v->value.string.len)) {
+
+ const unsigned char ekey[] = { 80, 104, 72, 58, 11, 130, 236,
+ 139, 132, 189, 255, 205, 61, 86, 151, 176, 99, 40, 44,
+ 233, 176, 189, 205, 70, 202, 169, 72, 40, 226, 181, 156,
+ 223, 120, 156, 115, 232, 150, 209, 145, 133, 104, 112,
+ 237, 156, 116, 250, 65, 102, 212, 210, 103, 240, 177,
+ 61, 93, 40, 71, 231, 223, 226, 240, 157, 15, 31, 150,
+ 89, 200, 215, 198, 203, 108, 70, 117, 66, 212, 238, 193,
+ 205, 23, 161, 169, 218, 243, 203, 128, 214, 127, 253,
+ 215, 139, 43, 17, 135, 103, 179, 220, 28, 2, 212, 206,
+ 131, 158, 128, 66, 62, 240, 78, 186, 141, 125, 132, 227,
+ 60, 137, 43, 31, 152, 199, 54, 72, 34, 212, 115, 11,
+ 152, 101, 70, 42, 219, 233, 142, 66, 151, 250, 126, 146,
+ 141, 216, 190, 73, 50, 177, 146, 5, 52, 247, 28, 197,
+ 21, 59, 170, 247, 181, 89, 131, 241, 169, 182, 246, 99,
+ 15, 36, 102, 166, 182, 172, 197, 136, 230, 120, 60, 58,
+ 219, 243, 149, 94, 222, 150, 154, 194, 110, 227, 225,
+ 112, 39, 89, 233, 112, 207, 211, 241, 124, 174, 69, 221,
+ 179, 107, 196, 225, 127, 167, 112, 226, 12, 242, 16, 24,
+ 28, 120, 182, 244, 213, 244, 153, 194, 162, 69, 160,
+ 244, 248, 63, 165, 141, 4, 207, 249, 193, 79, 131, 0,
+ 169, 233, 127, 167, 101, 151, 125, 56, 112, 111, 248,
+ 29, 232, 90, 29, 147, 110, 169, 146, 114, 165, 204, 71,
+ 136, 41, 252 };
+
+ recipient->ekey.data = apr_pmemdup(p, ekey, sizeof(ekey));
+ recipient->ekey.len = sizeof(ekey);
+
+ return APR_SUCCESS;
+ }
+
+ /* A128KW A128CBC-HS256 - https://tools.ietf.org/html/rfc7516#appendix-A.3 */
+ if (alg->v->type == APR_JSON_STRING
+ && !strncmp(alg->v->value.string.p, "A128KW",
+ alg->v->value.string.len)) {
+
+ const unsigned char ekey[] = { 232, 160, 123, 211, 183, 76, 245,
+ 132, 200, 128, 123, 75, 190, 216, 22, 67, 201, 138, 193,
+ 186, 9, 91, 122, 31, 246, 90, 28, 139, 57, 3, 76, 124,
+ 193, 11, 98, 37, 173, 61, 104, 57 };
+
+ recipient->ekey.data = apr_pmemdup(p, ekey, sizeof(ekey));
+ recipient->ekey.len = sizeof(ekey);
+
+ return APR_SUCCESS;
+ }
+
+ }
+ }
+
+ return APR_ENOTIMPL;
+}
+
+static apr_status_t decrypt_cb(apr_bucket_brigade *brigade, apr_jose_t *jose,
+ apr_jose_recipient_t *recipient, apr_jose_encryption_t *encryption,
+ apr_json_value_t *header, apr_jose_text_t *ph64, apr_jose_text_t *aad64,
+ void *ctx, int *dflags, apr_pool_t *pool)
+{
+
+ *dflags = APR_JOSE_FLAG_NONE;
+
+ if (encryption && recipient && header) {
+
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+
+ apr_bucket_brigade *bb = apr_brigade_create(p,
+ brigade->bucket_alloc);
+
+ apr_json_encode(bb, NULL, NULL, header,
+ APR_JSON_FLAGS_WHITESPACE, p);
+
+ apr_brigade_flatten(bb, buf, &len);
+
+ /* RSAES-OAEP and AES GCM jwe - https://tools.ietf.org/html/rfc7516#appendix-A.1 */
+ if (!strncmp("{\"alg\":\"RSA-OAEP\",\"enc\":\"A256GCM\"}", buf, len)) {
+
+ const char plaintext[] = { 84, 104, 101, 32, 116, 114, 117,
+ 101, 32, 115, 105, 103, 110, 32, 111, 102, 32, 105, 110,
+ 116, 101, 108, 108, 105, 103, 101, 110, 99, 101, 32, 105,
+ 115, 32, 110, 111, 116, 32, 107, 110, 111, 119, 108, 101,
+ 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105,
+ 110, 97, 116, 105, 111, 110, 46 };
+
+ apr_brigade_write(brigade, NULL, NULL, plaintext, sizeof(plaintext));
+
+ return APR_SUCCESS;
+ }
+
+ /* RSAES-PKCS1-v1_5 - https://tools.ietf.org/html/rfc7516#appendix-A.2 */
+ else if (!strncmp("{\"jku\":\"https://server.example.com/keys.jwks\",\"enc\":\"A128CBC-HS256\",\"alg\":\"RSA1_5\",\"kid\":\"2011-04-29\"}", buf, len)) {
+
+ const char plaintext[] = { 76, 105, 118, 101, 32, 108, 111, 110,
+ 103, 32, 97, 110, 100, 32, 112, 114, 111, 115, 112, 101,
+ 114, 46 };
+
+ apr_brigade_write(brigade, NULL, NULL, plaintext, sizeof(plaintext));
+
+ return APR_SUCCESS;
+ }
+
+ /* Flattened JWE JSON - https://tools.ietf.org/html/rfc7516#appendix-A.5 */
+ else if (!strncmp("{\"jku\":\"https://server.example.com/keys.jwks\",\"enc\":\"A128CBC-HS256\",\"alg\":\"A128KW\",\"kid\":\"7\"}", buf, len)) {
+
+ const char plaintext[] = { 76, 105, 118, 101, 32, 108, 111, 110,
+ 103, 32, 97, 110, 100, 32, 112, 114, 111, 115, 112, 101,
+ 114, 46 };
+
+ apr_brigade_write(brigade, NULL, NULL, plaintext, sizeof(plaintext));
+
+ return APR_SUCCESS;
+ }
+
+
+ else {
+ apr_errprintf(&jose->result, pool, NULL, 0,
+ "Header not recognised: %.*s", (int)len, buf);
+ return APR_ENOTIMPL;
+ }
+
+ }
+
+ return APR_ENOTIMPL;
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.5
+ */
+static void test_jose_encode_jws_compact_unsecured(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_jose_signature_t signature;
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const char *ph = "{\"alg\":\"none\"}";
+ const unsigned char pl[] = {123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10,
+ 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56,
+ 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97,
+ 109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111,
+ 111, 116, 34, 58, 116, 114, 117, 101, 125};
+ const char *expect = "eyJhbGciOiJub25lIn0"
+ "."
+ "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
+ "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+ ".";
+
+ apr_jose_cb_t cb;
+
+ cb.sign = sign_cb;
+ cb.ctx = tc;
+
+ signature.header = NULL;
+ apr_json_decode(&signature.protected_header, ph, APR_JSON_VALUE_STRING, &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "JWT", pl, sizeof(pl), p);
+ apr_jose_jws_make(&jose, &signature, NULL, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.1
+ */
+static void test_jose_encode_jws_compact_hs256(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_jose_signature_t signature;
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const unsigned char ph[] = { 123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84,
+ 34, 44, 13, 10, 32, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53,
+ 54, 34, 125 };
+
+ const unsigned char pl[] = {123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10,
+ 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56,
+ 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97,
+ 109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111,
+ 111, 116, 34, 58, 116, 114, 117, 101, 125};
+ const char *expect = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
+ "."
+ "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
+ "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+ "."
+ "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
+
+ apr_jose_cb_t cb;
+
+ cb.sign = sign_cb;
+ cb.ctx = tc;
+
+ signature.header = NULL;
+ apr_json_decode(&signature.protected_header, (const char *) ph, sizeof(ph), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "JWT", pl, sizeof(pl), p);
+ apr_jose_jws_make(&jose, &signature, NULL, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.6
+ */
+static void test_jose_encode_jws_json_general(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_jose_signature_t **signature;
+ apr_jose_signature_t signature1;
+ apr_jose_signature_t signature2;
+ apr_array_header_t *signatures = apr_array_make(p, 2,
+ sizeof(apr_jose_signature_t *));
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const unsigned char pl[] = { 123, 34, 105, 115, 115, 34, 58, 34, 106, 111,
+ 101, 34, 44, 13, 10, 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48,
+ 56, 49, 57, 51, 56, 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58,
+ 47, 47, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 47, 105,
+ 115, 95, 114, 111, 111, 116, 34, 58, 116, 114, 117, 101, 125 };
+
+ const char *s1h = "{\"kid\":\"2010-12-29\"}";
+ const char *s1ph = "{\"alg\":\"RS256\"}";
+ const char *s2h = "{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"}";
+ const char *s2ph = "{\"alg\":\"ES256\"}";
+
+ const char *expect = "{"
+ "\"payload\":"
+ "\"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF"
+ "tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\","
+ "\"signatures\":["
+ "{\"protected\":\"eyJhbGciOiJSUzI1NiJ9\","
+ "\"header\":"
+ "{\"kid\":\"2010-12-29\"},"
+ "\"signature\":"
+ "\"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ"
+ "mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb"
+ "KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl"
+ "b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES"
+ "c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX"
+ "LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw\"},"
+ "{\"protected\":\"eyJhbGciOiJFUzI1NiJ9\","
+ "\"header\":"
+ "{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"},"
+ "\"signature\":"
+ "\"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS"
+ "lSApmWQxfKTUJqPP3-Kg6NU1Q\"}]"
+ "}";
+
+ apr_jose_cb_t cb;
+
+ cb.sign = sign_cb;
+ cb.ctx = tc;
+
+ apr_json_decode(&signature1.header, (const char *) s1h, strlen(s1h), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&signature1.protected_header, (const char *) s1ph, strlen(s1ph), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&signature2.header, (const char *) s2h, strlen(s2h), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&signature2.protected_header, (const char *) s2ph, strlen(s2ph), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ signature = apr_array_push(signatures);
+ *signature = &signature1;
+ signature = apr_array_push(signatures);
+ *signature = &signature2;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "JWT", pl, sizeof(pl), p);
+ apr_jose_jws_json_make(&jose, NULL, signatures, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.7
+ */
+static void test_jose_encode_jws_json_flattened(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_jose_signature_t signature2;
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const unsigned char pl[] = { 123, 34, 105, 115, 115, 34, 58, 34, 106, 111,
+ 101, 34, 44, 13, 10, 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48,
+ 56, 49, 57, 51, 56, 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58,
+ 47, 47, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 47, 105,
+ 115, 95, 114, 111, 111, 116, 34, 58, 116, 114, 117, 101, 125 };
+
+ const char *s2h = "{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"}";
+ const char *s2ph = "{\"alg\":\"ES256\"}";
+
+ const char *expect = "{"
+ "\"payload\":"
+ "\"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF"
+ "tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\","
+ "\"protected\":\"eyJhbGciOiJFUzI1NiJ9\","
+ "\"header\":"
+ "{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"},"
+ "\"signature\":"
+ "\"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS"
+ "lSApmWQxfKTUJqPP3-Kg6NU1Q\""
+ "}";
+
+ apr_jose_cb_t cb;
+
+ cb.sign = sign_cb;
+ cb.ctx = tc;
+
+ apr_json_decode(&signature2.header, (const char *) s2h, strlen(s2h), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&signature2.protected_header, (const char *) s2ph, strlen(s2ph), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "JWT", pl, sizeof(pl), p);
+ apr_jose_jws_json_make(&jose, &signature2, NULL, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7516#appendix-A.1
+ */
+static void test_jose_encode_jwe_compact_rsaes_oaep_aes_gcm(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_jose_encryption_t *encryption;
+ apr_jose_recipient_t *recipient;
+ apr_json_value_t *header = NULL;
+ apr_json_value_t *protected_header = NULL;
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const char *ph = "{\"alg\":\"RSA-OAEP\",\"enc\":\"A256GCM\"}";
+
+ const unsigned char pl[] = { 84, 104, 101, 32, 116, 114, 117, 101, 32, 115,
+ 105, 103, 110, 32, 111, 102, 32, 105, 110, 116, 101, 108, 108, 105,
+ 103, 101, 110, 99, 101, 32, 105, 115, 32, 110, 111, 116, 32, 107,
+ 110, 111, 119, 108, 101, 100, 103, 101, 32, 98, 117, 116, 32, 105,
+ 109, 97, 103, 105, 110, 97, 116, 105, 111, 110, 46 };
+
+ const char *expect = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ."
+ "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe"
+ "ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb"
+ "Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV"
+ "mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8"
+ "1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi"
+ "6UklfCpIMfIjf7iGdXKHzg."
+ "48V1_ALb6US04U3b."
+ "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji"
+ "SdiwkIr3ajwQzaBtQD_A."
+ "XFBoMYUZodetZdvTiFvSkQ";
+
+ apr_jose_cb_t cb;
+
+ cb.encrypt = encrypt_cb;
+ cb.ctx = tc;
+
+ apr_json_decode(&protected_header, ph, APR_JSON_VALUE_STRING, &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "JWT", pl, sizeof(pl), p);
+ apr_jose_recipient_make(&recipient, header, p);
+ apr_jose_encryption_make(&encryption, NULL, protected_header, p);
+ apr_jose_jwe_make(&jose, recipient, NULL, encryption, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7516#appendix-A.4
+ */
+static void test_jose_encode_jwe_json_general(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_json_value_t *header = NULL;
+ apr_json_value_t *protected_header = NULL;
+ apr_jose_recipient_t **recipient;
+ apr_jose_recipient_t recipient1;
+ apr_jose_recipient_t recipient2;
+ apr_array_header_t *recipients = apr_array_make(p, 2,
+ sizeof(apr_jose_recipient_t *));
+ apr_jose_encryption_t *encryption;
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const char *r1h = "{\"alg\":\"RSA1_5\",\"kid\":\"2011-04-29\"}";
+ const char *r2h = "{\"alg\":\"A128KW\",\"kid\":\"7\"}";
+
+ const char *ph = "{\"enc\":\"A128CBC-HS256\"}";
+ const char *h = "{\"jku\":\"https://server.example.com/keys.jwks\"}";
+
+ const unsigned char pl[] = { 76, 105, 118, 101, 32, 108, 111, 110, 103, 32,
+ 97, 110, 100, 32, 112, 114, 111, 115, 112, 101, 114, 46 };
+
+ const char *expect = "{"
+ "\"protected\":"
+ "\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+ "\"unprotected\":"
+ "{\"jku\":\"https://server.example.com/keys.jwks\"},"
+ "\"recipients\":["
+ "{\"header\":"
+ "{\"alg\":\"RSA1_5\",\"kid\":\"2011-04-29\"},"
+ "\"encrypted_key\":"
+ "\"UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-"
+ "kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKx"
+ "GHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3"
+ "YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPh"
+ "cCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPg"
+ "wCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A\"},"
+ "{\"header\":"
+ "{\"alg\":\"A128KW\",\"kid\":\"7\"},"
+ "\"encrypted_key\":"
+ "\"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ\"}],"
+ "\"iv\":"
+ "\"AxY8DCtDaGlsbGljb3RoZQ\","
+ "\"ciphertext\":"
+ "\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
+ "\"tag\":"
+ "\"Mz-VPPyU4RlcuYv1IwIvzw\""
+ "}\";";
+
+ apr_jose_cb_t cb;
+
+ cb.encrypt = encrypt_cb;
+ cb.ctx = tc;
+
+ apr_json_decode(&recipient1.header, (const char *) r1h, strlen(r1h), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&recipient2.header, (const char *) r2h, strlen(r2h), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ recipient = apr_array_push(recipients);
+ *recipient = &recipient1;
+ recipient = apr_array_push(recipients);
+ *recipient = &recipient2;
+
+
+
+
+ apr_json_decode(&header, h, APR_JSON_VALUE_STRING, &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&protected_header, ph, APR_JSON_VALUE_STRING, &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "plain", pl, sizeof(pl), p);
+ apr_jose_encryption_make(&encryption, header, protected_header, p);
+ apr_jose_jwe_json_make(&jose, NULL, recipients, encryption, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7516#appendix-A.5
+ */
+static void test_jose_encode_jwe_json_flattened(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_jose_t *jdata = NULL;
+ apr_json_value_t *header = NULL;
+ apr_json_value_t *protected_header = NULL;
+ apr_jose_recipient_t recipient;
+ apr_jose_encryption_t *encryption;
+ char buf[1024];
+ apr_size_t len = sizeof(buf);
+ apr_off_t offset;
+ apr_status_t status;
+
+ const char *rh = "{\"alg\":\"A128KW\",\"kid\":\"7\"}";
+
+ const char *ph = "{\"enc\":\"A128CBC-HS256\"}";
+ const char *h = "{\"jku\":\"https://server.example.com/keys.jwks\"}";
+
+ const unsigned char pl[] = { 76, 105, 118, 101, 32, 108, 111, 110, 103, 32,
+ 97, 110, 100, 32, 112, 114, 111, 115, 112, 101, 114, 46 };
+
+ const char *expect = "{"
+ "\"protected\":"
+ "\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+ "\"unprotected\":"
+ "{\"jku\":\"https://server.example.com/keys.jwks\"},"
+ "\"header\":"
+ "{\"alg\":\"A128KW\",\"kid\":\"7\"},"
+ "\"encrypted_key\":"
+ "\"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ\","
+ "\"iv\":"
+ "\"AxY8DCtDaGlsbGljb3RoZQ\","
+ "\"ciphertext\":"
+ "\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
+ "\"tag\":"
+ "\"Mz-VPPyU4RlcuYv1IwIvzw\""
+ "}";
+
+ apr_jose_cb_t cb;
+
+ cb.encrypt = encrypt_cb;
+ cb.ctx = tc;
+
+ apr_json_decode(&recipient.header, (const char *) rh, strlen(rh), &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ apr_json_decode(&header, h, APR_JSON_VALUE_STRING, &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+ apr_json_decode(&protected_header, ph, APR_JSON_VALUE_STRING, &offset,
+ APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_jose_data_make(&jdata, "plain", pl, sizeof(pl), p);
+ apr_jose_encryption_make(&encryption, header, protected_header, p);
+ apr_jose_jwe_json_make(&jose, &recipient, NULL, encryption, jdata, p);
+
+ status = apr_jose_encode(bb, NULL, NULL, jose, &cb, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+
+ apr_brigade_flatten(bb, buf, &len);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.5
+ */
+static void test_jose_decode_jws_compact_unsecured(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_json_kv_t *kv;
+ apr_status_t status;
+
+ const char *source = "eyJhbGciOiJub25lIn0"
+ "."
+ "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
+ "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+ ".";
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JWT", bb, &cb, 10, APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_JWT, jose->type);
+
+ kv = apr_json_object_get(jose->jose.jwt->claims, "iss",
+ APR_JSON_VALUE_STRING);
+ ABTS_PTR_NOTNULL(tc, kv);
+ ABTS_INT_EQUAL(tc, APR_JSON_STRING, kv->v->type);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.1
+ */
+static void test_jose_decode_jws_compact_hs256(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_json_kv_t *kv;
+ apr_status_t status;
+
+ const char *source = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
+ "."
+ "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
+ "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+ "."
+ "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JWT", bb, &cb, 10, APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_JWT, jose->type);
+
+ kv = apr_json_object_get(jose->jose.jwt->claims, "iss",
+ APR_JSON_VALUE_STRING);
+ ABTS_PTR_NOTNULL(tc, kv);
+ ABTS_INT_EQUAL(tc, APR_JSON_STRING, kv->v->type);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.6
+ */
+static void test_jose_decode_jws_json_general(abts_case *tc, void *data)
+{
+ const char *source = "{"
+ "\"payload\":"
+ "\"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF"
+ "tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\","
+ "\"signatures\":["
+ "{\"protected\":\"eyJhbGciOiJSUzI1NiJ9\","
+ "\"header\":"
+ "{\"kid\":\"2010-12-29\"},"
+ "\"signature\":"
+ "\"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ"
+ "mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb"
+ "KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl"
+ "b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES"
+ "c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX"
+ "LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw\"},"
+ "{\"protected\":\"eyJhbGciOiJFUzI1NiJ9\","
+ "\"header\":"
+ "{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"},"
+ "\"signature\":"
+ "\"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS"
+ "lSApmWQxfKTUJqPP3-Kg6NU1Q\"}]"
+ "}";
+
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_status_t status;
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JOSE+JSON", bb, &cb, 10, APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+
+ /*
+ * There is nothing in this structure to identify the MIME type of the payload,
+ * so raw data is returned.
+ */
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_DATA, jose->type);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7515#appendix-A.7
+ */
+static void test_jose_decode_jws_json_flattened(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_status_t status;
+
+ const char *source = "{"
+ "\"payload\":"
+ "\"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF"
+ "tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\","
+ "\"protected\":\"eyJhbGciOiJFUzI1NiJ9\","
+ "\"header\":"
+ "{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"},"
+ "\"signature\":"
+ "\"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS"
+ "lSApmWQxfKTUJqPP3-Kg6NU1Q\""
+ "}";
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JOSE+JSON", bb, &cb, 10, APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_DATA, jose->type);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7516#appendix-A.1
+ */
+static void test_jose_decode_jwe_compact_rsaes_oaep_aes_gcm(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_status_t status;
+
+ const char *source = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ."
+ "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe"
+ "ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb"
+ "Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV"
+ "mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8"
+ "1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi"
+ "6UklfCpIMfIjf7iGdXKHzg."
+ "48V1_ALb6US04U3b."
+ "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji"
+ "SdiwkIr3ajwQzaBtQD_A."
+ "XFBoMYUZodetZdvTiFvSkQ";
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JWE", bb, &cb, 10, APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_DATA, jose->type);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7516#appendix-A.4
+ */
+static void test_jose_decode_jwe_json_general(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_status_t status;
+
+ const char *source = "{"
+ "\"protected\":"
+ "\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+ "\"unprotected\":"
+ "{\"jku\":\"https://server.example.com/keys.jwks\"},"
+ "\"recipients\":["
+ "{\"header\":"
+ "{\"alg\":\"RSA1_5\",\"kid\":\"2011-04-29\"},"
+ "\"encrypted_key\":"
+ "\"UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-"
+ "kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKx"
+ "GHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3"
+ "YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPh"
+ "cCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPg"
+ "wCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A\"},"
+ "{\"header\":"
+ "{\"alg\":\"A128KW\",\"kid\":\"7\"},"
+ "\"encrypted_key\":"
+ "\"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ\"}],"
+ "\"iv\":"
+ "\"AxY8DCtDaGlsbGljb3RoZQ\","
+ "\"ciphertext\":"
+ "\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
+ "\"tag\":"
+ "\"Mz-VPPyU4RlcuYv1IwIvzw\""
+ "}";
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JOSE+JSON", bb, &cb, 10,
+ APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_DATA, jose->type);
+
+}
+
+/**
+ * Test from https://tools.ietf.org/html/rfc7516#appendix-A.5
+ */
+static void test_jose_decode_jwe_json_flattened(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_jose_t *jose = NULL;
+ apr_status_t status;
+
+ const char *source = "{"
+ "\"protected\":"
+ "\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+ "\"unprotected\":"
+ "{\"jku\":\"https://server.example.com/keys.jwks\"},"
+ "\"header\":"
+ "{\"alg\":\"A128KW\",\"kid\":\"7\"},"
+ "\"encrypted_key\":"
+ "\"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ\","
+ "\"iv\":"
+ "\"AxY8DCtDaGlsbGljb3RoZQ\","
+ "\"ciphertext\":"
+ "\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
+ "\"tag\":"
+ "\"Mz-VPPyU4RlcuYv1IwIvzw\""
+ "}";
+
+ apr_jose_cb_t cb;
+
+ cb.verify = verify_cb;
+ cb.decrypt = decrypt_cb;
+ cb.ctx = tc;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ apr_brigade_write(bb, NULL, NULL, source, strlen(source));
+
+ status = apr_jose_decode(&jose, "JOSE+JSON", bb, &cb, 10,
+ APR_JOSE_FLAG_NONE, p);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, status);
+ ABTS_PTR_NOTNULL(tc, jose);
+ ABTS_INT_EQUAL(tc, APR_JOSE_TYPE_DATA, jose->type);
+
+}
+
+abts_suite *testjose(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_jose_decode_jws_compact_unsecured, NULL);
+ abts_run_test(suite, test_jose_decode_jws_compact_hs256, NULL);
+ abts_run_test(suite, test_jose_decode_jws_json_general, NULL);
+ abts_run_test(suite, test_jose_decode_jws_json_flattened, NULL);
+ abts_run_test(suite, test_jose_decode_jwe_compact_rsaes_oaep_aes_gcm, NULL);
+ abts_run_test(suite, test_jose_decode_jwe_json_general, NULL);
+ abts_run_test(suite, test_jose_decode_jwe_json_flattened, NULL);
+
+ abts_run_test(suite, test_jose_encode_jws_compact_unsecured, NULL);
+ abts_run_test(suite, test_jose_encode_jws_compact_hs256, NULL);
+ abts_run_test(suite, test_jose_encode_jws_json_general, NULL);
+ abts_run_test(suite, test_jose_encode_jws_json_flattened, NULL);
+ abts_run_test(suite, test_jose_encode_jwe_compact_rsaes_oaep_aes_gcm, NULL);
+ abts_run_test(suite, test_jose_encode_jwe_json_general, NULL);
+ abts_run_test(suite, test_jose_encode_jwe_json_flattened, NULL);
+
+ return suite;
+}