From 3f9d7e4c487dfa28b43b6292d4bee28c5233d851 Mon Sep 17 00:00:00 2001 From: Tristan Schwieren Date: Thu, 21 Apr 2022 15:53:15 +0200 Subject: - generate valid token respoise with RS256 signature --- src/reclaim/oidc_helper.c | 205 ++++++++++++++++--------------- src/reclaim/oidc_helper.h | 31 +++-- src/reclaim/plugin_rest_openid_connect.c | 5 +- 3 files changed, 127 insertions(+), 114 deletions(-) diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c index ff34e045e..cfa71b26c 100644 --- a/src/reclaim/oidc_helper.c +++ b/src/reclaim/oidc_helper.c @@ -22,6 +22,7 @@ * @file reclaim/oidc_helper.c * @brief helper library for OIDC related functions * @author Martin Schanzenbach + * @author Tristan Schwieren */ #include "platform.h" #include @@ -116,13 +117,13 @@ is_claim_in_address_scope (const char *claim) static char * -create_jwt_header (void) +create_jwt_hmac_header (void) { json_t *root; char *json_str; root = json_object (); - json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); + json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE_HMAC)); json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); json_str = json_dumps (root, JSON_INDENT (0) | JSON_COMPACT); @@ -356,36 +357,23 @@ OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *sub_key, return body_str; } -/** - * Create a JWT from attributes - * TODO: separate creation of body in OIDC_generate_id_token* - * - * @param aud_key the public of the audience - * @param sub_key the public key of the subject - * @param attrs the attribute list - * @param presentations credential presentation list (may be empty) - * @param expiration_time the validity of the token - * @param secret_rsa_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ + char * -OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, - const struct GNUNET_IDENTITY_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const json_t *secret_rsa_key) +generate_id_token_body (const struct GNUNET_IDENTITY_PublicKey *aud_key, + const struct GNUNET_IDENTITY_PublicKey *sub_key, + const struct GNUNET_RECLAIM_AttributeList *attrs, + const struct + GNUNET_RECLAIM_PresentationList *presentations, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce) { struct GNUNET_HashCode signature; struct GNUNET_TIME_Absolute exp_time; struct GNUNET_TIME_Absolute time_now; + json_t *body; char *audience; char *subject; - char *body_str; // REMOVE - char *result; - json_t *body; + char *body_str; body = generate_userinfo_json (sub_key, attrs, @@ -424,35 +412,80 @@ OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, if (NULL != nonce) json_object_set_new (body, "nonce", json_string (nonce)); - body_str = json_dumps (body, JSON_INDENT (2) | JSON_COMPACT); // REMOVE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str); // REMOVE + // Error checking + body_str = json_dumps (body, JSON_INDENT (2) | JSON_COMPACT); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str); + json_decref (body); GNUNET_free (subject); GNUNET_free (audience); - /** - * Creating the JWT signature. - */ - char *str = "Hallo Welt!"; - json_t *jws = json_pack ("{s:o}", "payload", - jose_b64_enc (str, strlen (str))); - jose_jws_sig (NULL, jws, NULL, secret_rsa_key); + return body_str; +} - str = json_dumps (jws, JSON_INDENT (2) | JSON_COMPACT); // REMOVE - printf ("jwk_json: %s\n", str); // REMOVE - GNUNET_asprintf (&str, "%s.%s.%s", +/** + * Create a JWT using RSA256 algorithm from attributes + * + * @param aud_key the public of the audience + * @param sub_key the public key of the subject + * @param attrs the attribute list + * @param presentations credential presentation list (may be empty) + * @param expiration_time the validity of the token + * @param secret_rsa_key the key used to sign the JWT + * @return a new base64-encoded JWT string. + */ +char * +OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, + const struct GNUNET_IDENTITY_PublicKey *sub_key, + const struct GNUNET_RECLAIM_AttributeList *attrs, + const struct + GNUNET_RECLAIM_PresentationList *presentations, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce, + const json_t *secret_rsa_key) +{ + json_t *jws; + char *body_str; + char *result; + + // Generate the body of the JSON Web Signature + body_str = generate_id_token_body (aud_key, + sub_key, + attrs, + presentations, + expiration_time, + nonce); + + if (! body_str) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Body for the JWS could not be generated\n"); + } + + // Creating the JSON Web Signature. + jws = json_pack ("{s:o}", "payload", + jose_b64_enc (body_str, strlen (body_str))); + + if (! jose_jws_sig (NULL, jws, NULL, secret_rsa_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Signature generation failed\n"); + } + + // Encoding JSON as compact JSON Web Signature + GNUNET_asprintf (&result, "%s.%s.%s", json_string_value (json_object_get (jws, "protected")), json_string_value (json_object_get (jws, "payload")), json_string_value (json_object_get (jws, "signature")) ); - printf ("jwk: %s\n", str); - - return str; + json_decref(jws); + GNUNET_free(body_str); + return result; } /** - * Create a JWT from attributes + * Create a JWT using HMAC (HS256) from attributes * * @param aud_key the public of the audience * @param sub_key the public key of the subject @@ -463,80 +496,48 @@ OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, * @return a new base64-encoded JWT string. */ char * -OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, - const struct GNUNET_IDENTITY_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key) +OIDC_generate_id_token_hmac (const struct GNUNET_IDENTITY_PublicKey *aud_key, + const struct GNUNET_IDENTITY_PublicKey *sub_key, + const struct GNUNET_RECLAIM_AttributeList *attrs, + const struct + GNUNET_RECLAIM_PresentationList *presentations, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce, + const char *secret_key) { struct GNUNET_HashCode signature; struct GNUNET_TIME_Absolute exp_time; struct GNUNET_TIME_Absolute time_now; - char *audience; - char *subject; char *header; - char *body_str; - char *result; char *header_base64; + char *body_str; char *body_base64; char *signature_target; char *signature_base64; - json_t *body; - - body = generate_userinfo_json (sub_key, - attrs, - presentations); - // iat REQUIRED time now - time_now = GNUNET_TIME_absolute_get (); - // exp REQUIRED time expired from config - exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); - // auth_time only if max_age - // nonce only if nonce - // OPTIONAL acr,amr,azp - subject = - GNUNET_STRINGS_data_to_string_alloc (sub_key, - sizeof(struct - GNUNET_IDENTITY_PublicKey)); - audience = - GNUNET_STRINGS_data_to_string_alloc (aud_key, - sizeof(struct - GNUNET_IDENTITY_PublicKey)); - header = create_jwt_header (); - - // aud REQUIRED public key client_id must be there - json_object_set_new (body, "aud", json_string (audience)); - // iat - json_object_set_new (body, - "iat", - json_integer (time_now.abs_value_us / (1000 * 1000))); - // exp - json_object_set_new (body, - "exp", - json_integer (exp_time.abs_value_us / (1000 * 1000))); - // nbf - json_object_set_new (body, - "nbf", - json_integer (time_now.abs_value_us / (1000 * 1000))); - // nonce - if (NULL != nonce) - json_object_set_new (body, "nonce", json_string (nonce)); - - body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT); - json_decref (body); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str); + char *result; + // Generate and encode Header + header = create_jwt_hmac_header (); GNUNET_STRINGS_base64url_encode (header, strlen (header), &header_base64); fix_base64 (header_base64); + // Generate and encode the body of the JSON Web Signature + body_str = generate_id_token_body (aud_key, + sub_key, + attrs, + presentations, + expiration_time, + nonce); + + if (! body_str) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Body for the JWS could not be generated\n"); + } + GNUNET_STRINGS_base64url_encode (body_str, strlen (body_str), &body_base64); fix_base64 (body_base64); - GNUNET_free (subject); - GNUNET_free (audience); - /** * Creating the JWT signature. This might not be * standards compliant, check. @@ -558,12 +559,12 @@ OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, body_base64, signature_base64); - GNUNET_free (signature_target); GNUNET_free (header); + GNUNET_free (header_base64); GNUNET_free (body_str); - GNUNET_free (signature_base64); GNUNET_free (body_base64); - GNUNET_free (header_base64); + GNUNET_free (signature_target); + GNUNET_free (signature_base64); return result; } diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h index 0a2f832ad..12c99a7bc 100644 --- a/src/reclaim/oidc_helper.h +++ b/src/reclaim/oidc_helper.h @@ -30,7 +30,7 @@ #define JWT_ALG "alg" /* Use 512bit HMAC */ -#define JWT_ALG_VALUE "HS512" +#define JWT_ALG_VALUE_HMAC "HS512" #define JWT_TYP "typ" @@ -51,6 +51,17 @@ enum OIDC_VerificationOptions OIDC_VERIFICATION_NO_CODE_VERIFIER = 1 }; +/** + * Create a JWT using RSA256 from attributes + * + * @param aud_key the public of the audience + * @param sub_key the public key of the subject + * @param attrs the attribute list + * @param presentations credential presentation list (may be empty) + * @param expiration_time the validity of the token + * @param secret_key the key used to sign the JWT + * @return a new base64-encoded JWT string. + */ char * OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, const struct GNUNET_IDENTITY_PublicKey *sub_key, @@ -62,7 +73,7 @@ OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, const json_t *secret_rsa_key); /** - * Create a JWT from attributes + * Create a JWT using HMAC (HS256) from attributes * * @param aud_key the public of the audience * @param sub_key the public key of the subject @@ -73,14 +84,14 @@ OIDC_generate_id_token_rsa (const struct GNUNET_IDENTITY_PublicKey *aud_key, * @return a new base64-encoded JWT string. */ char* -OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, - const struct GNUNET_IDENTITY_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key); +OIDC_generate_id_token_hmac (const struct GNUNET_IDENTITY_PublicKey *aud_key, + const struct GNUNET_IDENTITY_PublicKey *sub_key, + const struct GNUNET_RECLAIM_AttributeList *attrs, + const struct + GNUNET_RECLAIM_PresentationList *presentations, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce, + const char *secret_key); /** * Builds an OIDC authorization code including diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 17b707e7e..f76ced0cc 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c @@ -1,4 +1,4 @@ -/* + This file is part of GNUnet. Copyright (C) 2012-2018 GNUnet e.V. @@ -20,6 +20,7 @@ /** * @author Martin Schanzenbach * @author Philippe Buschmann + * @author Tristan Schwieren * @file identity/plugin_rest_openid_connect.c * @brief GNUnet Namestore REST plugin * @@ -2289,7 +2290,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - // id_token = OIDC_generate_id_token (&ticket.audience, + // id_token = OIDC_generate_id_token_hmac (&ticket.audience, // &ticket.identity, // cl, // pl, -- cgit v1.2.3