@@ -98,6 +98,338 @@ START_TEST(test_jose_jwe_encryption_is_supported) {
9898}
9999END_TEST
100100
101+ START_TEST (test_jose_hash_and_base64_and_length ) {
102+ apr_pool_t * pool = oidc_test_pool_get ();
103+ oidc_jose_error_t err ;
104+ char * hash = NULL ;
105+ unsigned int hash_len = 0 ;
106+
107+ ck_assert_msg (oidc_jose_hash_string (pool , CJOSE_HDR_ALG_RS256 , "hello" , & hash , & hash_len , & err ) == TRUE,
108+ "oidc_jose_hash_string failed" );
109+ ck_assert_msg (hash != NULL , "hash is NULL" );
110+ ck_assert_msg ((int )hash_len == oidc_jose_hash_length (CJOSE_HDR_ALG_RS256 ), "hash length mismatch" );
111+
112+ char * b64 = NULL ;
113+ ck_assert_msg (oidc_jose_hash_and_base64url_encode (pool , OIDC_JOSE_ALG_SHA256 , "hello" , 5 , & b64 , & err ) == TRUE,
114+ "oidc_jose_hash_and_base64url_encode failed" );
115+ ck_assert_msg (b64 != NULL , "base64url output is NULL" );
116+ ck_assert_str_eq (b64 , "LPJNul-wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ" );
117+ }
118+ END_TEST
119+
120+ START_TEST (test_jose_get_string_and_timestamps ) {
121+ apr_pool_t * pool = oidc_test_pool_get ();
122+ json_t * j = json_object ();
123+ json_object_set_new (j , "k1" , json_string ("v1" ));
124+ json_object_set_new (j , "num" , json_integer (123 ));
125+ json_object_set_new (j , "t1" , json_real (4.5 ));
126+ char * s = NULL ;
127+ oidc_jose_error_t err ;
128+
129+ ck_assert_msg (oidc_jose_get_string (pool , j , "k1" , TRUE, & s , & err ) == TRUE,
130+ "get string failed for existing key" );
131+ ck_assert_msg (_oidc_strcmp (s , "v1" ) == 0 , "unexpected value" );
132+
133+ char * s2 = NULL ;
134+ ck_assert_msg (oidc_jose_get_string (pool , j , "missing" , TRUE, & s2 , & err ) == FALSE,
135+ "get string should have failed for missing mandatory key" );
136+
137+ double ts = 0 ;
138+ ck_assert_msg (oidc_jose_get_timestamp (pool , j , "t1" , TRUE, & ts , & err ) == TRUE,
139+ "get timestamp failed for existing key" );
140+ ck_assert_msg (ts == 4.5 , "unexpected value" );
141+
142+ double ts2 = 0 ;
143+ ck_assert_msg (oidc_jose_get_timestamp (pool , j , "tsmissing" , TRUE, & ts2 , & err ) == FALSE,
144+ "get timestamp should have failed for missing mandatory key" );
145+
146+ json_decref (j );
147+ }
148+ END_TEST
149+
150+ START_TEST (test_jose_compress_uncompress ) {
151+ apr_pool_t * pool = oidc_test_pool_get ();
152+ const char * input = "the quick brown fox jumps over the lazy dog" ;
153+ int input_len = (int )_oidc_strlen (input );
154+ char * out = NULL ;
155+ int out_len = 0 ;
156+ oidc_jose_error_t err ;
157+ ck_assert_msg (oidc_jose_compress (pool , input , input_len , & out , & out_len , & err ) == TRUE, "compress failed" );
158+ ck_assert_msg (out != NULL , "compress returned NULL output" );
159+
160+ char * un = NULL ;
161+ int un_len = 0 ;
162+ ck_assert_msg (oidc_jose_uncompress (pool , out , out_len , & un , & un_len , & err ) == TRUE, "uncompress failed" );
163+ ck_assert_msg (un != NULL , "uncompress returned NULL output" );
164+ ck_assert_msg (un_len == input_len , "uncompressed length mismatch" );
165+ ck_assert_msg (memcmp (un , input , input_len ) == 0 , "uncompressed data differs from original" );
166+ }
167+ END_TEST
168+
169+ START_TEST (test_jose_jwk_and_json_and_copy_lists ) {
170+ apr_pool_t * pool = oidc_test_pool_get ();
171+ oidc_jose_error_t err ;
172+ const char * src_file = __FILE__ ;
173+ char * dir = NULL ;
174+ char * slash = strrchr (src_file , '/' );
175+ if (slash )
176+ dir = apr_pstrndup (pool , src_file , (int )(slash - src_file ));
177+ else
178+ dir = apr_pstrdup (pool , "." );
179+ char * pub_path = apr_psprintf (pool , "%s/public.pem" , dir );
180+
181+ oidc_jwk_t * pub = NULL ;
182+ if (oidc_jwk_parse_pem_public_key (pool , NULL , pub_path , & pub , & err ) != TRUE) {
183+ char * e = oidc_jose_e2s (pool , err );
184+ ck_abort_msg ("oidc_jwk_parse_pem_public_key failed: %s" , e );
185+ }
186+ ck_assert_ptr_nonnull (pub );
187+ ck_assert_ptr_nonnull (pub -> kid );
188+
189+ char * s_json = NULL ;
190+ ck_assert_msg (oidc_jwk_to_json (pool , pub , & s_json , & err ) == TRUE, "oidc_jwk_to_json failed" );
191+ ck_assert_ptr_nonnull (s_json );
192+ json_error_t je ;
193+ json_t * j = json_loads (s_json , 0 , & je );
194+ ck_assert_ptr_nonnull (j );
195+ json_t * kty = json_object_get (j , "kty" );
196+ ck_assert_ptr_nonnull (kty );
197+ json_decref (j );
198+
199+ unsigned char key [32 ];
200+ for (int i = 0 ; i < 32 ; i ++ )
201+ key [i ] = (unsigned char )i ;
202+ oidc_jwk_t * sym = oidc_jwk_create_symmetric_key (pool , "symkid" , key , 32 , TRUE, & err );
203+ ck_assert_ptr_nonnull (sym );
204+ ck_assert_ptr_nonnull (sym -> kid );
205+
206+ oidc_jwk_t * sym_copy = oidc_jwk_copy (pool , sym );
207+ ck_assert_ptr_nonnull (sym_copy );
208+ ck_assert_ptr_nonnull (sym_copy -> kid );
209+
210+ apr_array_header_t * arr = apr_array_make (pool , 1 , sizeof (const oidc_jwk_t * ));
211+ APR_ARRAY_PUSH (arr , const oidc_jwk_t * ) = sym ;
212+ apr_array_header_t * arr_copy = oidc_jwk_list_copy (pool , arr );
213+ ck_assert_msg (arr_copy != NULL && arr_copy -> nelts == 1 , "oidc_jwk_list_copy failed" );
214+
215+ apr_hash_t * h = apr_hash_make (pool );
216+ apr_hash_set (h , sym -> kid , APR_HASH_KEY_STRING , sym );
217+ oidc_jwk_list_destroy_hash (h );
218+ ck_assert_int_eq (apr_hash_count (h ), 0 );
219+ }
220+ END_TEST
221+
222+ START_TEST (test_jose_jwe_decrypt_plaintext ) {
223+ apr_pool_t * pool = oidc_test_pool_get ();
224+ char * plaintext = NULL ;
225+ int plaintext_len = 0 ;
226+ oidc_jose_error_t err ;
227+ ck_assert_msg (oidc_jwe_decrypt (pool , "plain-text-data" , NULL , & plaintext , & plaintext_len , & err , FALSE) == TRUE,
228+ "oidc_jwe_decrypt passthrough failed" );
229+ ck_assert_ptr_nonnull (plaintext );
230+ ck_assert_msg (plaintext_len == (int )_oidc_strlen ("plain-text-data" ), "plaintext len mismatch" );
231+ ck_assert_msg (_oidc_strcmp (plaintext , "plain-text-data" ) == 0 , "plaintext content mismatch" );
232+ }
233+ END_TEST
234+
235+ START_TEST (test_jwt_sign_verify_and_encrypt_decrypt ) {
236+ apr_pool_t * pool = oidc_test_pool_get ();
237+ oidc_jose_error_t err ;
238+ unsigned char key [32 ];
239+ for (int i = 0 ; i < 32 ; i ++ )
240+ key [i ] = (unsigned char )(i + 1 );
241+ oidc_jwk_t * sym = oidc_jwk_create_symmetric_key (pool , "hskid" , key , 32 , TRUE, & err );
242+ ck_assert_ptr_nonnull (sym );
243+
244+ oidc_jwt_t * jwt = oidc_jwt_new (pool , 1 , 1 );
245+ json_object_set_new (jwt -> payload .value .json , "iss" , json_string ("unit-test" ));
246+ jwt -> header .alg = apr_pstrdup (pool , CJOSE_HDR_ALG_HS256 );
247+
248+ ck_assert_msg (oidc_jwt_sign (pool , jwt , sym , FALSE, & err ) == TRUE, "oidc_jwt_sign failed" );
249+ ck_assert_ptr_nonnull (jwt -> cjose_jws );
250+
251+ apr_hash_t * keys = apr_hash_make (pool );
252+ apr_hash_set (keys , sym -> kid , APR_HASH_KEY_STRING , sym );
253+ ck_assert_msg (oidc_jwt_verify (pool , jwt , keys , & err ) == TRUE, "oidc_jwt_verify failed" );
254+
255+ oidc_jwt_t * none_jwt = oidc_jwt_new (pool , 1 , 1 );
256+ json_object_set_new (none_jwt -> payload .value .json , "hello" , json_string ("world" ));
257+ none_jwt -> header .alg = apr_pstrdup (pool , CJOSE_HDR_ALG_NONE );
258+ char * s = oidc_jose_jwt_serialize (pool , none_jwt , & err );
259+ ck_assert_ptr_nonnull (s );
260+
261+ char * dot = strchr (s , '.' );
262+ ck_assert_ptr_nonnull (dot );
263+ int hdr_len = (int )(dot - s );
264+ char * hdr_b64 = apr_pstrndup (pool , s , hdr_len );
265+ unsigned char * decoded = NULL ;
266+ size_t decoded_len = 0 ;
267+ cjose_err cjose_err_local ;
268+ if (cjose_base64url_decode (hdr_b64 , _oidc_strlen (hdr_b64 ), & decoded , & decoded_len , & cjose_err_local ) == FALSE) {
269+ ck_abort_msg ("cjose_base64url_decode failed: %s" , oidc_cjose_e2s (pool , cjose_err_local ));
270+ }
271+ char * hdr_json = apr_pstrmemdup (pool , (const char * )decoded , decoded_len );
272+ cjose_get_dealloc ()(decoded );
273+ json_error_t jerr ;
274+ json_t * hdr_obj = json_loads (hdr_json , 0 , & jerr );
275+ ck_assert_ptr_nonnull (hdr_obj );
276+ json_t * alg = json_object_get (hdr_obj , "alg" );
277+ ck_assert_ptr_nonnull (alg );
278+ ck_assert_msg (json_is_string (alg ) && _oidc_strcmp (json_string_value (alg ), "none" ) == 0 , "alg is not 'none'" );
279+ json_decref (hdr_obj );
280+
281+ const char * src_file = __FILE__ ;
282+ char * dir = NULL ;
283+ char * slash = strrchr (src_file , '/' );
284+ if (slash )
285+ dir = apr_pstrndup (pool , src_file , (int )(slash - src_file ));
286+ else
287+ dir = apr_pstrdup (pool , "." );
288+ char * pub_path = apr_psprintf (pool , "%s/public.pem" , dir );
289+ char * priv_path = apr_psprintf (pool , "%s/private.pem" , dir );
290+
291+ oidc_jwk_t * pub = NULL ;
292+ if (oidc_jwk_parse_pem_public_key (pool , NULL , pub_path , & pub , & err ) != TRUE) {
293+ char * e = oidc_jose_e2s (pool , err );
294+ ck_abort_msg ("parse public pem failed: %s" , e );
295+ }
296+ ck_assert_ptr_nonnull (pub );
297+ oidc_jwk_t * priv = NULL ;
298+ if (oidc_jwk_parse_pem_private_key (pool , NULL , priv_path , & priv , & err ) != TRUE) {
299+ char * e = oidc_jose_e2s (pool , err );
300+ ck_abort_msg ("parse private pem failed: %s" , e );
301+ }
302+ ck_assert_ptr_nonnull (priv );
303+
304+ oidc_jwt_t * jwe = oidc_jwt_new (pool , 1 , 0 );
305+ jwe -> header .alg = apr_pstrdup (pool , CJOSE_HDR_ALG_RSA_OAEP );
306+ jwe -> header .enc = apr_pstrdup (pool , CJOSE_HDR_ENC_A128CBC_HS256 );
307+ jwe -> header .kid = apr_pstrdup (pool , pub -> kid );
308+
309+ char * serialized = NULL ;
310+ const char * payload = "this is a secret" ;
311+ ck_assert_msg (oidc_jwt_encrypt (pool , jwe , pub , payload , (int )_oidc_strlen (payload ), & serialized , & err ) == TRUE,
312+ "oidc_jwt_encrypt failed" );
313+ ck_assert_ptr_nonnull (serialized );
314+
315+ apr_hash_t * dec_keys = apr_hash_make (pool );
316+ apr_hash_set (dec_keys , priv -> kid , APR_HASH_KEY_STRING , priv );
317+ char * dec_plain = NULL ;
318+ int dec_plain_len = 0 ;
319+ ck_assert_msg (oidc_jwe_decrypt (pool , serialized , dec_keys , & dec_plain , & dec_plain_len , & err , TRUE) == TRUE,
320+ "oidc_jwe_decrypt failed" );
321+ ck_assert_msg (dec_plain_len == (int )_oidc_strlen (payload ), "decrypted length mismatch" );
322+ ck_assert_msg (memcmp (dec_plain , payload , dec_plain_len ) == 0 , "decrypted plaintext mismatch" );
323+ }
324+ END_TEST
325+
326+ START_TEST (test_jose_hash_bytes ) {
327+ apr_pool_t * pool = oidc_test_pool_get ();
328+ unsigned char * out = NULL ;
329+ unsigned int out_len = 0 ;
330+ oidc_jose_error_t err ;
331+
332+ ck_assert_msg (oidc_jose_hash_bytes (pool , OIDC_JOSE_ALG_SHA256 , (const unsigned char * )"abc" , 3 , & out , & out_len ,
333+ & err ) == TRUE,
334+ "oidc_jose_hash_bytes failed" );
335+ ck_assert_msg (out != NULL , "hash output is NULL" );
336+ ck_assert_msg ((int )out_len == oidc_jose_hash_length (CJOSE_HDR_ALG_RS256 ), "hash length mismatch" );
337+ }
338+ END_TEST
339+
340+ START_TEST (test_jwk_json_parse_and_jwks ) {
341+ apr_pool_t * pool = oidc_test_pool_get ();
342+ oidc_jose_error_t err ;
343+ const char * src_file = __FILE__ ;
344+ char * dir = NULL ;
345+ char * slash = strrchr (src_file , '/' );
346+ if (slash )
347+ dir = apr_pstrndup (pool , src_file , (int )(slash - src_file ));
348+ else
349+ dir = apr_pstrdup (pool , "." );
350+ char * pub_path = apr_psprintf (pool , "%s/public.pem" , dir );
351+
352+ oidc_jwk_t * pub = NULL ;
353+ if (oidc_jwk_parse_pem_public_key (pool , NULL , pub_path , & pub , & err ) != TRUE) {
354+ char * e = oidc_jose_e2s (pool , err );
355+ ck_abort_msg ("oidc_jwk_parse_pem_public_key failed: %s" , e );
356+ }
357+ ck_assert_ptr_nonnull (pub );
358+
359+ char * s_json = NULL ;
360+ ck_assert_msg (oidc_jwk_to_json (pool , pub , & s_json , & err ) == TRUE, "oidc_jwk_to_json failed" );
361+ json_error_t je ;
362+ json_t * j = json_loads (s_json , 0 , & je );
363+ ck_assert_ptr_nonnull (j );
364+
365+ oidc_jwk_t * parsed = oidc_jwk_parse (pool , j , & err );
366+ ck_assert_ptr_nonnull (parsed );
367+ ck_assert_ptr_nonnull (parsed -> kid );
368+
369+ ck_assert_msg (oidc_is_jwk (j ) == TRUE, "oidc_is_jwk false for JWK json" );
370+
371+ json_t * jwks = json_object ();
372+ json_t * arr = json_array ();
373+ json_array_append_new (arr , json_deep_copy (j ));
374+ json_object_set_new (jwks , "keys" , arr );
375+ apr_array_header_t * jwk_list = NULL ;
376+ ck_assert_msg (oidc_jwks_parse_json (pool , jwks , & jwk_list , & err ) == TRUE, "oidc_jwks_parse_json failed" );
377+ ck_assert_msg (jwk_list != NULL && jwk_list -> nelts == 1 , "jwks parse returned wrong number of keys" );
378+ ck_assert_msg (oidc_is_jwks (jwks ) == TRUE, "oidc_is_jwks false for jwks json" );
379+
380+ json_decref (j );
381+ json_decref (jwks );
382+ }
383+ END_TEST
384+
385+ START_TEST (test_jwk_list_destroy ) {
386+ apr_pool_t * pool = oidc_test_pool_get ();
387+ apr_array_header_t * arr = apr_array_make (pool , 2 , sizeof (const oidc_jwk_t * ));
388+ oidc_jose_error_t err ;
389+ unsigned char key [16 ] = {0 };
390+ for (int i = 0 ; i < 2 ; i ++ ) {
391+ char kid [8 ];
392+ snprintf (kid , sizeof (kid ), "k%02d" , i );
393+ oidc_jwk_t * sym = oidc_jwk_create_symmetric_key (pool , kid , key , 16 , TRUE, & err );
394+ APR_ARRAY_PUSH (arr , const oidc_jwk_t * ) = sym ;
395+ }
396+ oidc_jwk_list_destroy (arr );
397+ ck_assert_int_eq (arr -> nelts , 0 );
398+ }
399+ END_TEST
400+
401+ START_TEST (test_alg2keysize_and_hdr_get_and_jwt_parse ) {
402+ apr_pool_t * pool = oidc_test_pool_get ();
403+ oidc_jose_error_t err ;
404+ ck_assert_msg (oidc_alg2keysize (CJOSE_HDR_ALG_A128KW ) == 16 , "A128KW keysize wrong" );
405+ ck_assert_msg (oidc_alg2keysize (CJOSE_HDR_ALG_A256KW ) == 32 , "A256KW keysize wrong" );
406+ ck_assert_msg (oidc_alg2keysize (CJOSE_HDR_ALG_RS256 ) == 32 , "RS256 keysize wrong" );
407+
408+ unsigned char key [32 ];
409+ for (int i = 0 ; i < 32 ; i ++ )
410+ key [i ] = (unsigned char )(i + 2 );
411+ oidc_jwk_t * sym = oidc_jwk_create_symmetric_key (pool , "parsekid" , key , 32 , TRUE, & err );
412+ ck_assert_ptr_nonnull (sym );
413+
414+ oidc_jwt_t * jwt = oidc_jwt_new (pool , 1 , 1 );
415+ json_object_set_new (jwt -> payload .value .json , "sub" , json_string ("subject" ));
416+ jwt -> header .alg = apr_pstrdup (pool , CJOSE_HDR_ALG_HS256 );
417+ ck_assert_msg (oidc_jwt_sign (pool , jwt , sym , FALSE, & err ) == TRUE, "oidc_jwt_sign failed" );
418+ char * s = oidc_jose_jwt_serialize (pool , jwt , & err );
419+ ck_assert_ptr_nonnull (s );
420+
421+ apr_hash_t * keys = apr_hash_make (pool );
422+ apr_hash_set (keys , sym -> kid , APR_HASH_KEY_STRING , sym );
423+ oidc_jwt_t * parsed = NULL ;
424+ ck_assert_msg (oidc_jwt_parse (pool , s , & parsed , keys , FALSE, & err ) == TRUE, "oidc_jwt_parse failed" );
425+ ck_assert_ptr_nonnull (parsed );
426+
427+ const char * alg = oidc_jwt_hdr_get (parsed , "alg" );
428+ ck_assert_ptr_nonnull (alg );
429+ ck_assert_msg (_oidc_strcmp (alg , CJOSE_HDR_ALG_HS256 ) == 0 , "parsed alg mismatch" );
430+ }
431+ END_TEST
432+
101433int main (void ) {
102434 TCase * sup = tcase_create ("supported" );
103435 tcase_add_checked_fixture (sup , oidc_test_setup , oidc_test_teardown );
@@ -109,8 +441,22 @@ int main(void) {
109441 tcase_add_test (sup , test_jose_jwe_supported_encryptions );
110442 tcase_add_test (sup , test_jose_jwe_encryption_is_supported );
111443
444+ TCase * core = tcase_create ("core" );
445+ tcase_add_checked_fixture (core , oidc_test_setup , oidc_test_teardown );
446+ tcase_add_test (core , test_jose_hash_and_base64_and_length );
447+ tcase_add_test (core , test_jose_get_string_and_timestamps );
448+ tcase_add_test (core , test_jose_compress_uncompress );
449+ tcase_add_test (core , test_jose_jwk_and_json_and_copy_lists );
450+ tcase_add_test (core , test_jose_jwe_decrypt_plaintext );
451+ tcase_add_test (core , test_jwt_sign_verify_and_encrypt_decrypt );
452+ tcase_add_test (core , test_jose_hash_bytes );
453+ tcase_add_test (core , test_jwk_json_parse_and_jwks );
454+ tcase_add_test (core , test_jwk_list_destroy );
455+ tcase_add_test (core , test_alg2keysize_and_hdr_get_and_jwt_parse );
456+
112457 Suite * s = suite_create ("jose" );
113458 suite_add_tcase (s , sup );
459+ suite_add_tcase (s , core );
114460
115461 return oidc_test_suite_run (s );
116462}
0 commit comments