Skip to content

Commit c784a3e

Browse files
committed
code: refactor util.c: factor out util/key.c
Signed-off-by: Hans Zandbelt <[email protected]>
1 parent e238b37 commit c784a3e

File tree

13 files changed

+184
-139
lines changed

13 files changed

+184
-139
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ libauth_openidc_la_SOURCES = \
4949
src/util/jq.c \
5050
src/util/json.c \
5151
src/util/jwt.c \
52+
src/util/key.c \
5253
src/util/pcre_subst.c \
5354
src/util/random.c \
5455
src/util/url.c \

src/handle/logout.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ static int oidc_logout_backchannel(request_rec *r, oidc_cfg_t *cfg) {
307307
// TODO: jwk symmetric key based on provider
308308

309309
if (oidc_jwt_parse(r->pool, logout_token, &jwt,
310-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_private_keys_get(cfg), NULL), FALSE,
310+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_private_keys_get(cfg), NULL), FALSE,
311311
&err) == FALSE) {
312312
oidc_error(r, "oidc_jwt_parse failed: %s", oidc_jose_e2s(r->pool, err));
313313
goto out;
@@ -334,14 +334,14 @@ static int oidc_logout_backchannel(request_rec *r, oidc_cfg_t *cfg) {
334334
// TODO: destroy the JWK used for decryption
335335

336336
jwk = NULL;
337-
if (oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, TRUE, &jwk) ==
337+
if (oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, TRUE, &jwk) ==
338338
FALSE)
339339
return FALSE;
340340

341341
if (oidc_proto_jwt_verify(
342342
r, cfg, jwt, oidc_cfg_provider_jwks_uri_get(provider),
343343
oidc_cfg_provider_ssl_validate_server_get(provider),
344-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_provider_verify_public_keys_get(provider), jwk),
344+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_provider_verify_public_keys_get(provider), jwk),
345345
oidc_cfg_provider_id_token_signed_response_alg_get(provider)) == FALSE) {
346346

347347
oidc_error(r, "id_token signature could not be validated, aborting");

src/oauth.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,13 +561,13 @@ static apr_byte_t oidc_oauth_validate_jwt_access_token(request_rec *r, oidc_cfg_
561561
oidc_jwk_t *jwk = NULL;
562562

563563
// TODO: replace this OIDC client secret with OIDCOAuthDecryptSharedKeys
564-
if (oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(oidc_cfg_provider_get(c)), 0, NULL,
564+
if (oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(oidc_cfg_provider_get(c)), 0, NULL,
565565
TRUE, &jwk) == FALSE)
566566
return FALSE;
567567

568568
oidc_jwt_t *jwt = NULL;
569569
if (oidc_jwt_parse(r->pool, access_token, &jwt,
570-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_private_keys_get(c), jwk), FALSE,
570+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_private_keys_get(c), jwk), FALSE,
571571
&err) == FALSE) {
572572
oidc_error(r, "could not parse JWT from access_token: %s", oidc_jose_e2s(r->pool, err));
573573
oidc_jwk_destroy(jwk);
@@ -597,7 +597,7 @@ static apr_byte_t oidc_oauth_validate_jwt_access_token(request_rec *r, oidc_cfg_
597597
oidc_cfg_provider_userinfo_refresh_interval_get(oidc_cfg_provider_get(c)), NULL,
598598
NULL};
599599
if (oidc_proto_jwt_verify(r, c, jwt, &jwks_uri, oidc_cfg_oauth_ssl_validate_server_get(c),
600-
oidc_util_merge_key_sets(r->pool, oidc_cfg_oauth_verify_shared_keys_get(c),
600+
oidc_util_key_sets_merge(r->pool, oidc_cfg_oauth_verify_shared_keys_get(c),
601601
oidc_cfg_oauth_verify_public_keys_get(c)),
602602
NULL) == FALSE) {
603603
oidc_error(r, "JWT access token signature could not be validated, aborting");

src/proto/id_token.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,14 +391,14 @@ apr_byte_t oidc_proto_idtoken_parse(request_rec *r, oidc_cfg_t *cfg, oidc_provid
391391
char buf[APR_RFC822_DATE_LEN + 1];
392392
oidc_jose_error_t err;
393393
oidc_jwk_t *jwk = NULL;
394-
if (oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider), oidc_alg2keysize(alg),
394+
if (oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider), oidc_alg2keysize(alg),
395395
OIDC_JOSE_ALG_SHA256, TRUE, &jwk) == FALSE)
396396
return FALSE;
397397

398-
decryption_keys = oidc_util_merge_symmetric_key(r->pool, oidc_cfg_private_keys_get(cfg), jwk);
398+
decryption_keys = oidc_util_key_symmetric_merge(r->pool, oidc_cfg_private_keys_get(cfg), jwk);
399399
if (oidc_cfg_provider_client_keys_get(provider))
400400
decryption_keys =
401-
oidc_util_merge_key_sets(r->pool, decryption_keys, oidc_cfg_provider_client_keys_get(provider));
401+
oidc_util_key_sets_merge(r->pool, decryption_keys, oidc_cfg_provider_client_keys_get(provider));
402402

403403
if (oidc_jwt_parse(r->pool, id_token, jwt, decryption_keys, FALSE, &err) == FALSE) {
404404
oidc_error(r, "oidc_jwt_parse failed: %s", oidc_jose_e2s(r->pool, err));
@@ -415,7 +415,7 @@ apr_byte_t oidc_proto_idtoken_parse(request_rec *r, oidc_cfg_t *cfg, oidc_provid
415415
if (is_code_flow == FALSE || _oidc_strcmp((*jwt)->header.alg, "none") != 0) {
416416

417417
jwk = NULL;
418-
if (oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, TRUE,
418+
if (oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, TRUE,
419419
&jwk) == FALSE) {
420420
oidc_jwt_destroy(*jwt);
421421
*jwt = NULL;
@@ -425,7 +425,7 @@ apr_byte_t oidc_proto_idtoken_parse(request_rec *r, oidc_cfg_t *cfg, oidc_provid
425425
if (oidc_proto_jwt_verify(
426426
r, cfg, *jwt, oidc_cfg_provider_jwks_uri_get(provider),
427427
oidc_cfg_provider_ssl_validate_server_get(provider),
428-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_provider_verify_public_keys_get(provider), jwk),
428+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_provider_verify_public_keys_get(provider), jwk),
429429
oidc_cfg_provider_id_token_signed_response_alg_get(provider)) == FALSE) {
430430

431431
oidc_error(r, "id_token signature could not be validated, aborting");

src/proto/jwt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ apr_byte_t oidc_proto_jwt_verify(request_rec *r, oidc_cfg_t *cfg, oidc_jwt_t *jw
187187

188188
/* do the actual JWS verification with the locally and remotely provided key material */
189189
// TODO: now static keys "win" if the same `kid` was used in both local and remote key sets
190-
rv = oidc_jwt_verify(r->pool, jwt, oidc_util_merge_key_sets_hash(r->pool, static_keys, dynamic_keys), &err);
190+
rv = oidc_jwt_verify(r->pool, jwt, oidc_util_key_sets_hash_merge(r->pool, static_keys, dynamic_keys), &err);
191191

192192
/* if no kid was provided we may have used stale keys from the cache, so we'll refresh it */
193193
if ((rv == FALSE) && (jwt->header.kid == NULL)) {
@@ -198,7 +198,7 @@ apr_byte_t oidc_proto_jwt_verify(request_rec *r, oidc_cfg_t *cfg, oidc_jwt_t *jw
198198
/* destroy the list to avoid memory leaks when keys with the same kid are retrieved */
199199
oidc_jwk_list_destroy_hash(dynamic_keys);
200200
oidc_proto_jwks_uri_keys(r, cfg, jwt, jwks_uri, ssl_validate_server, dynamic_keys, &force_refresh);
201-
rv = oidc_jwt_verify(r->pool, jwt, oidc_util_merge_key_sets_hash(r->pool, static_keys, dynamic_keys),
201+
rv = oidc_jwt_verify(r->pool, jwt, oidc_util_key_sets_hash_merge(r->pool, static_keys, dynamic_keys),
202202
&err);
203203
}
204204

src/proto/request.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ static char *oidc_request_uri_request_object(request_rec *r, struct oidc_provide
399399
}
400400
break;
401401
case CJOSE_JWK_KTY_OCT:
402-
oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, FALSE,
402+
oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, FALSE,
403403
&sjwk);
404404
jwk_needs_destroy = 1;
405405
break;
@@ -452,7 +452,7 @@ static char *oidc_request_uri_request_object(request_rec *r, struct oidc_provide
452452
oidc_request_uri_encryption_jwk_by_type(r, cfg, provider, oidc_jwt_alg2kty(jwe), &ejwk);
453453
break;
454454
case CJOSE_JWK_KTY_OCT:
455-
oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider),
455+
oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider),
456456
oidc_alg2keysize(jwe->header.alg), OIDC_JOSE_ALG_SHA256, FALSE,
457457
&ejwk);
458458
break;

src/proto/userinfo.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,13 @@ static apr_byte_t oidc_proto_userinfo_response_jwt_parse(request_rec *r, oidc_cf
7171
oidc_cfg_provider_userinfo_encrypted_response_alg_get(provider),
7272
oidc_cfg_provider_userinfo_encrypted_response_enc_get(provider));
7373

74-
if (oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider), oidc_alg2keysize(alg),
74+
if (oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider), oidc_alg2keysize(alg),
7575
OIDC_JOSE_ALG_SHA256, TRUE, &jwk) == FALSE)
7676
goto end;
7777

7878
if (oidc_cfg_provider_userinfo_encrypted_response_alg_get(provider) != NULL) {
7979
if (oidc_jwe_decrypt(r->pool, *response,
80-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_private_keys_get(cfg), jwk),
80+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_private_keys_get(cfg), jwk),
8181
&payload, NULL, &err, TRUE) == FALSE) {
8282
oidc_error(r, "oidc_jwe_decrypt failed: %s", oidc_jose_e2s(r->pool, err));
8383
goto end;
@@ -93,7 +93,7 @@ static apr_byte_t oidc_proto_userinfo_response_jwt_parse(request_rec *r, oidc_cf
9393
}
9494

9595
if (oidc_jwt_parse(r->pool, *response, &jwt,
96-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_private_keys_get(cfg), jwk), FALSE,
96+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_private_keys_get(cfg), jwk), FALSE,
9797
&err) == FALSE) {
9898
oidc_error(r, "oidc_jwt_parse failed: %s", oidc_jose_e2s(r->pool, err));
9999
goto end;
@@ -105,13 +105,13 @@ static apr_byte_t oidc_proto_userinfo_response_jwt_parse(request_rec *r, oidc_cf
105105
oidc_jwk_destroy(jwk);
106106
jwk = NULL;
107107

108-
if (oidc_util_create_symmetric_key(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, TRUE, &jwk) ==
108+
if (oidc_util_key_symmetric_create(r, oidc_cfg_provider_client_secret_get(provider), 0, NULL, TRUE, &jwk) ==
109109
FALSE)
110110
goto end;
111111

112112
if (oidc_proto_jwt_verify(r, cfg, jwt, oidc_cfg_provider_jwks_uri_get(provider),
113113
oidc_cfg_provider_ssl_validate_server_get(provider),
114-
oidc_util_merge_symmetric_key(r->pool, NULL, jwk),
114+
oidc_util_key_symmetric_merge(r->pool, NULL, jwk),
115115
oidc_cfg_provider_userinfo_signed_response_alg_get(provider)) == FALSE) {
116116

117117
oidc_error(r, "JWT signature could not be validated, aborting");
@@ -193,7 +193,7 @@ static apr_byte_t oidc_proto_userinfo_request_composite_claims(request_rec *r, o
193193
oidc_jwt_t *jwt = NULL;
194194
if (oidc_jwt_parse(
195195
r->pool, s_json, &jwt,
196-
oidc_util_merge_symmetric_key(r->pool, oidc_cfg_private_keys_get(cfg), jwk),
196+
oidc_util_key_symmetric_merge(r->pool, oidc_cfg_private_keys_get(cfg), jwk),
197197
FALSE, &err) == FALSE) {
198198
oidc_error(r, "could not parse JWT from aggregated claim \"%s\": %s", key,
199199
oidc_jose_e2s(r->pool, err));

src/util/jwt.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ apr_byte_t oidc_util_jwt_create(request_rec *r, const oidc_crypto_passphrase_t *
122122
goto end;
123123
}
124124

125-
if (oidc_util_create_symmetric_key(r, passphrase->secret1, 0, OIDC_JOSE_ALG_SHA256, FALSE, &jwk) == FALSE)
125+
if (oidc_util_key_symmetric_create(r, passphrase->secret1, 0, OIDC_JOSE_ALG_SHA256, FALSE, &jwk) == FALSE)
126126
goto end;
127127

128128
if (oidc_util_jwt_internal_compress(r)) {
@@ -197,11 +197,11 @@ apr_byte_t oidc_util_jwt_verify(request_rec *r, const oidc_crypto_passphrase_t *
197197
keys = apr_hash_make(r->pool);
198198

199199
if ((passphrase->secret2 != NULL) && (kid == NULL)) {
200-
if (oidc_util_create_symmetric_key(r, passphrase->secret2, 0, OIDC_JOSE_ALG_SHA256, FALSE, &jwk) ==
200+
if (oidc_util_key_symmetric_create(r, passphrase->secret2, 0, OIDC_JOSE_ALG_SHA256, FALSE, &jwk) ==
201201
FALSE)
202202
goto end;
203203
} else {
204-
if (oidc_util_create_symmetric_key(r, passphrase->secret1, 0, OIDC_JOSE_ALG_SHA256, FALSE, &jwk) ==
204+
if (oidc_util_key_symmetric_create(r, passphrase->secret1, 0, OIDC_JOSE_ALG_SHA256, FALSE, &jwk) ==
205205
FALSE)
206206
goto end;
207207
}

src/util/key.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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-2025 ZmartZone Holding BV
22+
* All rights reserved.
23+
*
24+
* DISCLAIMER OF WARRANTIES:
25+
*
26+
* THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
27+
* ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING,
28+
* WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT,
29+
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY
30+
* WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE
31+
* USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET
32+
* YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE
33+
* WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
34+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF
36+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39+
*
40+
* @Author: Hans Zandbelt - [email protected]
41+
*/
42+
43+
#include "util/util.h"
44+
45+
/*
46+
* create a symmetric key from a client_secret
47+
*/
48+
apr_byte_t oidc_util_key_symmetric_create(request_rec *r, const char *client_secret, unsigned int r_key_len,
49+
const char *hash_algo, apr_byte_t set_kid, oidc_jwk_t **jwk) {
50+
oidc_jose_error_t err = {{'\0'}, 0, {'\0'}, {'\0'}};
51+
unsigned char *key = NULL;
52+
unsigned int key_len;
53+
54+
if ((client_secret != NULL) && (_oidc_strlen(client_secret) > 0)) {
55+
56+
if (hash_algo == NULL) {
57+
key = (unsigned char *)client_secret;
58+
key_len = _oidc_strlen(client_secret);
59+
} else {
60+
/* hash the client_secret first, this is OpenID Connect specific */
61+
oidc_jose_hash_bytes(r->pool, hash_algo, (const unsigned char *)client_secret,
62+
_oidc_strlen(client_secret), &key, &key_len, &err);
63+
}
64+
65+
if ((key != NULL) && (key_len > 0)) {
66+
if ((r_key_len != 0) && (key_len >= r_key_len))
67+
key_len = r_key_len;
68+
oidc_debug(r, "key_len=%d", key_len);
69+
*jwk = oidc_jwk_create_symmetric_key(r->pool, NULL, key, key_len, set_kid, &err);
70+
}
71+
72+
if (*jwk == NULL) {
73+
oidc_error(r, "could not create JWK from the provided secret: %s", oidc_jose_e2s(r->pool, err));
74+
return FALSE;
75+
}
76+
}
77+
78+
return TRUE;
79+
}
80+
81+
/*
82+
* merge provided keys and client secret in to a single hashtable
83+
*/
84+
apr_hash_t *oidc_util_key_symmetric_merge(apr_pool_t *pool, const apr_array_header_t *keys, oidc_jwk_t *jwk) {
85+
apr_hash_t *result = apr_hash_make(pool);
86+
const oidc_jwk_t *elem = NULL;
87+
int i = 0;
88+
if (keys != NULL) {
89+
for (i = 0; i < keys->nelts; i++) {
90+
elem = APR_ARRAY_IDX(keys, i, oidc_jwk_t *);
91+
apr_hash_set(result, elem->kid, APR_HASH_KEY_STRING, elem);
92+
}
93+
}
94+
if (jwk != NULL) {
95+
apr_hash_set(result, jwk->kid, APR_HASH_KEY_STRING, jwk);
96+
}
97+
return result;
98+
}
99+
100+
/*
101+
* merge the provided array of keys (k2) into a hash table of keys (k1)
102+
*/
103+
apr_hash_t *oidc_util_key_sets_merge(apr_pool_t *pool, apr_hash_t *k1, const apr_array_header_t *k2) {
104+
apr_hash_t *rv = k1 ? apr_hash_copy(pool, k1) : apr_hash_make(pool);
105+
const oidc_jwk_t *jwk = NULL;
106+
int i = 0;
107+
if (k2 != NULL) {
108+
for (i = 0; i < k2->nelts; i++) {
109+
jwk = APR_ARRAY_IDX(k2, i, oidc_jwk_t *);
110+
apr_hash_set(rv, jwk->kid, APR_HASH_KEY_STRING, jwk);
111+
}
112+
}
113+
return rv;
114+
}
115+
116+
/*
117+
* merge two hash tables with key sets
118+
*/
119+
apr_hash_t *oidc_util_key_sets_hash_merge(apr_pool_t *pool, apr_hash_t *k1, apr_hash_t *k2) {
120+
if (k1 == NULL) {
121+
if (k2 == NULL)
122+
return apr_hash_make(pool);
123+
return k2;
124+
}
125+
if (k2 == NULL)
126+
return k1;
127+
return apr_hash_overlay(pool, k1, k2);
128+
}
129+
130+
/*
131+
* return the first JWK that matches a provided key type and use from an array of JWKs
132+
*/
133+
oidc_jwk_t *oidc_util_key_list_first(const apr_array_header_t *key_list, int kty, const char *use) {
134+
oidc_jwk_t *rv = NULL;
135+
int i = 0;
136+
oidc_jwk_t *jwk = NULL;
137+
for (i = 0; (key_list) && (i < key_list->nelts); i++) {
138+
jwk = APR_ARRAY_IDX(key_list, i, oidc_jwk_t *);
139+
if ((kty != -1) && (jwk->kty != kty))
140+
continue;
141+
if (((use == NULL) || (jwk->use == NULL) || (_oidc_strncmp(jwk->use, use, _oidc_strlen(use)) == 0))) {
142+
rv = jwk;
143+
break;
144+
}
145+
}
146+
return rv;
147+
}
148+

0 commit comments

Comments
 (0)