text: /* 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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "JWT", pl, sizeof(pl), p);
      jose = apr_jose_jws_make(NULL, &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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "JWT", pl, sizeof(pl), p);
      jose = apr_jose_jws_make(NULL, &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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "JWT", pl, sizeof(pl), p);
      jose = apr_jose_jws_json_make(NULL, 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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "JWT", pl, sizeof(pl), p);
      jose = apr_jose_jws_json_make(NULL, &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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "JWT", pl, sizeof(pl), p);
      recipient = apr_jose_recipient_make(NULL, header, p);
      encryption = apr_jose_encryption_make(NULL, NULL, protected_header, p);
      jose = apr_jose_jwe_make(NULL, 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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "plain", pl, sizeof(pl), p);
      encryption = apr_jose_encryption_make(NULL, header, protected_header, p);
      jose = apr_jose_jwe_json_make(NULL, 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;
      apr_jose_t *jdata;
      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);
  
      jdata = apr_jose_data_make(NULL, "plain", pl, sizeof(pl), p);
      encryption = apr_jose_encryption_make(NULL, header, protected_header, p);
      jose = apr_jose_jwe_json_make(NULL, &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;
      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;
      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;
      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;
      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;
      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;
      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;
      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;
  }
  