apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From minf...@apache.org
Subject svn commit: r1839819 [1/2] - in /apr/apr/trunk: CHANGES build.conf jose/ jose/apr_jose.c jose/apr_jose_decode.c jose/apr_jose_encode.c test/Makefile.in test/abts_tests.h test/testutil.h
Date Sat, 01 Sep 2018 11:17:15 GMT
Author: minfrin
Date: Sat Sep  1 11:17:14 2018
New Revision: 1839819

URL: http://svn.apache.org/viewvc?rev=1839819&view=rev
Log:
apr_jose: Add support for encoding and decoding of JSON Object 
Signing and Encryption messages as per RFC7515, RFC7516, RFC7517
and RFC7519.

Added:
    apr/apr/trunk/jose/
    apr/apr/trunk/jose/apr_jose.c   (with props)
    apr/apr/trunk/jose/apr_jose_decode.c   (with props)
    apr/apr/trunk/jose/apr_jose_encode.c   (with props)
Modified:
    apr/apr/trunk/CHANGES
    apr/apr/trunk/build.conf
    apr/apr/trunk/test/Makefile.in
    apr/apr/trunk/test/abts_tests.h
    apr/apr/trunk/test/testutil.h

Modified: apr/apr/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr/trunk/CHANGES?rev=1839819&r1=1839818&r2=1839819&view=diff
==============================================================================
--- apr/apr/trunk/CHANGES [utf-8] (original)
+++ apr/apr/trunk/CHANGES [utf-8] Sat Sep  1 11:17:14 2018
@@ -1,6 +1,10 @@
                                                      -*- coding: utf-8 -*-
 Changes for APR 2.0.0
 
+  *) apr_jose: Add support for encoding and decoding of JSON Object
+     Signing and Encryption messages as per RFC7515, RFC7516, RFC7517
+     and RFC7519. [Graham Leggett]
+
   *) Add apr_errprintf() as a convenience function to create and
      populate apu_err_t. [Graham Leggett]
 

Modified: apr/apr/trunk/build.conf
URL: http://svn.apache.org/viewvc/apr/apr/trunk/build.conf?rev=1839819&r1=1839818&r2=1839819&view=diff
==============================================================================
--- apr/apr/trunk/build.conf (original)
+++ apr/apr/trunk/build.conf Sat Sep  1 11:17:14 2018
@@ -26,6 +26,7 @@ paths =
   dbm/sdbm/*.c
   encoding/*.c
   hooks/*.c
+  jose/*.c
   json/*.c
   misc/*.c
   memcache/*.c

Added: apr/apr/trunk/jose/apr_jose.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/jose/apr_jose.c?rev=1839819&view=auto
==============================================================================
--- apr/apr/trunk/jose/apr_jose.c (added)
+++ apr/apr/trunk/jose/apr_jose.c Sat Sep  1 11:17:14 2018
@@ -0,0 +1,353 @@
+/* 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 "apr_jose.h"
+
+APR_DECLARE(apu_err_t *) apr_jose_error(apr_jose_t *jose)
+{
+    return &jose->result;
+}
+
+APR_DECLARE(apr_status_t) apr_jose_make(apr_jose_t **jose, apr_jose_type_e type,
+        apr_pool_t *pool)
+{
+    apr_jose_t *j;
+
+    if (*jose) {
+        j = *jose;
+    } else {
+        *jose = j = apr_pcalloc(pool, sizeof(apr_jose_t));
+        if (!j) {
+            return APR_ENOMEM;
+        }
+    }
+
+    j->pool = pool;
+    j->type = type;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_DATA, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    j->typ = typ;
+    j->jose.data = apr_palloc(pool, sizeof(apr_jose_data_t));
+    if (!j->jose.data) {
+        return APR_ENOMEM;
+    }
+    j->jose.data->data = in;
+    j->jose.data->len = inlen;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JSON, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    j->cty = cty;
+    j->jose.json = apr_palloc(pool, sizeof(apr_jose_json_t));
+    if (!j->jose.json) {
+        return APR_ENOMEM;
+    }
+    j->jose.json->json = json;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_signature_t *s;
+
+    *signature = s = apr_pcalloc(pool, sizeof(apr_jose_signature_t));
+    if (!s) {
+        return APR_ENOMEM;
+    }
+
+    s->header = header;
+    s->protected_header = protected;
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_jose_recipient_make(
+        apr_jose_recipient_t **recipient, apr_json_value_t *header,
+        apr_pool_t *pool)
+{
+    apr_jose_recipient_t *r;
+
+    *recipient = r = apr_pcalloc(pool, sizeof(apr_jose_recipient_t));
+    if (!r) {
+        return APR_ENOMEM;
+    }
+
+    r->header = header;
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_jose_encryption_make(
+        apr_jose_encryption_t **encryption, apr_json_value_t *header,
+        apr_json_value_t *protected_header, apr_pool_t *pool)
+{
+    apr_jose_encryption_t *e;
+
+    *encryption = e = apr_pcalloc(pool, sizeof(apr_jose_encryption_t));
+    if (!e) {
+        return APR_ENOMEM;
+    }
+
+    e->unprotected = header;
+    e->protected = protected_header;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_jose_jwe_t *jwe;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWE, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    j->cty = payload->cty;
+
+    jwe = j->jose.jwe = apr_palloc(pool, sizeof(apr_jose_jwe_t));
+    if (!jwe) {
+        return APR_ENOMEM;
+    }
+
+    jwe->recipient = recipient;
+    jwe->recipients = recipients;
+    jwe->encryption = encryption;
+    jwe->payload = payload;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_jose_jwe_t *jwe;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWE_JSON, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    if (payload) {
+        j->cty = payload->cty;
+    }
+
+    jwe = j->jose.jwe = apr_palloc(pool, sizeof(apr_jose_jwe_t));
+    if (!jwe) {
+        return APR_ENOMEM;
+    }
+
+    jwe->recipient = recipient;
+    jwe->recipients = recipients;
+    jwe->encryption = encryption;
+    jwe->payload = payload;
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_jose_jwk_make(apr_jose_t **jose,
+        apr_json_value_t *key, apr_pool_t *pool)
+{
+    apr_jose_t *j;
+    apr_jose_jwk_t *jwk;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWK, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    jwk = j->jose.jwk = apr_palloc(pool, sizeof(apr_jose_jwk_t));
+    if (!jwk) {
+        return APR_ENOMEM;
+    }
+
+    jwk->key = key;
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_jose_jwks_make(apr_jose_t **jose,
+        apr_json_value_t *keys, apr_pool_t *pool)
+{
+    apr_jose_t *j;
+    apr_jose_jwks_t *jwks;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWKS, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    jwks = j->jose.jwks = apr_palloc(pool, sizeof(apr_jose_jwks_t));
+    if (!jwks) {
+        return APR_ENOMEM;
+    }
+
+    jwks->keys = keys;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_jose_jws_t *jws;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWS, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    if (payload) {
+        j->cty = payload->cty;
+    }
+
+    jws = j->jose.jws = apr_pcalloc(pool, sizeof(apr_jose_jws_t));
+    if (!jws) {
+        return APR_ENOMEM;
+    }
+
+    jws->signature = signature;
+    jws->signatures = signatures;
+    jws->payload = payload;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_jose_jws_t *jws;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWS_JSON, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    if (payload) {
+        j->cty = payload->cty;
+    }
+
+    jws = j->jose.jws = apr_pcalloc(pool, sizeof(apr_jose_jws_t));
+    if (!jws) {
+        return APR_ENOMEM;
+    }
+
+    jws->signature = signature;
+    jws->signatures = signatures;
+    jws->payload = payload;
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_jose_jwt_make(apr_jose_t **jose, apr_json_value_t *claims,
+        apr_pool_t *pool)
+{
+    apr_jose_t *j;
+    apr_jose_jwt_t *jwt;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_JWT, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    j->cty = "JWT";
+
+    jwt = j->jose.jwt = apr_palloc(pool, sizeof(apr_jose_jwt_t));
+    if (!jwt) {
+        return APR_ENOMEM;
+    }
+
+    jwt->claims = claims;
+
+    return APR_SUCCESS;
+}
+
+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)
+{
+    apr_jose_t *j;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_TEXT, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    j = *jose;
+
+    j->cty = cty;
+    j->jose.text = apr_palloc(pool, sizeof(apr_jose_text_t));
+    if (!j->jose.text) {
+        return APR_ENOMEM;
+    }
+    j->jose.text->text = in;
+    j->jose.text->len = inlen;
+
+    return APR_SUCCESS;
+}

Propchange: apr/apr/trunk/jose/apr_jose.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: apr/apr/trunk/jose/apr_jose_decode.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/jose/apr_jose_decode.c?rev=1839819&view=auto
==============================================================================
--- apr/apr/trunk/jose/apr_jose_decode.c (added)
+++ apr/apr/trunk/jose/apr_jose_decode.c Sat Sep  1 11:17:14 2018
@@ -0,0 +1,1694 @@
+/* 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
+ * levelations under the License.
+ */
+
+#include "apr_jose.h"
+#include "apr_lib.h"
+#include "apr_encode.h"
+
+apr_status_t apr_jose_flatten(apr_bucket_brigade *bb, apr_jose_text_t *in,
+        apr_pool_t *pool)
+{
+    apr_bucket *e;
+
+    /* most common case - one pool bucket, avoid unnecessary duplication */
+    e = APR_BRIGADE_FIRST(bb);
+    if (e != APR_BRIGADE_SENTINEL(bb)) {
+        if (!APR_BUCKET_NEXT(e) && APR_BUCKET_IS_POOL(e)) {
+            apr_bucket_pool *p = e->data;
+            if (pool == p->pool) {
+                return apr_bucket_read(e, &in->text, &in->len, APR_BLOCK_READ);
+            }
+        }
+    }
+
+    return apr_brigade_pflatten(bb, (char **)&in->text, &in->len, pool);
+}
+
+apr_status_t apr_jose_decode_jwk(apr_jose_t **jose,
+        const char *typ, apr_bucket_brigade *bb, apr_jose_cb_t *cb,
+        int level, int flags, apr_pool_t *pool)
+{
+    apr_jose_text_t in;
+    apr_off_t offset;
+    apr_status_t status;
+
+    status = apr_jose_jwk_make(jose, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_flatten(bb, &in, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_json_decode(&(*jose)->jose.jwk->key, in.text, in.len, &offset,
+            APR_JSON_FLAGS_WHITESPACE, level, pool);
+
+    if (APR_SUCCESS != status) {
+        char buf[1024];
+        apr_strerror(status, buf, sizeof(buf));
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWK decoding failed at offset %" APR_OFF_T_FMT ": %s",
+                                        offset, buf);
+
+        return status;
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t apr_jose_decode_jwks(apr_jose_t **jose,
+        const char *typ, apr_bucket_brigade *bb, apr_jose_cb_t *cb,
+        int level, int flags, apr_pool_t *pool)
+{
+    apr_jose_text_t in;
+    apr_off_t offset;
+    apr_status_t status;
+
+    status = apr_jose_jwks_make(jose, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_flatten(bb, &in, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_json_decode(&(*jose)->jose.jwks->keys, in.text, in.len,
+            &offset, APR_JSON_FLAGS_WHITESPACE, level, pool);
+
+    if (APR_SUCCESS != status) {
+        char buf[1024];
+        apr_strerror(status, buf, sizeof(buf));
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWKS decoding failed at offset %" APR_OFF_T_FMT ": %s",
+                offset, buf);
+
+        return status;
+    }
+
+    if ((*jose)->jose.jwks->keys->type != APR_JSON_ARRAY) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWKS 'keys' is not an array");
+        return APR_EINVAL;
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t apr_jose_decode_jwt(apr_jose_t **jose,
+        const char *typ, apr_bucket_brigade *bb, apr_jose_cb_t *cb,
+        int level, int flags, apr_pool_t *pool)
+{
+    apr_jose_text_t in;
+    apr_off_t offset;
+    apr_status_t status;
+
+    status = apr_jose_jwt_make(jose, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_flatten(bb, &in, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_json_decode(&(*jose)->jose.jwt->claims, in.text, in.len, &offset,
+            APR_JSON_FLAGS_WHITESPACE, level, pool);
+
+    if (APR_SUCCESS != status) {
+        char buf[1024];
+        apr_strerror(status, buf, sizeof(buf));
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWT decoding failed at offset %" APR_OFF_T_FMT ": %s",
+                offset, buf);
+
+        return status;
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t apr_jose_decode_data(apr_jose_t **jose, const char *typ,
+        apr_bucket_brigade *brigade, apr_jose_cb_t *cb, int level, int flags,
+        apr_pool_t *pool)
+{
+    apr_jose_text_t in;
+    apr_status_t status;
+
+    status = apr_jose_flatten(brigade, &in, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_data_make(jose, typ, (const unsigned char *) in.text, in.len,
+            pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    return status;
+}
+
+apr_status_t apr_jose_decode_jws_signature(apr_jose_t **jose,
+        apr_jose_signature_t *signature, const char *typ, const char *cty,
+        apr_jose_text_t *ph64, apr_jose_text_t *sig64, apr_jose_text_t *pl64,
+        apr_json_value_t *uh, apr_jose_cb_t *cb, int level, int *flags,
+        apr_pool_t *pool, apr_bucket_brigade *bb)
+{
+    const char *phs;
+    apr_size_t phlen;
+    apr_off_t offset;
+    apr_status_t status = APR_SUCCESS;
+
+    /*
+     * Base64url-decode the encoded representation of the JWS Protected
+     * Header, following the restriction that no line breaks,
+     * whitespace, or other additional characters have been used.
+     */
+
+    phs = apr_pdecode_base64(pool, ph64->text, ph64->len, APR_ENCODE_BASE64URL,
+            &phlen);
+
+    if (!phs) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'protected' is not valid base64url");
+        return APR_EINVAL;
+    }
+
+    /*
+     * Verify that the resulting octet sequence is a UTF-8-encoded
+     * representation of a completely valid JSON object conforming to
+     * RFC 7159 [RFC7159]; let the JWS Protected Header be this JSON
+     * object.
+     */
+
+    status = apr_json_decode(&signature->protected_header, phs, phlen, &offset,
+    APR_JSON_FLAGS_WHITESPACE, level, pool);
+    if (APR_SUCCESS != status) {
+        char buf[1024];
+        apr_strerror(status, buf, sizeof(buf));
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'protected' decoding failed at %" APR_OFF_T_FMT ": %s",
+                offset, buf);
+
+        return status;
+    }
+
+    /*
+     * If using the JWS Compact Serialization, let the JOSE Header be
+     * the JWS Protected Header.  Otherwise, when using the JWS JSON
+     * Serialization, let the JOSE Header be the union of the members of
+     * the corresponding JWS Protected Header and JWS Unprotected
+     * Header, all of which must be completely valid JSON objects.
+     * During this step, verify that the resulting JOSE Header does not
+     * contain duplicate Header Parameter names.  When using the JWS
+     * JSON Serialization, this restriction includes that the same
+     * Header Parameter name also MUST NOT occur in distinct JSON object
+     * values that together comprise the JOSE Header.
+     */
+
+    if (uh) {
+        signature->header = apr_json_overlay(pool, signature->protected_header,
+                uh, APR_JSON_FLAGS_STRICT);
+    } else {
+        signature->header = signature->protected_header;
+    }
+
+    /*
+     * Verify that the implementation understands and can process all
+     * fields that it is required to support, whether required by this
+     * specification, by the algorithm being used, or by the "crit"
+     * Header Parameter value, and that the values of those parameters
+     * are also understood and supported.
+     */
+
+    /*
+     * Base64url-decode the encoded representation of the JWS Signature,
+     * following the restriction that no line breaks, whitespace, or
+     * other additional characters have been used.
+     */
+
+    signature->sig.data = apr_pdecode_base64_binary(pool, sig64->text,
+            sig64->len,
+            APR_ENCODE_BASE64URL, &signature->sig.len);
+    if (!signature->sig.data) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS signature decoding failed: bad character");
+        return APR_BADCH;
+    }
+
+    /*
+     * The verify function is expected to perform some or all of the
+     * following steps:
+     *
+     * FIXME fill in from RFC
+     */
+
+    status = cb->verify(bb, *jose, signature, cb->ctx, flags, pool);
+
+    return status;
+}
+
+apr_status_t apr_jose_decode_jwe_recipient(apr_jose_t **jose,
+        apr_bucket_brigade *bb, apr_jose_recipient_t *recipient,
+        apr_jose_encryption_t *encryption, const char *typ, const char *cty,
+        apr_jose_text_t *ph64, apr_jose_text_t *aad64, apr_jose_cb_t *cb,
+        int level, int *dflags, apr_pool_t *pool)
+{
+    apr_json_value_t *header;
+    apr_status_t status;
+
+    /*
+     * If using the JWE Compact Serialization, let the JOSE Header be
+     * the JWE Protected Header.  Otherwise, when using the JWE JSON
+     * Serialization, let the JOSE Header be the union of the members
+     * of the JWE Protected Header, the JWE Shared Unprotected Header
+     * and the corresponding JWE Per-Recipient Unprotected Header, all
+     * of which must be completely valid JSON objects.  During this
+     * step, verify that the resulting JOSE Header does not contain
+     * duplicate Header Parameter names.  When using the JWE JSON
+     * Serialization, this restriction includes that the same Header
+     * Parameter name also MUST NOT occur in distinct JSON object
+     * values that together comprise the JOSE Header.
+     */
+
+    header = apr_json_overlay(pool, recipient->header,
+            apr_json_overlay(pool, encryption->protected,
+                    encryption->unprotected, APR_JSON_FLAGS_STRICT),
+            APR_JSON_FLAGS_STRICT);
+
+    if (!header) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "JWE decryption failed: protected, unprotected and per "
+                "recipient headers had an overlapping element, or were all missing");
+        return APR_EINVAL;
+    }
+
+    /*
+     * Verify that the implementation understands and can process all
+     * fields that it is required to support, whether required by this
+     * specification, by the algorithms being used, or by the "crit"
+     * Header Parameter value, and that the values of those parameters
+     * are also understood and supported.
+     */
+
+    /*
+     * 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.
+     */
+
+    status = cb->decrypt(bb, *jose, recipient, encryption, header, ph64, aad64,
+            cb->ctx, dflags, pool);
+
+    recipient->status = status;
+
+    return status;
+}
+
+apr_status_t apr_jose_decode_compact_jws(apr_jose_t **jose,
+        const char *left, const char *right,
+        apr_json_value_t *ph, const char *typ, const char *cty,
+        apr_jose_text_t *in, apr_jose_text_t *ph64, apr_jose_cb_t *cb,
+        int level, int flags, apr_pool_t *pool, apr_bucket_brigade *bb)
+{
+    apr_jose_jws_t *jws;
+    apr_jose_text_t sig64;
+    apr_jose_text_t pl64;
+    apr_jose_text_t pls;
+    const char *dot;
+    apr_bucket *e;
+    apr_status_t status = APR_EINVAL;
+    int vflags = APR_JOSE_FLAG_NONE;
+
+    if (!cb || !cb->verify) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Verification failed: no verify callback provided");
+        return APR_EINIT;
+    }
+
+    status = apr_jose_jws_make(jose, NULL, NULL, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    jws = (*jose)->jose.jws;
+
+    /*
+     * If using the JWS Compact Serialization, let the JOSE Header be
+     * the JWS Protected Header.
+     */
+
+    status = apr_jose_signature_make(&jws->signature, NULL, ph, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    dot = memchr(left, '.', right - left);
+    if (!dot) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS compact decoding failed: one lonely dot");
+        return APR_BADCH;
+    }
+
+    pl64.text = left;
+    pl64.len = dot - left;
+
+    left = dot + 1;
+
+    sig64.text = left;
+    sig64.len = right - left;
+
+    /*
+     * 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.
+     */
+
+    status = apr_brigade_write(bb, NULL, NULL, in->text,
+            sig64.text - in->text - 1);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_decode_jws_signature(jose, jws->signature,
+            typ, cty, ph64, &sig64, &pl64, NULL, cb, level, &vflags, pool, bb);
+
+    if (APR_SUCCESS != status) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "JWS verification failed: signature rejected");
+        return status;
+    }
+
+    /*
+     * Base64url-decode the encoded representation of the JWS Payload,
+     * following the restriction that no line breaks, whitespace, or
+     * other additional characters have been used.
+     */
+
+    pls.text = apr_pdecode_base64(pool, pl64.text,
+            pl64.len, APR_ENCODE_BASE64URL, &pls.len);
+    if (!pls.text) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'payload' is not valid base64url");
+        return APR_BADCH;
+    }
+
+
+    apr_brigade_cleanup(bb);
+    e = apr_bucket_pool_create(pls.text, pls.len, pool,
+            bb->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(bb, e);
+
+    return APR_SUCCESS;
+}
+
+apr_status_t apr_jose_decode_compact_jwe(apr_jose_t **jose, const char *left,
+        const char *right, apr_json_value_t *ph, apr_json_value_t *enc,
+        const char *typ, const char *cty, apr_jose_text_t *ph64,
+        apr_jose_cb_t *cb, int level, int flags, apr_pool_t *pool,
+        apr_bucket_brigade *bb)
+{
+    const char *dot;
+    apr_jose_jwe_t *jwe;
+    apr_jose_text_t aad64;
+    apr_status_t status;
+    int dflags = APR_JOSE_FLAG_NONE;
+
+    if (!cb || !cb->decrypt) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Decryption failed: no decrypt callback provided");
+        return APR_EINIT;
+    }
+
+    status = apr_jose_jwe_make(jose, NULL, NULL, NULL, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    jwe = (*jose)->jose.jwe;
+
+    status = apr_jose_encryption_make(&jwe->encryption, NULL,
+            NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_recipient_make(&jwe->recipient, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    /*
+     * Parse the JWE representation to extract the serialized values
+     * for the components of the JWE.  When using the JWE Compact
+     * Serialization, these components are the base64url-encoded
+     * representations of the JWE Protected Header, the JWE Encrypted
+     * Key, the JWE Initialization Vector, the JWE Ciphertext, and the
+     * JWE Authentication Tag, and when using the JWE JSON
+     * Serialization, these components also include the base64url-
+     * encoded representation of the JWE AAD and the unencoded JWE
+     * Shared Unprotected Header and JWE Per-Recipient Unprotected
+     * Header values.  When using the JWE Compact Serialization, the
+     * JWE Protected Header, the JWE Encrypted Key, the JWE
+     * Initialization Vector, the JWE Ciphertext, and the JWE
+     * Authentication Tag are represented as base64url-encoded values
+     * in that order, with each value being separated from the next by
+     * a single period ('.') character, resulting in exactly four
+     * delimiting period characters being used.  The JWE JSON
+     * Serialization is described in Section 7.2.
+     */
+
+    /* protected header */
+    if (ph) {
+        jwe->encryption->protected = ph;
+    }
+
+    /* encrypted key */
+    dot = memchr(left, '.', right - left);
+    if (!dot) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: compact JWE decoding failed: one lonely dot");
+        return APR_BADCH;
+    }
+
+    jwe->recipient->ekey.data = apr_pdecode_base64_binary(pool, left,
+            dot - left, APR_ENCODE_BASE64URL, &jwe->recipient->ekey.len);
+    if (!jwe->recipient->ekey.data) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE ekey base64url decoding failed at %" APR_SIZE_T_FMT "",
+                jwe->recipient->ekey.len);
+        return APR_BADCH;
+    }
+
+    left = dot + 1;
+
+    /* iv */
+    dot = memchr(left, '.', right - left);
+    if (!dot) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE compact decoding failed: only two dots");
+        return APR_BADCH;
+    }
+
+    jwe->encryption->iv.data = apr_pdecode_base64_binary(pool, left,
+            dot - left, APR_ENCODE_BASE64URL, &jwe->encryption->iv.len);
+    if (!jwe->encryption->iv.data) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE iv base64url decoding failed at %" APR_SIZE_T_FMT "",
+                                        jwe->encryption->iv.len);
+        return APR_BADCH;
+    }
+
+    left = dot + 1;
+
+    /* ciphertext */
+    dot = memchr(left, '.', right - left);
+    if (!dot) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JOSE compact JWE decoding failed: only three dots");
+
+        return APR_BADCH;
+    }
+
+    jwe->encryption->cipher.data = apr_pdecode_base64_binary(pool, left,
+            dot - left, APR_ENCODE_BASE64URL, &jwe->encryption->cipher.len);
+    if (!jwe->encryption->cipher.data) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE ciphertext base64url decoding failed at %" APR_SIZE_T_FMT "",
+                jwe->encryption->cipher.len);
+
+        return APR_BADCH;
+    }
+
+    left = dot + 1;
+
+    /* tag */
+    jwe->encryption->tag.data = apr_pdecode_base64_binary(pool, left,
+            dot - left, APR_ENCODE_BASE64URL, &jwe->encryption->tag.len);
+    if (!jwe->encryption->tag.data) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE tag base64url decoding failed at %" APR_SIZE_T_FMT "",
+                jwe->encryption->tag.len);
+
+        return APR_BADCH;
+    }
+
+    /* aad is the empty string in compact serialisation */
+    memset(&aad64, 0, sizeof(apr_jose_text_t));
+
+    status = apr_jose_decode_jwe_recipient(jose,
+            bb, jwe->recipient, jwe->encryption, typ, cty, ph64, &aad64, cb,
+            level, &dflags, pool);
+
+    if (APR_SUCCESS != status) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Decryption failed: JWE decryption failed");
+
+        return status;
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t apr_jose_decode_compact(apr_jose_t **jose, const char *typ,
+        apr_bucket_brigade *brigade, apr_jose_cb_t *cb, int level, int flags,
+        apr_pool_t *pool)
+{
+    apr_bucket_brigade *bb;
+    apr_jose_text_t in;
+    apr_jose_text_t ph64;
+    apr_jose_text_t phs;
+    apr_json_kv_t *kv;
+    apr_json_value_t *header;
+    const char *left;
+    const char *right;
+    const char *dot;
+    const char *cty = NULL;
+    apr_off_t offset;
+    apr_status_t status = APR_ENOTIMPL;
+
+    status = apr_jose_flatten(brigade, &in, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    left = in.text;
+    right = in.text + in.len;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_NONE, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    bb = apr_brigade_create(pool, brigade->bucket_alloc);
+    if (!bb) {
+        return APR_ENOMEM;
+    }
+
+    /*
+     * Use a heuristic to see whether this is a JWT, JWE or JWS.
+     *
+     * This is described in https://tools.ietf.org/html/rfc7519#section-7.2
+     */
+
+    /* Verify that the JWT contains at least one period ('.')
+     * character.
+     */
+    dot = memchr(left, '.', in.len);
+    if (!dot) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JOSE compact decoding failed: no dots found");
+
+        return APR_BADCH;
+    }
+
+    ph64.text = in.text;
+    ph64.len = dot - in.text;
+
+    left = dot + 1;
+
+    /*
+     * Let the Encoded JOSE Header be the portion of the JWT before the
+     * first period ('.') character.
+     *
+     * Base64url decode the Encoded JOSE Header following the
+     * restriction that no line breaks, whitespace, or other additional
+     * characters have been used.
+     */
+
+    phs.text = apr_pdecode_base64(pool, ph64.text, ph64.len, APR_ENCODE_BASE64URL,
+            &phs.len);
+    if (!phs.text) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JOSE header base64url decoding failed at %" APR_SIZE_T_FMT "",
+                phs.len);
+
+        return APR_BADCH;
+    }
+
+    /*
+     * Verify that the resulting octet sequence is a UTF-8-encoded
+     * representation of a completely valid JSON object conforming to
+     * RFC 7159 [RFC7159]; let the JOSE Header be this JSON object.
+     */
+
+    status = apr_json_decode(&header, phs.text, phs.len, &offset,
+            APR_JSON_FLAGS_WHITESPACE, level, pool);
+
+    if (APR_SUCCESS != status) {
+        char buf[1024];
+        apr_strerror(status, buf, sizeof(buf));
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JOSE header decoding failed at %" APR_OFF_T_FMT ": %s",
+                offset, buf);
+
+        return status;
+    }
+
+    kv = apr_json_object_get(header, APR_JOSE_JWSE_CONTENT_TYPE,
+            APR_JSON_VALUE_STRING);
+    if (kv) {
+        if (kv->v->type == APR_JSON_STRING) {
+            cty = apr_pstrndup(pool, kv->v->value.string.p,
+                    kv->v->value.string.len);
+        }
+    }
+
+    if (cty) {
+        if (!strcasecmp(cty, "JWT") || !strcasecmp(cty, "application/jwt")) {
+            typ = "JWT";
+        }
+    }
+
+    kv = apr_json_object_get(header, APR_JOSE_JWSE_TYPE, APR_JSON_VALUE_STRING);
+    if (kv) {
+        if (kv->v->type == APR_JSON_STRING) {
+            typ = apr_pstrndup(pool, kv->v->value.string.p,
+                    kv->v->value.string.len);
+        }
+    }
+
+    /*
+     * Determine whether the JWT is a JWS or a JWE using any of the
+     * methods described in Section 9 of [JWE].
+     *
+     * The JOSE Header for a JWS can also be distinguished from the JOSE
+     * Header for a JWE by determining whether an "enc" (encryption
+     * algorithm) member exists.  If the "enc" member exists, it is a
+     * JWE; otherwise, it is a JWS.
+     */
+
+    kv = apr_json_object_get(header, APR_JOSE_JWE_ENCRYPTION,
+            APR_JSON_VALUE_STRING);
+    if (kv) {
+        status = apr_jose_decode_compact_jwe(jose, left, right, header, kv->v,
+                typ, cty, &ph64, cb, level, flags, pool, bb);
+    } else {
+        status = apr_jose_decode_compact_jws(jose, left, right, header, typ, cty, &in, &ph64,
+                cb, level, flags, pool, bb);
+    }
+
+    if (APR_SUCCESS == status) {
+
+        /*
+         * JWT is an anomaly.
+         *
+         * If we have stripped off one level of JOSE, and the content-type
+         * is present and set to JWT, our payload is a next level JOSE.
+         *
+         * If we have stripped off one level of JOSE, and the content-type
+         * is not present but the type is present and set to JWT, our payload
+         * is a JSON object containing claims.
+         */
+
+        if (!cty && typ
+                && (!strcasecmp(typ, "JWT")
+                        || !strcasecmp(typ, "application/jwt"))) {
+
+            status = apr_jose_decode_jwt(
+                    flags & APR_JOSE_FLAG_DECODE_ALL ?
+                            &(*jose)->jose.jws->payload : jose, typ, bb, cb,
+                    level, flags, pool);
+
+        }
+        else {
+
+            status = apr_jose_decode(
+                    flags & APR_JOSE_FLAG_DECODE_ALL ?
+                            &(*jose)->jose.jws->payload : jose, typ, bb, cb,
+                    level, flags, pool);
+        }
+
+    }
+
+    return status;
+}
+
+apr_status_t apr_jose_decode_json_jws(apr_jose_t **jose, apr_json_value_t *val,
+        const char *typ, const char *cty, apr_json_value_t *pl,
+        apr_jose_cb_t *cb, int level, int flags, apr_pool_t *pool,
+        apr_bucket_brigade *bb)
+{
+    apr_jose_text_t ph64;
+    apr_jose_text_t sig64;
+    apr_jose_text_t pl64;
+    apr_jose_text_t pls;
+    apr_jose_jws_t *jws;
+    apr_json_kv_t *kv;
+    apr_json_value_t *uh;
+    apr_bucket *e;
+    apr_status_t status = APR_EINVAL;
+    int vflags = APR_JOSE_FLAG_NONE;
+
+    if (!cb || !cb->verify) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Verification failed: no verify callback provided");
+
+        return APR_EINIT;
+    }
+
+    if (pl->type != APR_JSON_STRING) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'payload' is not a string");
+
+        return APR_EINVAL;
+    }
+
+    pl64.text = pl->value.string.p;
+    pl64.len = pl->value.string.len;
+
+    /*
+     * Base64url-decode the encoded representation of the JWS Payload,
+     * following the restriction that no line breaks, whitespace, or
+     * other additional characters have been used.
+     */
+
+    pls.text = apr_pdecode_base64(pool, pl64.text,
+            pl64.len, APR_ENCODE_BASE64URL, &pls.len);
+    if (!pls.text) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'payload' is not valid base64url");
+
+        return APR_BADCH;
+    }
+
+    status = apr_jose_jws_json_make(jose, NULL, NULL, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    jws = (*jose)->jose.jws;
+
+    /* for each signature in signatures... */
+    kv = apr_json_object_get(val, APR_JOSE_JWS_SIGNATURES,
+            APR_JSON_VALUE_STRING);
+    if (kv) {
+        apr_json_value_t *sigs = kv->v;
+        int i;
+        int verified = 0;
+
+        if (sigs->type != APR_JSON_ARRAY) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWS 'signatures' is not an array");
+
+            return APR_EINVAL;
+        }
+
+        jws->signatures = apr_array_make(pool, sigs->value.array->array->nelts,
+                sizeof(apr_jose_signature_t *));
+        if (!jws->signatures) {
+            return APR_ENOMEM;
+        }
+
+        /*
+         * 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.
+         */
+
+        for (i = 0; i < sigs->value.array->array->nelts; i++) {
+            apr_json_value_t *sig = apr_json_array_get(sigs, i);
+
+            if (sig) {
+                apr_jose_signature_t **sp;
+
+                if (sig->type != APR_JSON_OBJECT) {
+                    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                            "Syntax error: JWS 'signatures' array contains a non-object");
+
+                    return APR_EINVAL;
+                }
+
+                sp = apr_array_push(jws->signatures);
+                *sp = apr_pcalloc(pool, sizeof(apr_jose_signature_t));
+                if (!*sp) {
+                    return APR_ENOMEM;
+                }
+
+                kv = apr_json_object_get(sig, APR_JOSE_JWSE_PROTECTED,
+                        APR_JSON_VALUE_STRING);
+                if (!kv) {
+                    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                            "Syntax error: JWS 'protected' header is missing");
+
+                    return APR_EINVAL;
+                }
+
+                if (kv->v->type != APR_JSON_STRING) {
+                    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                            "Syntax error: JWS 'protected' is not a string");
+
+                    return APR_EINVAL;
+                }
+
+                ph64.text = kv->v->value.string.p;
+                ph64.len = kv->v->value.string.len;
+
+                kv = apr_json_object_get(sig, APR_JOSE_JWSE_HEADER,
+                        APR_JSON_VALUE_STRING);
+                if (kv) {
+
+                    if (kv->v->type != APR_JSON_OBJECT) {
+                        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                                "Syntax error: JWS 'header' is not an object");
+
+                        return APR_EINVAL;
+                    }
+
+                    uh = kv->v;
+                }
+                else {
+                    uh = NULL;
+                }
+
+                kv = apr_json_object_get(sig, APR_JOSE_JWS_SIGNATURE,
+                        APR_JSON_VALUE_STRING);
+                if (!kv) {
+                    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                            "Syntax error: JWS 'signature' header is missing");
+
+                    return APR_EINVAL;
+                }
+
+                if (kv->v->type != APR_JSON_STRING) {
+                    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                            "Syntax error: JWS 'signature' is not a string");
+
+                    return APR_EINVAL;
+                }
+
+                sig64.text = kv->v->value.string.p;
+                sig64.len = kv->v->value.string.len;
+
+                /*
+                 * 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.
+                 */
+
+                apr_brigade_cleanup(bb);
+
+                status = apr_brigade_write(bb, NULL, NULL, ph64.text,
+                        ph64.len);
+                if (APR_SUCCESS != status) {
+                    return status;
+                }
+
+                status = apr_brigade_putc(bb, NULL, NULL, '.');
+                if (APR_SUCCESS != status) {
+                    return status;
+                }
+
+                status = apr_brigade_write(bb, NULL, NULL, pl64.text,
+                        pl64.len);
+                if (APR_SUCCESS != status) {
+                    return status;
+                }
+
+                status = apr_jose_decode_jws_signature(jose, *sp, typ, cty,
+                        &ph64, &sig64, &pl64, uh, cb, level, &vflags, pool, bb);
+
+                if (APR_SUCCESS == status) {
+
+                    verified++;
+
+                    if (verified == 1) {
+
+                        apr_brigade_cleanup(bb);
+                        e = apr_bucket_pool_create(pls.text, pls.len, pool,
+                                bb->bucket_alloc);
+                        APR_BRIGADE_INSERT_TAIL(bb, e);
+
+                        status = apr_jose_decode(
+                                flags & APR_JOSE_FLAG_DECODE_ALL ?
+                                        &(*jose)->jose.jwe->payload : jose, typ,
+                                bb, cb, level, flags, pool);
+
+                        if (APR_SUCCESS != status) {
+                            return status;
+                        }
+
+                    }
+
+                }
+
+                if (!(vflags & APR_JOSE_FLAG_BREAK)) {
+                    break;
+                }
+
+            }
+
+        }
+
+        if (!verified) {
+            apr_jose_t *j = *jose;
+
+            if (!j->result.msg) {
+                apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                        "JWS verification failed: no signatures matched");
+            }
+
+            return APR_ENOVERIFY;
+        }
+
+        return APR_SUCCESS;
+    }
+
+    status = apr_jose_signature_make(&jws->signature, NULL, NULL,
+            pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    kv = apr_json_object_get(val, APR_JOSE_JWSE_PROTECTED,
+            APR_JSON_VALUE_STRING);
+    if (!kv) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'protected' header is missing");
+
+        return APR_EINVAL;
+    }
+
+    if (kv->v->type != APR_JSON_STRING) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'protected' is not a string");
+
+        return APR_EINVAL;
+    }
+
+    ph64.text = kv->v->value.string.p;
+    ph64.len = kv->v->value.string.len;
+
+    kv = apr_json_object_get(val, APR_JOSE_JWSE_HEADER, APR_JSON_VALUE_STRING);
+    if (kv) {
+
+        if (kv->v->type != APR_JSON_OBJECT) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWS 'header' is not an object");
+
+            return APR_EINVAL;
+        }
+
+        uh = kv->v;
+    }
+    else {
+        uh = NULL;
+    }
+
+    kv = apr_json_object_get(val, APR_JOSE_JWS_SIGNATURE,
+            APR_JSON_VALUE_STRING);
+    if (!kv) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'signature' header is missing");
+
+        return APR_EINVAL;
+    }
+
+    if (kv->v->type != APR_JSON_STRING) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWS 'signature' is not a string");
+
+        return APR_EINVAL;
+    }
+
+    sig64.text = kv->v->value.string.p;
+    sig64.len = kv->v->value.string.len;
+
+    /*
+     * 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.
+     */
+
+    apr_brigade_cleanup(bb);
+
+    status = apr_brigade_write(bb, NULL, NULL, ph64.text,
+            ph64.len);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_brigade_putc(bb, NULL, NULL, '.');
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_brigade_write(bb, NULL, NULL, pl64.text,
+            pl64.len);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_decode_jws_signature(jose, jws->signature, typ, cty,
+            &ph64, &sig64, &pl64, uh, cb, level, &vflags, pool, bb);
+
+    if (APR_SUCCESS != status) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "JWS verification failed: signature rejected");
+
+        return status;
+    }
+
+    apr_brigade_cleanup(bb);
+    e = apr_bucket_pool_create(pls.text, pls.len, pool,
+            bb->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(bb, e);
+
+    return apr_jose_decode(
+            flags & APR_JOSE_FLAG_DECODE_ALL ?
+                    &(*jose)->jose.jws->payload : jose, typ, bb, cb,
+            level, flags, pool);
+}
+
+apr_status_t apr_jose_decode_json_jwe(apr_jose_t **jose, apr_json_value_t *val,
+        const char *typ, const char *cty, apr_json_value_t *ct,
+        apr_jose_cb_t *cb, int level, int flags, apr_pool_t *pool,
+        apr_bucket_brigade *bb)
+{
+    apr_jose_text_t ph64;
+    apr_jose_text_t aad64;
+    apr_jose_jwe_t *jwe;
+    apr_json_kv_t *kv;
+    apr_status_t status = APR_EGENERAL;
+    int dflags = APR_JOSE_FLAG_NONE;
+
+    if (!cb || !cb->decrypt) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Decryption failed: no decrypt callback provided");
+
+        return APR_EINIT;
+    }
+
+    if (ct->type != APR_JSON_STRING) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE 'ciphertext' is not a string");
+
+        return APR_EINVAL;
+    }
+
+    status = apr_jose_jwe_json_make(jose, NULL, NULL, NULL, NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+    jwe = (*jose)->jose.jwe;
+
+    status = apr_jose_encryption_make(&jwe->encryption, NULL,
+            NULL, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    /*
+     * Base64url decode the encoded representations of the JWE
+     * Protected Header, the JWE Encrypted Key, the JWE Initialization
+     * Vector, the JWE Ciphertext, the JWE Authentication Tag, and the
+     * JWE AAD, following the restriction that no line breaks,
+     * whitespace, or other additional characters have been used.
+     */
+
+    kv = apr_json_object_get(val, APR_JOSE_JWSE_PROTECTED,
+            APR_JSON_VALUE_STRING);
+    if (kv) {
+        const char *phs;
+        apr_size_t phlen;
+        apr_off_t offset;
+
+        if (kv->v->type != APR_JSON_STRING) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'protected' is not a string");
+
+            return APR_EINVAL;
+        }
+
+        /*
+         * Verify that the octet sequence resulting from decoding the
+         * encoded JWE Protected Header is a UTF-8-encoded representation
+         * of a completely valid JSON object conforming to RFC 7159
+         * [RFC7159]; let the JWE Protected Header be this JSON object.
+         */
+
+        ph64.text = kv->v->value.string.p;
+        ph64.len = kv->v->value.string.len;
+
+        phs = apr_pdecode_base64(pool, ph64.text,
+                ph64.len, APR_ENCODE_BASE64URL, &phlen);
+
+        if (!phs) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'protected' is not valid base64url");
+
+            return APR_EINVAL;
+        }
+
+        status = apr_json_decode(&jwe->encryption->protected, phs, phlen, &offset,
+                APR_JSON_FLAGS_WHITESPACE, level, pool);
+        if (APR_SUCCESS != status) {
+            char buf[1024];
+            apr_strerror(status, buf, sizeof(buf));
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'protected' decoding failed at %" APR_OFF_T_FMT ": %s",
+                    offset, buf);
+
+            return status;
+        }
+
+    }
+    else {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE 'protected' header is missing");
+
+        return APR_EINVAL;
+    }
+
+    /* unprotected */
+    kv = apr_json_object_get(val, APR_JOSE_JWE_UNPROTECTED,
+            APR_JSON_VALUE_STRING);
+    if (kv) {
+
+        if (kv->v->type != APR_JSON_OBJECT) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'unprotected' is not an object");
+
+            return APR_EINVAL;
+        }
+
+        jwe->encryption->unprotected = kv->v;
+    }
+
+    /* ciphertext */
+    jwe->encryption->cipher.data = apr_pdecode_base64_binary(pool,
+            ct->value.string.p, ct->value.string.len, APR_ENCODE_BASE64URL,
+            &jwe->encryption->cipher.len);
+    if (!jwe->encryption->cipher.data) {
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JWE 'ciphertext' is not valid base64url");
+
+        return APR_BADCH;
+    }
+
+    /* iv */
+    kv = apr_json_object_get(val, APR_JOSE_JWE_IV, APR_JSON_VALUE_STRING);
+    if (kv) {
+
+        if (kv->v->type != APR_JSON_STRING) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'iv' is not a string");
+
+            return APR_EINVAL;
+        }
+
+        jwe->encryption->iv.data = apr_pdecode_base64_binary(pool,
+                kv->v->value.string.p, kv->v->value.string.len, APR_ENCODE_BASE64URL,
+                &jwe->encryption->iv.len);
+        if (!jwe->encryption->iv.data) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'iv' is not valid base64url");
+
+            return APR_BADCH;
+        }
+
+    }
+
+    /* tag */
+    kv = apr_json_object_get(val, APR_JOSE_JWE_TAG, APR_JSON_VALUE_STRING);
+    if (kv) {
+
+        if (kv->v->type != APR_JSON_STRING) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'tag' is not a string");
+
+            return APR_EINVAL;
+        }
+
+        jwe->encryption->tag.data = apr_pdecode_base64_binary(pool,
+                kv->v->value.string.p, kv->v->value.string.len, APR_ENCODE_BASE64URL,
+                &jwe->encryption->tag.len);
+        if (!jwe->encryption->tag.data) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'tag' is not valid base64url");
+
+            return APR_BADCH;
+        }
+
+    }
+
+    /* aad */
+    kv = apr_json_object_get(val, APR_JOSE_JWE_AAD, APR_JSON_VALUE_STRING);
+    if (kv) {
+
+        if (kv->v->type != APR_JSON_STRING) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'aad' is not a string");
+
+            return APR_EINVAL;
+        }
+
+        aad64.text = kv->v->value.string.p;
+        aad64.len = kv->v->value.string.len;
+
+        jwe->encryption->aad.data = apr_pdecode_base64_binary(pool,
+                aad64.text, aad64.len, APR_ENCODE_BASE64URL,
+                &jwe->encryption->aad.len);
+        if (!jwe->encryption->aad.data) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'add' is not valid base64url");
+
+            return APR_BADCH;
+        }
+
+    }
+    else {
+        memset(&aad64, 0, sizeof(apr_jose_text_t));
+    }
+
+    /* for each recipient in recipients... */
+    kv = apr_json_object_get(val, APR_JOSE_JWE_RECIPIENTS,
+            APR_JSON_VALUE_STRING);
+    if (kv) {
+        apr_json_value_t *recips = kv->v;
+        int i;
+        int decrypt = 0;
+
+        if (recips->type != APR_JSON_ARRAY) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'recipients' is not an array");
+
+            return APR_EINVAL;
+        }
+
+        (*jose)->jose.jwe->recipients = apr_array_make(pool,
+                recips->value.array->array->nelts, sizeof(apr_jose_recipient_t *));
+        if (!(*jose)->jose.jwe->recipients) {
+            return APR_ENOMEM;
+        }
+
+        for (i = 0; i < recips->value.array->array->nelts; i++) {
+            apr_json_value_t *recip = apr_json_array_get(recips, i);
+
+            if (recip) {
+                apr_jose_recipient_t **rp;
+                apr_jose_recipient_t *recipient;
+
+                if (recip->type != APR_JSON_OBJECT) {
+                    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                            "Syntax error: JWE 'recipients' array contains a non-object");
+
+                    return APR_EINVAL;
+                }
+
+                rp = apr_array_push((*jose)->jose.jwe->recipients);
+                *rp = recipient = apr_pcalloc(pool, sizeof(apr_jose_recipient_t));
+                if (!recipient) {
+                    return APR_ENOMEM;
+                }
+
+                /* unprotected */
+                kv = apr_json_object_get(recip, APR_JOSE_JWSE_HEADER,
+                        APR_JSON_VALUE_STRING);
+                if (kv) {
+
+                    if (kv->v->type != APR_JSON_OBJECT) {
+                        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                                "Syntax error: JWE 'header' is not an object");
+
+                        return APR_EINVAL;
+                    }
+
+                    recipient->header = kv->v;
+                }
+
+                kv = apr_json_object_get(recip, APR_JOSE_JWE_EKEY,
+                        APR_JSON_VALUE_STRING);
+                if (kv) {
+
+                    if (kv->v->type != APR_JSON_STRING) {
+                        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                                "Syntax error: JWE 'encrypted_key' element must be a string");
+
+                        return APR_EINVAL;
+                    }
+
+                    recipient->ekey.data = apr_pdecode_base64_binary(pool,
+                            kv->v->value.string.p, kv->v->value.string.len, APR_ENCODE_BASE64URL,
+                            &recipient->ekey.len);
+                    if (!recipient->ekey.data) {
+                        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                                "Syntax error: JWE 'encrypted_key' is not valid base64url");
+
+                        return APR_BADCH;
+                    }
+
+                }
+
+                apr_brigade_cleanup(bb);
+
+                status = apr_jose_decode_jwe_recipient(jose, bb, recipient,
+                        jwe->encryption, typ, cty, &ph64, &aad64, cb, level,
+                        &dflags, pool);
+
+                if (APR_SUCCESS == status) {
+
+                    decrypt++;
+
+                    if (decrypt == 1) {
+
+                        status = apr_jose_decode(
+                                flags & APR_JOSE_FLAG_DECODE_ALL ?
+                                        &(*jose)->jose.jwe->payload : jose, typ,
+                                        bb, cb, level, flags, pool);
+
+                        if (APR_SUCCESS != status) {
+                            return status;
+                        }
+
+                    }
+
+                }
+
+                if (!(dflags & APR_JOSE_FLAG_BREAK)) {
+                    break;
+                }
+
+            }
+
+        }
+
+        if (!decrypt) {
+            apr_jose_t *j = *jose;
+
+            if (!j->result.msg) {
+                apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                        "JWE decryption failed: no recipients matched");
+            }
+
+            return APR_ECRYPT;
+        }
+
+        return APR_SUCCESS;
+    }
+
+    /* ok, just one recipient */
+    kv = apr_json_object_get(val, APR_JOSE_JWE_EKEY, APR_JSON_VALUE_STRING);
+    if (kv) {
+        apr_json_value_t *ekey = kv->v;
+        apr_jose_recipient_t *recipient;
+
+        if (ekey->type != APR_JSON_STRING) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Syntax error: JWE 'encrypted_key' element must be a string");
+
+            return APR_EINVAL;
+        }
+
+        recipient = apr_pcalloc(pool, sizeof(apr_jose_recipient_t));
+        if (!recipient) {
+            return APR_ENOMEM;
+        }
+
+        /* unprotected */
+        kv = apr_json_object_get(val, APR_JOSE_JWSE_HEADER,
+                APR_JSON_VALUE_STRING);
+        if (kv) {
+
+            if (kv->v->type != APR_JSON_OBJECT) {
+                apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                        "Syntax error: JWE 'header' is not an object");
+
+                return APR_EINVAL;
+            }
+
+            recipient->header = kv->v;
+        }
+
+        apr_brigade_cleanup(bb);
+
+        status = apr_jose_decode_jwe_recipient(jose, bb, recipient,
+                jwe->encryption, typ, cty, &ph64, &aad64, cb, level, &dflags,
+                pool);
+
+        if (APR_SUCCESS == status) {
+
+            return apr_jose_decode(
+                    flags & APR_JOSE_FLAG_DECODE_ALL ?
+                            &(*jose)->jose.jwe->payload : jose, typ, bb,
+                    cb, level, flags, pool);
+
+        }
+
+        if (APR_SUCCESS != status) {
+            apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                    "Decryption failed: JWE decryption failed");
+        }
+
+    }
+
+    /* no recipient at all */
+    apr_errprintf(&(*jose)->result, pool, NULL, 0,
+            "Syntax error: No 'recipients' or 'encrypted_key' present");
+
+    return APR_EINVAL;
+
+}
+
+apr_status_t apr_jose_decode_json(apr_jose_t **jose, const char *typ,
+        apr_bucket_brigade *brigade, apr_jose_cb_t *cb, int level,
+        int flags, apr_pool_t *pool)
+{
+    apr_json_value_t *val;
+    apr_bucket_brigade *bb;
+    apr_jose_text_t in;
+    apr_off_t offset;
+    apr_status_t status;
+
+    status = apr_jose_make(jose, APR_JOSE_TYPE_NONE, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    status = apr_jose_flatten(brigade, &in, pool);
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    bb = apr_brigade_create(pool, brigade->bucket_alloc);
+    if (!bb) {
+        return APR_ENOMEM;
+    }
+
+    /*
+     * Parse the JWS representation to extract the serialized values for
+     * the components of the JWS.  When using the JWS Compact
+     * Serialization, these components are the base64url-encoded
+     * representations of the JWS Protected Header, the JWS Payload, and
+     * the JWS Signature, and when using the JWS JSON Serialization,
+     * these components also include the unencoded JWS Unprotected
+     * Header value.  When using the JWS Compact Serialization, the JWS
+     * Protected Header, the JWS Payload, and the JWS Signature are
+     * represented as base64url-encoded values in that order, with each
+     * value being separated from the next by a single period ('.')
+     * character, resulting in exactly two delimiting period characters
+     * being used.  The JWS JSON Serialization is described in
+     * Section 7.2.
+     */
+
+    status = apr_json_decode(&val, in.text, in.len, &offset,
+            APR_JSON_FLAGS_WHITESPACE, level, pool);
+    if (APR_SUCCESS == status) {
+        apr_json_kv_t *kv;
+        const char *cty = NULL;
+
+        /*
+         * 9.  Distinguishing between JWS and JWE Objects
+         *
+         * If the object is using the JWS JSON Serialization or the JWE JSON
+         * Serialization, the members used will be different.  JWSs have a
+         * "payload" member and JWEs do not.  JWEs have a "ciphertext" member
+         * and JWSs do not.
+         */
+
+        /* are we JWS? */
+        kv = apr_json_object_get(val, APR_JOSE_JWS_PAYLOAD,
+                APR_JSON_VALUE_STRING);
+        if (kv) {
+
+            return apr_jose_decode_json_jws(jose, val, typ, cty,
+                    kv->v, cb, level, flags, pool, bb);
+
+        }
+
+        /* are we JWE? */
+        kv = apr_json_object_get(val, APR_JOSE_JWE_CIPHERTEXT,
+                APR_JSON_VALUE_STRING);
+        if (kv) {
+
+            return apr_jose_decode_json_jwe(jose, val, typ, cty,
+                    kv->v, cb, level, flags, pool, bb);
+
+        }
+
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JOSE JSON contained neither a 'payload' nor a 'ciphertext'");
+
+        return APR_EINVAL;
+
+    }
+    else {
+        char buf[1024];
+        apr_strerror(status, buf, sizeof(buf));
+        apr_errprintf(&(*jose)->result, pool, NULL, 0,
+                "Syntax error: JOSE JSON decoding failed at character %" APR_OFF_T_FMT ": %s",
+                offset, buf);
+    }
+
+    return status;
+}
+
+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)
+{
+
+    /* handle JOSE and JOSE+JSON */
+    if (typ) {
+        switch (typ[0]) {
+        case 'a':
+        case 'A': {
+
+            if (!strncasecmp(typ, "application/", 12)) {
+                const char *sub = typ + 12;
+
+                if (!strcasecmp(sub, "jwt")) {
+                    return apr_jose_decode_compact(jose, typ, brigade, cb,
+                            level, flags, pool);
+                } else if (!strcasecmp(sub, "jose")) {
+                    return apr_jose_decode_compact(jose, NULL, brigade, cb,
+                            level, flags, pool);
+                } else if (!strcasecmp(sub, "jose+json")) {
+                    return apr_jose_decode_json(jose, NULL, brigade, cb, level,
+                            flags, pool);
+                } else if (!strcasecmp(sub, "jwk+json")) {
+                    return apr_jose_decode_jwk(jose, typ, brigade, cb, level,
+                            flags, pool);
+                } else if (!strcasecmp(sub, "jwk-set+json")) {
+                    return apr_jose_decode_jwks(jose, typ, brigade, cb, level,
+                            flags, pool);
+                }
+
+            }
+
+            break;
+        }
+        case 'J':
+        case 'j': {
+
+            if (!strcasecmp(typ, "JWT")) {
+                return apr_jose_decode_compact(jose, typ, brigade, cb, level, flags,
+                        pool);
+            } else if (!strcasecmp(typ, "JOSE")) {
+                return apr_jose_decode_compact(jose, NULL, brigade, cb, level,
+                        flags, pool);
+            } else if (!strcasecmp(typ, "JOSE+JSON")) {
+                return apr_jose_decode_json(jose, NULL, brigade, cb, level, flags,
+                        pool);
+            } else if (!strcasecmp(typ, "JWK+JSON")) {
+                return apr_jose_decode_jwk(jose, typ, brigade, cb, level, flags,
+                        pool);
+            } else if (!strcasecmp(typ, "JWK-SET+JSON")) {
+                return apr_jose_decode_jwks(jose, typ, brigade, cb, level, flags,
+                        pool);
+            }
+
+            break;
+        }
+        }
+    }
+
+    return apr_jose_decode_data(jose, typ, brigade, cb, level, flags, pool);
+}

Propchange: apr/apr/trunk/jose/apr_jose_decode.c
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message