Coverage Report

Created: 2026-09-03 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/jose.c
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
/***************************************************************************
21
 * Copyright (C) 2017-2026 ZmartZone Holding BV
22
 * Copyright (C) 2013-2017 Ping Identity Corporation
23
 * All rights reserved.
24
 *
25
 * DISCLAIMER OF WARRANTIES:
26
 *
27
 * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
28
 * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING,
29
 * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT,
30
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  NOR ARE THERE ANY
31
 * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE
32
 * USAGE.  FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET
33
 * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE
34
 * WILL BE UNINTERRUPTED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
35
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF
37
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
 *
41
 * JSON Web Token handling
42
 *
43
 * @Author: Hans Zandbelt - hans.zandbelt@openidc.com
44
 */
45
46
#include <apr_base64.h>
47
#define APR_WANT_BYTEFUNC
48
#include <apr_want.h>
49
50
#ifdef USE_LIBBROTLI
51
#include <brotli/decode.h>
52
#include <brotli/encode.h>
53
#endif
54
#ifdef USE_ZLIB
55
#include <zlib.h>
56
#endif
57
58
#include "jose.h"
59
60
/* cjose exposes the backend JSON type, so this file is the only raw JSON user outside json.c. */
61
#include <jansson.h>
62
63
#include <cjose/cjose.h>
64
65
#include <openssl/bn.h>
66
#include <openssl/err.h>
67
#include <openssl/evp.h>
68
#include <openssl/hmac.h>
69
#include <openssl/opensslv.h>
70
#include <openssl/pem.h>
71
#include <openssl/rsa.h>
72
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
73
#include <openssl/core_names.h>
74
#endif
75
76
#include "util/util.h"
77
78
#include "jose/internal.h"
79
80
/*
81
 * assemble an error report
82
 */
83
void _oidc_jose_error_set(oidc_jose_error_t *error, const char *source, const int line, const char *function,
84
96.2k
        const char *fmt, ...) {
85
96.2k
  if (error == NULL)
86
0
    return;
87
96.2k
  snprintf(error->source, OIDC_JOSE_ERROR_SOURCE_LENGTH, "%s", source);
88
96.2k
  error->line = line;
89
96.2k
  snprintf(error->function, OIDC_JOSE_ERROR_FUNCTION_LENGTH, "%s", function);
90
96.2k
  va_list ap;
91
96.2k
  va_start(ap, fmt);
92
96.2k
  vsnprintf(error->text, OIDC_JOSE_ERROR_TEXT_LENGTH, fmt ? fmt : "(null)", ap);
93
96.2k
  va_end(ap);
94
96.2k
}
95
96
/*
97
 * hash a sequence of bytes with a specific algorithm and return the result as a base64url-encoded \0 terminated string
98
 */
99
apr_byte_t oidc_jose_hash_and_base64url_encode(apr_pool_t *pool, const char *openssl_hash_algo, const char *input,
100
41.0k
                 int input_len, char **output, oidc_jose_error_t *err) {
101
41.0k
  unsigned char *hashed = NULL;
102
41.0k
  unsigned int hashed_len = 0;
103
41.0k
  if (oidc_jose_hash_bytes(pool, openssl_hash_algo, (const unsigned char *)input, input_len, &hashed, &hashed_len,
104
41.0k
         err) == FALSE)
105
0
    return FALSE;
106
41.0k
  char *out = NULL;
107
41.0k
  size_t out_len;
108
41.0k
  cjose_err cjose_err;
109
41.0k
  if (cjose_base64url_encode(hashed, hashed_len, &out, &out_len, &cjose_err) == FALSE) {
110
0
    oidc_jose_error(err, "cjose_base64url_encode failed: %s", oidc_cjose_e2s(pool, cjose_err));
111
0
    return FALSE;
112
0
  }
113
41.0k
  *output = apr_pstrmemdup(pool, out, out_len);
114
41.0k
  cjose_get_dealloc()(out);
115
41.0k
  return TRUE;
116
41.0k
}
117
118
/*
119
 * check if a string is an element of an array of strings
120
 */
121
241
static apr_byte_t oidc_jose_array_has_string(apr_array_header_t *haystack, const char *needle) {
122
241
  int i = 0;
123
1.64k
  while (i < haystack->nelts) {
124
1.42k
    if (_oidc_strcmp(APR_ARRAY_IDX(haystack, i, const char *), needle) == 0)
125
25
      return TRUE;
126
1.39k
    i++;
127
1.39k
  }
128
216
  return FALSE;
129
241
}
130
131
/*
132
 * return all supported signing algorithms
133
 */
134
114
apr_array_header_t *oidc_jose_jws_supported_algorithms(apr_pool_t *pool) {
135
114
  apr_array_header_t *result = apr_array_make(pool, 12, sizeof(const char *));
136
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_RS256;
137
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_RS384;
138
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_RS512;
139
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_PS256;
140
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_PS384;
141
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_PS512;
142
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_HS256;
143
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_HS384;
144
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_HS512;
145
114
#if (OIDC_JOSE_EC_SUPPORT)
146
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_ES256;
147
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_ES384;
148
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_ES512;
149
114
#endif
150
114
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_NONE;
151
114
  return result;
152
114
}
153
154
/*
155
 * check if the provided signing algorithm is supported
156
 */
157
63
apr_byte_t oidc_jose_jws_algorithm_is_supported(apr_pool_t *pool, const char *alg) {
158
63
  return oidc_jose_array_has_string(oidc_jose_jws_supported_algorithms(pool), alg);
159
63
}
160
161
/*
162
 * return all supported content encryption key algorithms
163
 */
164
126
apr_array_header_t *oidc_jose_jwe_supported_algorithms(apr_pool_t *pool) {
165
126
  apr_array_header_t *result = apr_array_make(pool, 4, sizeof(const char *));
166
126
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_A128KW;
167
126
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_A192KW;
168
126
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_A256KW;
169
126
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ALG_RSA_OAEP;
170
126
  return result;
171
126
}
172
173
/*
174
 * check if the provided content encryption key algorithm is supported
175
 */
176
66
apr_byte_t oidc_jose_jwe_algorithm_is_supported(apr_pool_t *pool, const char *alg) {
177
66
  return oidc_jose_array_has_string(oidc_jose_jwe_supported_algorithms(pool), alg);
178
66
}
179
180
/*
181
 * return all supported encryption algorithms
182
 */
183
217
apr_array_header_t *oidc_jose_jwe_supported_encryptions(apr_pool_t *pool) {
184
217
  apr_array_header_t *result = apr_array_make(pool, 5, sizeof(const char *));
185
217
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ENC_A128CBC_HS256;
186
217
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ENC_A192CBC_HS384;
187
217
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ENC_A256CBC_HS512;
188
217
#if (OIDC_JOSE_GCM_SUPPORT)
189
217
  APR_ARRAY_PUSH(result, const char *) = CJOSE_HDR_ENC_A256GCM;
190
217
#endif
191
217
  return result;
192
217
}
193
194
/*
195
 * check if the provided encryption algorithm is supported
196
 */
197
112
apr_byte_t oidc_jose_jwe_encryption_is_supported(apr_pool_t *pool, const char *enc) {
198
112
  return oidc_jose_array_has_string(oidc_jose_jwe_supported_encryptions(pool), enc);
199
112
}
200
201
/*
202
 * get (optional) string from JWT
203
 */
204
apr_byte_t oidc_jose_get_string(apr_pool_t *pool, const json_t *json, const char *claim_name, apr_byte_t is_mandatory,
205
82.5k
        char **result, oidc_jose_error_t *err) {
206
82.5k
  const json_t *v = json_object_get(json, claim_name);
207
82.5k
  if (v != NULL) {
208
15.8k
    if (json_is_string(v)) {
209
15.6k
      *result = apr_pstrdup(pool, json_string_value(v));
210
15.6k
    } else if (is_mandatory) {
211
0
      oidc_jose_error(err, "mandatory JSON key \"%s\" was found but the type is not a string",
212
0
          claim_name);
213
0
      return FALSE;
214
0
    }
215
66.7k
  } else if (is_mandatory) {
216
2.13k
    oidc_jose_error(err, "mandatory JSON key \"%s\" could not be found", claim_name);
217
2.13k
    return FALSE;
218
2.13k
  }
219
80.4k
  return TRUE;
220
82.5k
}
221
222
/*
223
 * parse (optional) timestamp from payload
224
 */
225
apr_byte_t oidc_jose_get_timestamp(const json_t *json, const char *claim_name, apr_byte_t is_mandatory, double *result,
226
26.1k
           oidc_jose_error_t *err) {
227
26.1k
  *result = OIDC_JWT_CLAIM_TIME_EMPTY;
228
26.1k
  const json_t *v = json_object_get(json, claim_name);
229
26.1k
  if (v != NULL) {
230
6.22k
    if (json_is_number(v)) {
231
6.19k
      *result = json_number_value(v);
232
6.19k
    } else if (is_mandatory) {
233
0
      oidc_jose_error(err, "mandatory JSON key \"%s\" was found but the type is not a number",
234
0
          claim_name);
235
0
      return FALSE;
236
0
    }
237
19.9k
  } else if (is_mandatory) {
238
0
    oidc_jose_error(err, "mandatory JSON key \"%s\" could not be found", claim_name);
239
0
    return FALSE;
240
0
  }
241
26.1k
  return TRUE;
242
26.1k
}
243
244
8.87k
#define OIDC_CJOSE_UNCOMPRESS_CHUNK 8192
245
/* absolute cap on the decompressed output to prevent decompression bombs */
246
28
#define OIDC_CJOSE_UNCOMPRESS_MAX (10 * 1024 * 1024)
247
248
#ifdef USE_LIBBROTLI
249
250
/*
251
 * deflate using libbrotli
252
 */
253
static apr_byte_t oidc_jose_brotli_compress(apr_pool_t *pool, const char *input, int input_len, char **output,
254
              int *output_len, oidc_jose_error_t *err) {
255
  size_t len = BrotliEncoderMaxCompressedSize(input_len);
256
  *output = apr_pcalloc(pool, len);
257
  if (BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_MODE_TEXT, input_len,
258
          (const uint8_t *)input, &len, (uint8_t *)*output) != BROTLI_TRUE) {
259
    oidc_jose_error(err, "BrotliEncoderCompress failed: compression error or buffer too small");
260
    return FALSE;
261
  }
262
  *output_len = len;
263
  return TRUE;
264
}
265
266
/* Stream Brotli output into a doubling buffer so valid high-ratio payloads fit below the bomb cap. */
267
static apr_byte_t oidc_jose_brotli_uncompress(apr_pool_t *pool, const char *input, int input_len, char **output,
268
                int *output_len, oidc_jose_error_t *err) {
269
  apr_byte_t rv = FALSE;
270
  BrotliDecoderResult res = BROTLI_DECODER_RESULT_ERROR;
271
  size_t len = OIDC_CJOSE_UNCOMPRESS_CHUNK;
272
  size_t available_in = (size_t)input_len;
273
  const uint8_t *next_in = (const uint8_t *)input;
274
  size_t total_out = 0;
275
  char *buf = apr_pcalloc(pool, len);
276
  char *tmp = NULL;
277
278
  BrotliDecoderState *state = BrotliDecoderCreateInstance(NULL, NULL, NULL);
279
  if (state == NULL) {
280
    oidc_jose_error(err, "BrotliDecoderCreateInstance failed");
281
    return FALSE;
282
  }
283
284
  while (1) {
285
    size_t available_out = len - total_out;
286
    uint8_t *next_out = (uint8_t *)(buf + total_out);
287
    res = BrotliDecoderDecompressStream(state, &available_in, &next_in, &available_out, &next_out, NULL);
288
    total_out = len - available_out;
289
    if (res == BROTLI_DECODER_RESULT_SUCCESS)
290
      break;
291
    if (res != BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
292
      /* a decode error, or a truncated stream asking for more input */
293
      oidc_jose_error(err, "BrotliDecoderDecompressStream failed: %d", res);
294
      goto end;
295
    }
296
    if (len >= OIDC_CJOSE_UNCOMPRESS_MAX) {
297
      oidc_jose_error(err, "brotli output would exceed %d bytes", OIDC_CJOSE_UNCOMPRESS_MAX);
298
      goto end;
299
    }
300
    /* grow by doubling, as the zlib side does and for the same reasons */
301
    size_t next = (len > OIDC_CJOSE_UNCOMPRESS_MAX / 2) ? OIDC_CJOSE_UNCOMPRESS_MAX : len * 2;
302
    tmp = apr_pcalloc(pool, next);
303
    _oidc_memcpy(tmp, buf, len);
304
    len = next;
305
    buf = tmp;
306
  }
307
308
  *output = buf;
309
  *output_len = (int)total_out;
310
  rv = TRUE;
311
312
end:
313
314
  BrotliDecoderDestroyInstance(state);
315
316
  return rv;
317
}
318
319
#endif
320
321
#ifdef USE_ZLIB
322
323
/*
324
 * deflate using zlib
325
 */
326
static apr_byte_t oidc_jose_zlib_compress(apr_pool_t *pool, const char *input, int input_len, char **output,
327
16.4k
            int *output_len, oidc_jose_error_t *err) {
328
16.4k
  apr_byte_t rv = FALSE;
329
16.4k
  int status = Z_OK;
330
16.4k
  z_stream zlib;
331
332
16.4k
  zlib.zalloc = Z_NULL;
333
16.4k
  zlib.zfree = Z_NULL;
334
16.4k
  zlib.opaque = Z_NULL;
335
16.4k
  zlib.next_in = (Bytef *)input;
336
16.4k
  zlib.avail_in = input_len;
337
338
  /*
339
   * Small window and memory settings avoid oversized allocations for short payloads. The zlib
340
   * header records the window size, so the default inflate path remains compatible.
341
   */
342
16.4k
  status = deflateInit2(&zlib, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 12, 5, Z_DEFAULT_STRATEGY);
343
16.4k
  if (status != Z_OK) {
344
0
    oidc_jose_error(err, "deflateInit2() failed: %d", status);
345
0
    goto end;
346
0
  }
347
348
  /* deflateBound accounts for the zlib header/trailer overhead that dominates for
349
   * short inputs; a fixed input_len * 2 buffer made deflate fail on values of a
350
   * few bytes, silently preventing such values from being cached */
351
  /* the (uInt) narrowing is safe: input_len is an int so deflateBound's small
352
   * relative overhead keeps the result well within uInt range */
353
16.4k
  uLong output_max = deflateBound(&zlib, input_len);
354
16.4k
  *output = apr_pcalloc(pool, output_max);
355
16.4k
  zlib.next_out = (Bytef *)(*output);
356
16.4k
  zlib.avail_out = (uInt)output_max;
357
358
16.4k
  status = deflate(&zlib, Z_FINISH);
359
16.4k
  if (status != Z_STREAM_END) {
360
0
    oidc_jose_error(err, "deflate() failed: %d", status);
361
0
    goto end;
362
0
  }
363
364
16.4k
  *output_len = (int)zlib.total_out;
365
366
16.4k
  rv = TRUE;
367
368
16.4k
end:
369
370
16.4k
  deflateEnd(&zlib);
371
372
16.4k
  return rv;
373
16.4k
}
374
375
/*
376
 * inflate using zlib
377
 */
378
static apr_byte_t oidc_jose_zlib_uncompress(apr_pool_t *pool, const char *input, int input_len, char **output,
379
8.87k
              int *output_len, apr_byte_t *capped, oidc_jose_error_t *err) {
380
8.87k
  apr_byte_t rv = FALSE;
381
8.87k
  int status = Z_OK;
382
8.87k
  size_t len = OIDC_CJOSE_UNCOMPRESS_CHUNK;
383
8.87k
  char *tmp = NULL;
384
8.87k
  char *buf = apr_pcalloc(pool, len);
385
8.87k
  z_stream zlib;
386
387
  /* whether inflation was stopped at the output cap: the one failure that must not be passed
388
   * through as "not a zlib stream after all" - see the caller */
389
8.87k
  *capped = FALSE;
390
391
8.87k
  zlib.zalloc = Z_NULL;
392
8.87k
  zlib.zfree = Z_NULL;
393
8.87k
  zlib.opaque = Z_NULL;
394
8.87k
  zlib.avail_in = (uInt)input_len;
395
8.87k
  zlib.next_in = (Bytef *)input;
396
8.87k
  zlib.total_out = 0;
397
398
8.87k
  status = inflateInit(&zlib);
399
8.87k
  if (status != Z_OK) {
400
0
    oidc_jose_error(err, "inflateInit() failed: %d", status);
401
0
    goto end;
402
0
  }
403
404
17.7k
  while (status == Z_OK) {
405
    /* Double pooled buffers; fixed growth retains old allocations and becomes quadratic. */
406
8.89k
    if (zlib.total_out >= len) {
407
14
      if (len >= OIDC_CJOSE_UNCOMPRESS_MAX) {
408
0
        *capped = TRUE;
409
0
        oidc_jose_error(err, "inflate() output would exceed %d bytes",
410
0
            OIDC_CJOSE_UNCOMPRESS_MAX);
411
0
        goto end;
412
0
      }
413
14
      size_t next = (len > OIDC_CJOSE_UNCOMPRESS_MAX / 2) ? OIDC_CJOSE_UNCOMPRESS_MAX : len * 2;
414
14
      tmp = apr_pcalloc(pool, next);
415
14
      _oidc_memcpy(tmp, buf, len);
416
14
      len = next;
417
14
      buf = tmp;
418
14
    }
419
8.89k
    zlib.next_out = (Bytef *)(buf + zlib.total_out);
420
8.89k
    zlib.avail_out = (uInt)(len - zlib.total_out);
421
8.89k
    status = inflate(&zlib, Z_SYNC_FLUSH);
422
8.89k
  }
423
424
8.87k
  if (status != Z_STREAM_END) {
425
0
    oidc_jose_error(err, "inflate() failed: %d", status);
426
0
    goto end;
427
0
  }
428
429
8.87k
  *output_len = (int)zlib.total_out;
430
8.87k
  *output = buf;
431
432
8.87k
  rv = TRUE;
433
434
8.87k
end:
435
436
8.87k
  inflateEnd(&zlib);
437
438
8.87k
  return rv;
439
8.87k
}
440
441
#endif
442
443
/*
444
 * compress using (compile-time) zlib or libbrotli, otherwise just plain copy
445
 */
446
apr_byte_t oidc_jose_compress(apr_pool_t *pool, const char *input, int input_len, char **output, int *output_len,
447
16.4k
            oidc_jose_error_t *err) {
448
#ifdef USE_LIBBROTLI
449
  return oidc_jose_brotli_compress(pool, input, input_len, output, output_len, err);
450
#elif defined(USE_ZLIB)
451
  return oidc_jose_zlib_compress(pool, input, input_len, output, output_len, err);
452
#else
453
  *output = apr_pmemdup(pool, input, input_len);
454
  *output_len = input_len;
455
  return TRUE;
456
#endif
457
16.4k
}
458
459
/* Recognize a possible zlib stream from its RFC 1950 header; callers handle false positives. */
460
8.87k
static apr_byte_t oidc_jose_is_zlib(const char *input, int input_len) {
461
8.87k
  const unsigned char *b = (const unsigned char *)input;
462
8.87k
  if ((input == NULL) || (input_len < 2))
463
0
    return FALSE;
464
8.87k
  if ((b[0] & 0x0f) != 8)
465
0
    return FALSE;
466
8.87k
  return (((((unsigned int)b[0]) << 8) | b[1]) % 31) == 0 ? TRUE : FALSE;
467
8.87k
}
468
469
/*
470
 * Detect compression from the payload so caches remain readable across build or configuration
471
 * changes. A build without zlib still cannot decode a zlib payload.
472
 */
473
apr_byte_t oidc_jose_uncompress(apr_pool_t *pool, const char *input, int input_len, char **output, int *output_len,
474
8.87k
        oidc_jose_error_t *err) {
475
476
8.87k
  if (oidc_jose_is_zlib(input, input_len)) {
477
8.87k
#ifdef USE_ZLIB
478
    /*
479
     * The zlib header test has false positives for arbitrary cache values. Treat inflate
480
     * errors as uncompressed input; only the decompression-size cap is a hard failure.
481
     */
482
8.87k
    apr_byte_t capped = FALSE;
483
8.87k
    if (oidc_jose_zlib_uncompress(pool, input, input_len, output, output_len, &capped, err) == TRUE)
484
8.87k
      return TRUE;
485
0
    if (capped == TRUE)
486
0
      return FALSE;
487
0
#endif
488
    /* Without zlib support, pass possible zlib input through for downstream validation. */
489
0
  }
490
491
#ifdef USE_LIBBROTLI
492
  /* Brotli has no header; a failed decode may simply mean the payload is uncompressed. */
493
  if (oidc_jose_brotli_uncompress(pool, input, input_len, output, output_len, err) == TRUE)
494
    return TRUE;
495
#endif
496
  /* not compressed, or compressed by an algorithm this build does not have */
497
0
  *output = apr_pmemdup(pool, input, input_len);
498
0
  *output_len = input_len;
499
0
  return TRUE;
500
8.87k
}
501
502
#if (OPENSSL_VERSION_NUMBER < 0x10100000) || defined(LIBRESSL_VERSION_NUMBER)
503
EVP_MD_CTX *EVP_MD_CTX_new() {
504
  return malloc(sizeof(EVP_MD_CTX));
505
}
506
void EVP_MD_CTX_free(EVP_MD_CTX *ctx) {
507
  if (ctx)
508
    free(ctx);
509
}
510
#endif
511
512
314
#define OIDC_JOSE_CJOSE_VERSION_DEPRECATED "0.4."
513
514
/*
515
 * return the version string of the underlying JOSE backend library
516
 */
517
0
const char *oidc_jose_version(void) {
518
0
  return cjose_version();
519
0
}
520
521
/*
522
 * check for a version of cjose < 0.5.0 that has a version of
523
 * cjose_jws_verify that resources after a verification failure
524
 */
525
314
apr_byte_t oidc_jose_version_deprecated(apr_pool_t *pool) {
526
314
  const char *version = apr_pstrdup(pool, cjose_version());
527
314
  return (_oidc_strstr(version, OIDC_JOSE_CJOSE_VERSION_DEPRECATED) == version);
528
314
}
529
530
/*
531
 * hash a byte sequence with the specified algorithm
532
 */
533
apr_byte_t oidc_jose_hash_bytes(apr_pool_t *pool, const char *s_digest, const unsigned char *input,
534
        unsigned int input_len, unsigned char **output, unsigned int *output_len,
535
110k
        oidc_jose_error_t *err) {
536
110k
  apr_byte_t rv = FALSE;
537
110k
  unsigned char md_value[EVP_MAX_MD_SIZE];
538
110k
  const EVP_MD *evp_digest = NULL;
539
110k
  EVP_MD_CTX *ctx = EVP_MD_CTX_new();
540
110k
  EVP_MD_CTX_init(ctx);
541
542
110k
  if ((evp_digest = EVP_get_digestbyname(s_digest)) == NULL) {
543
0
    oidc_jose_error(err, "no OpenSSL digest algorithm found for algorithm \"%s\"", s_digest);
544
0
    goto end;
545
0
  }
546
547
110k
  if (!EVP_DigestInit_ex(ctx, evp_digest, NULL)) {
548
0
    oidc_jose_error_openssl(err, "EVP_DigestInit_ex");
549
0
    goto end;
550
0
  }
551
552
110k
  if (!EVP_DigestUpdate(ctx, input, input_len)) {
553
0
    oidc_jose_error_openssl(err, "EVP_DigestUpdate");
554
0
    goto end;
555
0
  }
556
557
110k
  if (!EVP_DigestFinal(ctx, md_value, output_len)) {
558
0
    oidc_jose_error_openssl(err, "EVP_DigestFinal");
559
0
    goto end;
560
0
  }
561
562
110k
  *output = apr_pmemdup(pool, md_value, *output_len);
563
564
110k
  rv = TRUE;
565
566
110k
end:
567
568
110k
  if (ctx)
569
110k
    EVP_MD_CTX_free(ctx);
570
571
110k
  return rv;
572
110k
}
573
574
/* Map JOSE algorithms to digest name and length together; cjose names are not constant expressions. */
575
1.48k
static apr_byte_t _oidc_jose_alg_to_sha2(const char *alg, const char **openssl_digest, int *hash_len) {
576
1.48k
  const struct {
577
1.48k
    const char *algs[4];
578
1.48k
    const char *openssl_digest;
579
1.48k
    int hash_len;
580
1.48k
  } families[] = {
581
1.48k
      {{CJOSE_HDR_ALG_RS256, CJOSE_HDR_ALG_PS256, CJOSE_HDR_ALG_HS256, CJOSE_HDR_ALG_ES256}, LN_sha256, 32},
582
1.48k
      {{CJOSE_HDR_ALG_RS384, CJOSE_HDR_ALG_PS384, CJOSE_HDR_ALG_HS384, CJOSE_HDR_ALG_ES384}, LN_sha384, 48},
583
1.48k
      {{CJOSE_HDR_ALG_RS512, CJOSE_HDR_ALG_PS512, CJOSE_HDR_ALG_HS512, CJOSE_HDR_ALG_ES512}, LN_sha512, 64},
584
1.48k
  };
585
1.48k
  for (int i = 0; i < (int)(sizeof(families) / sizeof(families[0])); i++) {
586
4.44k
    for (int j = 0; j < (int)(sizeof(families[0].algs) / sizeof(const char *)); j++) {
587
4.44k
      if (_oidc_strcmp(alg, families[i].algs[j]) == 0) {
588
1.48k
        *openssl_digest = families[i].openssl_digest;
589
1.48k
        *hash_len = families[i].hash_len;
590
1.48k
        return TRUE;
591
1.48k
      }
592
4.44k
    }
593
1.48k
  }
594
0
  return FALSE;
595
1.48k
}
596
597
/*
598
 * return the OpenSSL hash algorithm associated with a specified JWT algorithm
599
 */
600
970
static const char *oidc_jose_alg_to_openssl_digest(const char *alg) {
601
970
  const char *digest = NULL;
602
970
  int len = 0;
603
970
  return _oidc_jose_alg_to_sha2(alg, &digest, &len) ? digest : NULL;
604
970
}
605
606
/*
607
 * hash a string value with the specified algorithm
608
 */
609
apr_byte_t oidc_jose_hash_string(apr_pool_t *pool, const char *alg, const char *msg, char **hash,
610
970
         unsigned int *hash_len, oidc_jose_error_t *err) {
611
612
970
  const char *s_digest = oidc_jose_alg_to_openssl_digest(alg);
613
970
  if (s_digest == NULL) {
614
0
    oidc_jose_error(err, "no OpenSSL digest algorithm name found for algorithm \"%s\"", alg);
615
0
    return FALSE;
616
0
  }
617
618
970
  return oidc_jose_hash_bytes(pool, s_digest, (const unsigned char *)msg, (unsigned int)_oidc_strlen(msg),
619
970
            (unsigned char **)hash, hash_len, err);
620
970
}
621
622
/*
623
 * return hash length for the specified JOSE algorithm
624
 */
625
510
int oidc_jose_hash_length(const char *alg) {
626
510
  const char *digest = NULL;
627
510
  int len = 0;
628
510
  return _oidc_jose_alg_to_sha2(alg, &digest, &len) ? len : 0;
629
510
}