Coverage Report

Created: 2026-09-01 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/jose.h
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 Object Signing and Encryption
42
 *
43
 * @Author: Hans Zandbelt - hans.zandbelt@openidc.com
44
 */
45
46
#ifndef _MOD_AUTH_OPENIDC_JOSE_H_
47
#define _MOD_AUTH_OPENIDC_JOSE_H_
48
49
#include "const.h"
50
51
#include <apr_hash.h>
52
#include <apr_pools.h>
53
#include <apr_strings.h>
54
#include <apr_tables.h>
55
56
#include "json.h"
57
58
/* opaque forward declaration of the OpenSSL BIO type used in the oidc_jwk_pem_bio_to_jwk() prototype below */
59
typedef struct bio_st BIO;
60
61
#ifndef APR_ARRAY_IDX
62
#define APR_ARRAY_IDX(ary, i, type) (((type *)(ary)->elts)[i])
63
#endif
64
65
#ifndef APR_ARRAY_PUSH
66
#define APR_ARRAY_PUSH(ary, type) (*((type *)apr_array_push(ary)))
67
#endif
68
69
0
#define OIDC_JOSE_ALG_SHA1 "sha1"
70
0
#define OIDC_JOSE_ALG_SHA256 "sha256"
71
72
/* indicate support for OpenSSL version dependent features */
73
#define OIDC_JOSE_EC_SUPPORT OPENSSL_VERSION_NUMBER >= 0x1000100f
74
#define OIDC_JOSE_GCM_SUPPORT OPENSSL_VERSION_NUMBER >= 0x1000100f
75
76
/* error message element sizes */
77
6.60k
#define OIDC_JOSE_ERROR_TEXT_LENGTH 200
78
#define OIDC_JOSE_ERROR_SOURCE_LENGTH 80
79
#define OIDC_JOSE_ERROR_FUNCTION_LENGTH 80
80
81
/* the OIDC jwk fields as references in RFC 5741 */
82
#define OIDC_JOSE_JWK_KID_STR "kid"     // Key ID
83
0
#define OIDC_JOSE_JWK_KTY_STR "kty"      // Key type
84
0
#define OIDC_JOSE_JWK_USE_STR "use"      // Key usage (enc|sig)
85
0
#define OIDC_JOSE_JWK_X5C_STR "x5c"      // X509 certificate chain
86
0
#define OIDC_JOSE_JWK_X5T_STR "x5t"      // X509 SHA-1 thumbprint
87
0
#define OIDC_JOSE_JWK_X5T256_STR "x5t#S256" // X509 SHA-256 thumbprint
88
0
#define OIDC_JOSE_JWK_SIG_STR "sig"      // use signature type
89
0
#define OIDC_JOSE_JWK_ENC_STR "enc"      // use encryption type
90
0
#define OIDC_JOSE_JWK_ALG_STR "alg"      // algorithm intended for use with the key
91
92
/* the OIDC jwks fields from RFC 5741 */
93
0
#define OIDC_JOSE_JWKS_KEYS_STR "keys" // Array of JWKs
94
95
/* Backend-independent JOSE names and values. Key types match cjose and are compile-time asserted. */
96
11.1k
#define OIDC_JOSE_HDR_ALG "alg"
97
11.1k
#define OIDC_JOSE_HDR_ENC "enc"
98
11.1k
#define OIDC_JOSE_HDR_KID "kid"
99
41.2k
#define OIDC_JOSE_HDR_ALG_DIR "dir"
100
0
#define OIDC_JOSE_HDR_ALG_RS256 "RS256"
101
0
#define OIDC_JOSE_HDR_ALG_PS256 "PS256"
102
0
#define OIDC_JOSE_HDR_ALG_HS256 "HS256"
103
0
#define OIDC_JOSE_HDR_ALG_ES256 "ES256"
104
0
#define OIDC_JOSE_HDR_ALG_ES384 "ES384"
105
0
#define OIDC_JOSE_HDR_ALG_ES512 "ES512"
106
9.79k
#define OIDC_JOSE_HDR_ENC_A256GCM "A256GCM"
107
0
#define OIDC_JOSE_HDR_ENC_A128CBC_HS256 "A128CBC-HS256"
108
109
0
#define OIDC_JOSE_JWK_KTY_RSA 1
110
0
#define OIDC_JOSE_JWK_KTY_EC 2
111
0
#define OIDC_JOSE_JWK_KTY_OCT 3
112
113
/* struct for returning errors to the caller */
114
typedef struct {
115
  char source[OIDC_JOSE_ERROR_SOURCE_LENGTH];
116
  int line;
117
  char function[OIDC_JOSE_ERROR_FUNCTION_LENGTH];
118
  char text[OIDC_JOSE_ERROR_TEXT_LENGTH];
119
} oidc_jose_error_t;
120
121
/*
122
 * error handling functions
123
 */
124
6.60k
#define oidc_jose_error(err, msg, ...) _oidc_jose_error_set(err, __FILE__, __LINE__, __FUNCTION__, msg, ##__VA_ARGS__)
125
#define oidc_jose_error_openssl(err, msg, ...)                                                                         \
126
0
  _oidc_jose_error_set(err, __FILE__, __LINE__, __FUNCTION__, "%s() failed: %s", msg,                            \
127
0
           ERR_error_string(ERR_get_error(), NULL), ##__VA_ARGS__)
128
0
#define oidc_jose_e2s(pool, err) apr_psprintf(pool, "[%s:%d: %s]: %s", err.source, err.line, err.function, err.text)
129
130
/*
131
 * helper functions
132
 */
133
134
/* helpers to find out about the supported ala/enc algorithms */
135
apr_array_header_t *oidc_jose_jws_supported_algorithms(apr_pool_t *pool);
136
apr_byte_t oidc_jose_jws_algorithm_is_supported(apr_pool_t *pool, const char *alg);
137
apr_array_header_t *oidc_jose_jwe_supported_algorithms(apr_pool_t *pool);
138
apr_byte_t oidc_jose_jwe_algorithm_is_supported(apr_pool_t *pool, const char *alg);
139
apr_array_header_t *oidc_jose_jwe_supported_encryptions(apr_pool_t *pool);
140
apr_byte_t oidc_jose_jwe_encryption_is_supported(apr_pool_t *pool, const char *enc);
141
142
/* return the version string of the underlying JOSE backend library */
143
const char *oidc_jose_version(void);
144
145
/* hash helpers */
146
apr_byte_t oidc_jose_hash_string(apr_pool_t *pool, const char *alg, const char *msg, char **hash,
147
         unsigned int *hash_len, oidc_jose_error_t *err);
148
int oidc_jose_hash_length(const char *alg);
149
apr_byte_t oidc_jose_hash_bytes(apr_pool_t *pool, const char *s_digest, const unsigned char *input,
150
        unsigned int input_len, unsigned char **output, unsigned int *output_len,
151
        oidc_jose_error_t *err);
152
apr_byte_t oidc_jose_hash_and_base64url_encode(apr_pool_t *pool, const char *openssl_hash_algo, const char *input,
153
                 int input_len, char **output, oidc_jose_error_t *err);
154
155
/* return a string claim value from a JSON object */
156
apr_byte_t oidc_jose_get_string(apr_pool_t *pool, const oidc_json_t *json, const char *claim_name,
157
        apr_byte_t is_mandatory, char **result, oidc_jose_error_t *err);
158
apr_byte_t oidc_jose_get_timestamp(const oidc_json_t *json, const char *claim_name, apr_byte_t is_mandatory,
159
           double *result, oidc_jose_error_t *err);
160
161
apr_byte_t oidc_jose_compress(apr_pool_t *pool, const char *input, int input_len, char **output, int *output_len,
162
            oidc_jose_error_t *err);
163
apr_byte_t oidc_jose_uncompress(apr_pool_t *pool, const char *input, int input_len, char **output, int *output_len,
164
        oidc_jose_error_t *err);
165
166
/* a parsed JWK/JWT JSON object */
167
typedef struct oidc_jose_json_t {
168
  /* parsed JSON struct representation */
169
  oidc_json_t *json;
170
  /* string representation */
171
  char *str;
172
} oidc_jose_json_t;
173
174
/*
175
 * JSON Web Key handling
176
 */
177
178
/* parsed JWK */
179
typedef struct oidc_jwk_t {
180
  /* use type */
181
  char *use;
182
  /* JWK "alg" (algorithm) parameter (optional; RFC 7517 section 4.4); when set it is published in the
183
   * JWKs so an OP can select this key for the named algorithm, and it drives per-alg key duplication */
184
  char *alg;
185
  /* key type */
186
  int kty;
187
  /* key identifier */
188
  char *kid;
189
  /* X.509 Certificate Chain */
190
  apr_array_header_t *x5c;
191
  /* X.509 Certificate SHA-1 Thumbprint */
192
  char *x5t;
193
  /* X.509 Certificate SHA-256 Thumbprint */
194
  char *x5t_S256;
195
  /* backend-private handle to the JOSE library's key object (currently a cjose_jwk_t); typed as
196
   * void* so this public header needs no backend types: only jose.c and the jose/ subdirectory,
197
   * which include the real backend header, may dereference or operate on it */
198
  void *cjose_jwk;
199
} oidc_jwk_t;
200
201
/* decrypt a JWT */
202
apr_byte_t oidc_jwe_decrypt(apr_pool_t *pool, const char *input_json, apr_hash_t *keys, char **plaintext,
203
          int *plaintext_len, oidc_jose_error_t *err, apr_byte_t import_must_succeed);
204
/* parse a JSON string (JWK) to a JWK struct */
205
oidc_jwk_t *oidc_jwk_parse(apr_pool_t *pool, const oidc_json_t *json, oidc_jose_error_t *err);
206
oidc_jwk_t *oidc_jwk_copy(apr_pool_t *pool, const oidc_jwk_t *jwk);
207
/* parse a JSON object (JWK) in to a JWK struct */
208
apr_byte_t oidc_jwk_parse_json(apr_pool_t *pool, const oidc_json_t *json, oidc_jwk_t **jwk, oidc_jose_error_t *err);
209
/* parse a JSON object (JWKS) to a list of JWK structs */
210
apr_byte_t oidc_jwks_parse_json(apr_pool_t *pool, const oidc_json_t *json, apr_array_header_t **jwk_list,
211
        oidc_jose_error_t *err);
212
/* test if JSON object looks like JWK */
213
apr_byte_t oidc_is_jwk(const oidc_json_t *json);
214
/* test if JSON object looks like JWKS */
215
apr_byte_t oidc_is_jwks(const oidc_json_t *json);
216
/* convert a JWK struct to a JSON string */
217
apr_byte_t oidc_jwk_to_json(apr_pool_t *pool, const oidc_jwk_t *jwk, char **s_json, oidc_jose_error_t *err);
218
/* convert the PUBLIC part of a JWK struct to a JSON string (excludes private key material) */
219
apr_byte_t oidc_jwk_to_public_json(apr_pool_t *pool, const oidc_jwk_t *jwk, char **s_json, oidc_jose_error_t *err);
220
/* derive the default JWS signing algorithm for a key (RS256 for RSA; ES256/384/512 per EC curve); NULL if unsupported
221
 */
222
const char *oidc_jwk_default_jws_alg(const oidc_jwk_t *jwk);
223
/* destroy resources allocated for a JWK struct */
224
void oidc_jwk_destroy(oidc_jwk_t *jwk);
225
/* destroy a list of JWKs structs */
226
void oidc_jwk_list_destroy_hash(apr_hash_t *key);
227
apr_array_header_t *oidc_jwk_list_copy(apr_pool_t *pool, apr_array_header_t *src);
228
void oidc_jwk_list_destroy(apr_array_header_t *keys_list);
229
/* create an "oct" symmetric JWK */
230
oidc_jwk_t *oidc_jwk_create_symmetric_key(apr_pool_t *pool, const char *kid, const unsigned char *key,
231
            unsigned int key_len, apr_byte_t set_kid, oidc_jose_error_t *err);
232
233
/* parse an X.509 PEM formatted certificate file with a public key to a JWK struct */
234
apr_byte_t oidc_jwk_parse_pem_public_key(apr_pool_t *pool, const char *kid, const char *filename, oidc_jwk_t **jwk,
235
           oidc_jose_error_t *err);
236
/* parse an X.509 PEM formatted private key file to a JWK */
237
apr_byte_t oidc_jwk_parse_pem_private_key(apr_pool_t *pool, const char *kid, const char *filename, oidc_jwk_t **jwk,
238
            oidc_jose_error_t *err);
239
240
/*
241
 * JSON Web Token handling
242
 */
243
244
/* represents NULL timestamp */
245
0
#define OIDC_JWT_CLAIM_TIME_EMPTY -1
246
247
/* a parsed JWT header */
248
typedef struct oidc_jwt_hdr_t {
249
  /* parsed header value */
250
  oidc_jose_json_t value;
251
  /* JWT "alg" claim value; signing algorithm */
252
  char *alg;
253
  /* JWT "kid" claim value; key identifier */
254
  char *kid;
255
  /* JWT "enc" claim value; encryption algorithm */
256
  char *enc;
257
  /* JWT "cty" claim value; content type (e.g. "JWT" for a Nested JWT) */
258
  char *cty;
259
  /* JWT "x5t" thumbprint */
260
  char *x5t;
261
} oidc_jwt_hdr_t;
262
263
/* parsed JWT payload */
264
typedef struct oidc_jwt_payload_t {
265
  /* parsed payload value */
266
  oidc_jose_json_t value;
267
  /* JWT "iss" claim value; JWT issuer */
268
  char *iss;
269
  /* JWT "sub" claim value; subject/principal */
270
  char *sub;
271
  /* parsed JWT "exp" claim value; token expiry */
272
  double exp;
273
  /* parsed JWT "iat" claim value; issued-at timestamp */
274
  double iat;
275
} oidc_jwt_payload_t;
276
277
/* parsed JWT */
278
typedef struct oidc_jwt_t {
279
  /* parsed JWT header */
280
  oidc_jwt_hdr_t header;
281
  /* parsed JWT payload */
282
  oidc_jwt_payload_t payload;
283
  /* backend-private handle to the JOSE library's signature object (currently a cjose_jws_t); typed
284
   * as void* so this public header needs no backend types: only jose.c and the jose/ subdirectory,
285
   * which include the real backend header, may dereference or operate on it */
286
  void *cjose_jws;
287
} oidc_jwt_t;
288
289
/* parse a string into a JSON Web Token struct and (optionally) decrypt it */
290
apr_byte_t oidc_jwt_parse(apr_pool_t *pool, const char *s_json, oidc_jwt_t **j_jwt, apr_hash_t *keys,
291
        apr_byte_t compress, oidc_jose_error_t *err);
292
/* sign a JWT with a JWK */
293
apr_byte_t oidc_jwt_sign(apr_pool_t *pool, oidc_jwt_t *jwt, const oidc_jwk_t *jwk, apr_byte_t compress,
294
       oidc_jose_error_t *err);
295
/* verify a JWT a key in a list of JWKs */
296
apr_byte_t oidc_jwt_verify(apr_pool_t *pool, oidc_jwt_t *jwt, apr_hash_t *keys, oidc_jose_error_t *err);
297
/* perform compact serialization on a JWT and return the resulting string */
298
char *oidc_jose_jwt_serialize(apr_pool_t *pool, oidc_jwt_t *jwt, oidc_jose_error_t *err);
299
/* encrypt JWT */
300
apr_byte_t oidc_jwt_encrypt(apr_pool_t *pool, oidc_jwt_t *jwe, const oidc_jwk_t *jwk, const char *payload,
301
          int payload_len, char **serialized, oidc_jose_error_t *err);
302
303
/* create a new JWT */
304
oidc_jwt_t *oidc_jwt_new(apr_pool_t *pool, int create_header, int create_payload);
305
/* destroy resources allocated for JWT */
306
void oidc_jwt_destroy(oidc_jwt_t *);
307
308
/* get a header value from a JWT */
309
const char *oidc_jwt_hdr_get(oidc_jwt_t *jwt, const char *key);
310
/* set a JWT header member to a raw (pre-serialized) JSON value */
311
apr_byte_t oidc_jwt_hdr_set_json(oidc_jwt_t *jwt, const char *key, const char *raw_json, oidc_jose_error_t *err);
312
/* return the key type of a JWT */
313
int oidc_jwt_alg2kty(const oidc_jwt_t *jwt);
314
/* return the key type (cjose kty) that the provided JWA algorithm name requires, or -1 if unknown */
315
int oidc_alg2kty(const char *alg);
316
/* return the key size for an algorithm */
317
unsigned int oidc_alg2keysize(const char *alg);
318
319
apr_byte_t oidc_jwk_pem_bio_to_jwk(apr_pool_t *pool, BIO *input, const char *kid, oidc_jwk_t **jwk,
320
           apr_byte_t is_private_key, oidc_jose_error_t *err);
321
322
#endif /* _MOD_AUTH_OPENIDC_JOSE_H_ */