diff options
author | Schanzenbach, Martin <mschanzenbach@posteo.de> | 2019-04-26 14:47:29 +0200 |
---|---|---|
committer | Schanzenbach, Martin <mschanzenbach@posteo.de> | 2019-04-26 14:47:29 +0200 |
commit | dba51d34726695de64bca656399ed8f82d225f53 (patch) | |
tree | ad64981fb7189fe0c12b3e6c7f7f819bfe4d700a | |
parent | b6d8d75ac3700abee64adb452b7e3652b75933c0 (diff) | |
download | gnunet-dba51d34726695de64bca656399ed8f82d225f53.tar.gz gnunet-dba51d34726695de64bca656399ed8f82d225f53.zip |
RECLAIM/REST: simplify auth code; include attrs
-rw-r--r-- | src/reclaim/oidc_helper.c | 311 | ||||
-rw-r--r-- | src/reclaim/oidc_helper.h | 8 | ||||
-rw-r--r-- | src/reclaim/plugin_rest_openid_connect.c | 49 |
3 files changed, 195 insertions, 173 deletions
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c index 331bd2711..37387b5e0 100644 --- a/src/reclaim/oidc_helper.c +++ b/src/reclaim/oidc_helper.c | |||
@@ -52,7 +52,8 @@ static void | |||
52 | replace_char (char *str, char find, char replace) | 52 | replace_char (char *str, char find, char replace) |
53 | { | 53 | { |
54 | char *current_pos = strchr (str, find); | 54 | char *current_pos = strchr (str, find); |
55 | while (current_pos) { | 55 | while (current_pos) |
56 | { | ||
56 | *current_pos = replace; | 57 | *current_pos = replace; |
57 | current_pos = strchr (current_pos, find); | 58 | current_pos = strchr (current_pos, find); |
58 | } | 59 | } |
@@ -84,7 +85,8 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
84 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | 85 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, |
85 | const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, | 86 | const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, |
86 | const struct GNUNET_TIME_Relative *expiration_time, | 87 | const struct GNUNET_TIME_Relative *expiration_time, |
87 | const char *nonce, const char *secret_key) | 88 | const char *nonce, |
89 | const char *secret_key) | ||
88 | { | 90 | { |
89 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; | 91 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; |
90 | struct GNUNET_HashCode signature; | 92 | struct GNUNET_HashCode signature; |
@@ -110,9 +112,11 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
110 | // nonce only if nonce | 112 | // nonce only if nonce |
111 | // OPTIONAL acr,amr,azp | 113 | // OPTIONAL acr,amr,azp |
112 | subject = GNUNET_STRINGS_data_to_string_alloc ( | 114 | subject = GNUNET_STRINGS_data_to_string_alloc ( |
113 | sub_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | 115 | sub_key, |
116 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
114 | audience = GNUNET_STRINGS_data_to_string_alloc ( | 117 | audience = GNUNET_STRINGS_data_to_string_alloc ( |
115 | aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | 118 | aud_key, |
119 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
116 | header = create_jwt_header (); | 120 | header = create_jwt_header (); |
117 | body = json_object (); | 121 | body = json_object (); |
118 | 122 | ||
@@ -125,21 +129,27 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
125 | // aud REQUIRED public key client_id must be there | 129 | // aud REQUIRED public key client_id must be there |
126 | json_object_set_new (body, "aud", json_string (audience)); | 130 | json_object_set_new (body, "aud", json_string (audience)); |
127 | // iat | 131 | // iat |
128 | json_object_set_new (body, "iat", | 132 | json_object_set_new (body, |
133 | "iat", | ||
129 | json_integer (time_now.abs_value_us / (1000 * 1000))); | 134 | json_integer (time_now.abs_value_us / (1000 * 1000))); |
130 | // exp | 135 | // exp |
131 | json_object_set_new (body, "exp", | 136 | json_object_set_new (body, |
137 | "exp", | ||
132 | json_integer (exp_time.abs_value_us / (1000 * 1000))); | 138 | json_integer (exp_time.abs_value_us / (1000 * 1000))); |
133 | // nbf | 139 | // nbf |
134 | json_object_set_new (body, "nbf", | 140 | json_object_set_new (body, |
141 | "nbf", | ||
135 | json_integer (time_now.abs_value_us / (1000 * 1000))); | 142 | json_integer (time_now.abs_value_us / (1000 * 1000))); |
136 | // nonce | 143 | // nonce |
137 | if (NULL != nonce) | 144 | if (NULL != nonce) |
138 | json_object_set_new (body, "nonce", json_string (nonce)); | 145 | json_object_set_new (body, "nonce", json_string (nonce)); |
139 | 146 | ||
140 | for (le = attrs->list_head; NULL != le; le = le->next) { | 147 | for (le = attrs->list_head; NULL != le; le = le->next) |
141 | attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string ( | 148 | { |
142 | le->claim->type, le->claim->data, le->claim->data_size); | 149 | attr_val_str = |
150 | GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, | ||
151 | le->claim->data, | ||
152 | le->claim->data_size); | ||
143 | json_object_set_new (body, le->claim->name, json_string (attr_val_str)); | 153 | json_object_set_new (body, le->claim->name, json_string (attr_val_str)); |
144 | GNUNET_free (attr_val_str); | 154 | GNUNET_free (attr_val_str); |
145 | } | 155 | } |
@@ -160,14 +170,20 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
160 | * standards compliant, check. | 170 | * standards compliant, check. |
161 | */ | 171 | */ |
162 | GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); | 172 | GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); |
163 | GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target, | 173 | GNUNET_CRYPTO_hmac_raw (secret_key, |
164 | strlen (signature_target), &signature); | 174 | strlen (secret_key), |
165 | GNUNET_STRINGS_base64_encode ((const char *)&signature, | 175 | signature_target, |
176 | strlen (signature_target), | ||
177 | &signature); | ||
178 | GNUNET_STRINGS_base64_encode ((const char *) &signature, | ||
166 | sizeof (struct GNUNET_HashCode), | 179 | sizeof (struct GNUNET_HashCode), |
167 | &signature_base64); | 180 | &signature_base64); |
168 | fix_base64 (signature_base64); | 181 | fix_base64 (signature_base64); |
169 | 182 | ||
170 | GNUNET_asprintf (&result, "%s.%s.%s", header_base64, body_base64, | 183 | GNUNET_asprintf (&result, |
184 | "%s.%s.%s", | ||
185 | header_base64, | ||
186 | body_base64, | ||
171 | signature_base64); | 187 | signature_base64); |
172 | 188 | ||
173 | GNUNET_free (signature_target); | 189 | GNUNET_free (signature_target); |
@@ -178,64 +194,125 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
178 | GNUNET_free (header_base64); | 194 | GNUNET_free (header_base64); |
179 | return result; | 195 | return result; |
180 | } | 196 | } |
197 | |||
198 | |||
199 | /** | ||
200 | * Returns base64 encoded string urlencoded | ||
201 | * | ||
202 | * @param string the string to encode | ||
203 | * @return base64 encoded string | ||
204 | */ | ||
205 | static char * | ||
206 | base64_encode (const char *data, | ||
207 | size_t data_size) | ||
208 | { | ||
209 | char *enc; | ||
210 | char *enc_urlencode; | ||
211 | char *tmp; | ||
212 | int i; | ||
213 | int num_pads = 0; | ||
214 | |||
215 | GNUNET_STRINGS_base64_encode (data, data_size, &enc); | ||
216 | tmp = strchr (enc, '='); | ||
217 | num_pads = strlen (enc) - (tmp - enc); | ||
218 | GNUNET_assert ((3 > num_pads) && (0 <= num_pads)); | ||
219 | if (0 == num_pads) | ||
220 | return enc; | ||
221 | enc_urlencode = GNUNET_malloc (strlen (enc) + num_pads * 2); | ||
222 | strcpy (enc_urlencode, enc); | ||
223 | GNUNET_free (enc); | ||
224 | tmp = strchr (enc_urlencode, '='); | ||
225 | for (i = 0; i < num_pads; i++) { | ||
226 | strcpy (tmp, "%3D"); // replace '=' with '%3D' | ||
227 | tmp += 3; | ||
228 | } | ||
229 | return enc_urlencode; | ||
230 | } | ||
231 | |||
232 | |||
233 | |||
234 | |||
181 | /** | 235 | /** |
182 | * Builds an OIDC authorization code including | 236 | * Builds an OIDC authorization code including |
183 | * a reclaim ticket and nonce | 237 | * a reclaim ticket and nonce |
184 | * | 238 | * |
185 | * @param issuer the issuer of the ticket, used to sign the ticket and nonce | 239 | * @param issuer the issuer of the ticket, used to sign the ticket and nonce |
186 | * @param ticket the ticket to include in the code | 240 | * @param ticket the ticket to include in the code |
241 | * @param attrs list of attributes whicha re shared | ||
187 | * @param nonce the nonce to include in the code | 242 | * @param nonce the nonce to include in the code |
188 | * @return a new authorization code (caller must free) | 243 | * @return a new authorization code (caller must free) |
189 | */ | 244 | */ |
190 | char * | 245 | char * |
191 | OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | 246 | OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, |
192 | const struct GNUNET_RECLAIM_Ticket *ticket, | 247 | const struct GNUNET_RECLAIM_Ticket *ticket, |
193 | const char *nonce) | 248 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, |
249 | const char *nonce_str) | ||
194 | { | 250 | { |
195 | char *ticket_str; | 251 | char *code_payload; |
196 | json_t *code_json; | 252 | char *attrs_ser; |
197 | char *signature_payload; | 253 | char *code_str; |
198 | char *signature_str; | 254 | char *buf_ptr; |
199 | char *authz_code; | ||
200 | size_t signature_payload_len; | 255 | size_t signature_payload_len; |
256 | size_t attr_list_len; | ||
257 | size_t code_payload_len; | ||
258 | unsigned int nonce; | ||
259 | unsigned int nonce_tmp; | ||
201 | struct GNUNET_CRYPTO_EcdsaSignature signature; | 260 | struct GNUNET_CRYPTO_EcdsaSignature signature; |
202 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | 261 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; |
203 | 262 | ||
204 | signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); | 263 | attrs_ser = NULL; |
205 | if (NULL != nonce) | 264 | signature_payload_len = |
206 | signature_payload_len += strlen (nonce); | 265 | sizeof (struct GNUNET_RECLAIM_Ticket) + sizeof (unsigned int); |
207 | 266 | if (NULL != attrs) | |
208 | signature_payload = | 267 | { |
209 | GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | 268 | attr_list_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs); |
210 | signature_payload_len); | 269 | signature_payload_len += attr_list_len; |
211 | purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload; | 270 | attrs_ser = GNUNET_malloc (attr_list_len); |
271 | GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, attrs_ser); | ||
272 | } | ||
273 | code_payload_len = sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | ||
274 | signature_payload_len + sizeof (signature); | ||
275 | code_payload = GNUNET_malloc (code_payload_len); | ||
276 | purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload; | ||
212 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | 277 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + |
213 | signature_payload_len); | 278 | signature_payload_len); |
214 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); | 279 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); |
215 | memcpy (&purpose[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket)); | 280 | // First, copy ticket |
216 | if (NULL != nonce) | 281 | buf_ptr = (char *) &purpose[1]; |
217 | memcpy (((char *)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket), | 282 | memcpy (buf_ptr, ticket, sizeof (struct GNUNET_RECLAIM_Ticket)); |
218 | nonce, strlen (nonce)); | 283 | buf_ptr += sizeof (struct GNUNET_RECLAIM_Ticket); |
219 | if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, purpose, &signature)) { | 284 | // Then copy nonce |
220 | GNUNET_free (signature_payload); | 285 | nonce = 0; |
286 | if (NULL != nonce_str) | ||
287 | { | ||
288 | if ((1 != SSCANF (nonce_str, "%u", &nonce)) || (nonce > UINT16_MAX)) | ||
289 | { | ||
290 | GNUNET_free (code_payload); | ||
291 | GNUNET_free_non_null (attrs_ser); | ||
292 | return NULL; | ||
293 | } | ||
294 | } | ||
295 | nonce_tmp = htons (nonce); | ||
296 | memcpy (buf_ptr, &nonce_tmp, sizeof (unsigned int)); | ||
297 | buf_ptr += sizeof (unsigned int); | ||
298 | // Finally, attributes | ||
299 | if (NULL != attrs_ser) | ||
300 | { | ||
301 | memcpy (buf_ptr, attrs_ser, attr_list_len); | ||
302 | buf_ptr += attr_list_len; | ||
303 | } | ||
304 | if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, purpose, &signature)) | ||
305 | { | ||
306 | GNUNET_free (code_payload); | ||
307 | GNUNET_free_non_null (attrs_ser); | ||
221 | return NULL; | 308 | return NULL; |
222 | } | 309 | } |
223 | signature_str = | 310 | memcpy (buf_ptr, &signature, sizeof (signature)); |
224 | GNUNET_STRINGS_data_to_string_alloc (&signature, sizeof (signature)); | 311 | code_str = base64_encode ((const char *) &code_payload, |
225 | ticket_str = GNUNET_STRINGS_data_to_string_alloc ( | 312 | code_payload_len); |
226 | ticket, sizeof (struct GNUNET_RECLAIM_Ticket)); | 313 | GNUNET_free (code_payload); |
227 | 314 | GNUNET_free_non_null (attrs_ser); | |
228 | code_json = json_object (); | 315 | return code_str; |
229 | json_object_set_new (code_json, "ticket", json_string (ticket_str)); | ||
230 | if (NULL != nonce) | ||
231 | json_object_set_new (code_json, "nonce", json_string (nonce)); | ||
232 | json_object_set_new (code_json, "signature", json_string (signature_str)); | ||
233 | authz_code = json_dumps (code_json, JSON_INDENT (0) | JSON_COMPACT); | ||
234 | GNUNET_free (signature_payload); | ||
235 | GNUNET_free (signature_str); | ||
236 | GNUNET_free (ticket_str); | ||
237 | json_decref (code_json); | ||
238 | return authz_code; | ||
239 | } | 316 | } |
240 | 317 | ||
241 | 318 | ||
@@ -247,99 +324,70 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | |||
247 | * @param audience the expected audience of the code | 324 | * @param audience the expected audience of the code |
248 | * @param code the string representation of the code | 325 | * @param code the string representation of the code |
249 | * @param ticket where to store the ticket | 326 | * @param ticket where to store the ticket |
327 | * @param attrs the attributes in the code | ||
250 | * @param nonce where to store the nonce | 328 | * @param nonce where to store the nonce |
251 | * @return GNUNET_OK if successful, else GNUNET_SYSERR | 329 | * @return GNUNET_OK if successful, else GNUNET_SYSERR |
252 | */ | 330 | */ |
253 | int | 331 | int |
254 | OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | 332 | OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, |
255 | const char *code, struct GNUNET_RECLAIM_Ticket **ticket, | 333 | const char *code, |
256 | char **nonce) | 334 | struct GNUNET_RECLAIM_Ticket *ticket, |
335 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs, | ||
336 | char **nonce_str) | ||
257 | { | 337 | { |
258 | json_error_t error; | 338 | char *code_payload; |
259 | json_t *code_json; | 339 | char *attrs_ser; |
260 | json_t *ticket_json; | 340 | char *ptr; |
261 | json_t *nonce_json; | ||
262 | json_t *signature_json; | ||
263 | const char *ticket_str; | ||
264 | const char *signature_str; | ||
265 | const char *nonce_str; | ||
266 | char *code_output; | ||
267 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | 341 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; |
268 | struct GNUNET_CRYPTO_EcdsaSignature signature; | 342 | struct GNUNET_CRYPTO_EcdsaSignature *signature; |
269 | size_t signature_payload_len; | 343 | size_t code_payload_len; |
270 | 344 | size_t attrs_ser_len; | |
271 | code_output = NULL; | 345 | size_t signature_offset; |
272 | GNUNET_STRINGS_base64_decode (code, strlen (code), (void **)&code_output); | 346 | unsigned int nonce; |
273 | code_json = json_loads (code_output, 0, &error); | 347 | |
274 | GNUNET_free (code_output); | 348 | code_payload = NULL; |
275 | ticket_json = json_object_get (code_json, "ticket"); | 349 | code_payload_len = |
276 | nonce_json = json_object_get (code_json, "nonce"); | 350 | GNUNET_STRINGS_base64_decode (code, strlen (code), (void **) &code_payload); |
277 | signature_json = json_object_get (code_json, "signature"); | 351 | purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload; |
278 | *ticket = NULL; | 352 | attrs_ser_len = code_payload_len; |
279 | *nonce = NULL; | 353 | attrs_ser_len -= sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose); |
280 | 354 | *ticket = *((struct GNUNET_RECLAIM_Ticket*) &purpose[1]); | |
281 | if ((NULL == ticket_json || !json_is_string (ticket_json)) || | 355 | attrs_ser_len -= sizeof (struct GNUNET_RECLAIM_Ticket); |
282 | (NULL == signature_json || !json_is_string (signature_json))) { | 356 | nonce = ntohs (((unsigned int *) &ticket[1])); |
283 | json_decref (code_json); | 357 | attrs_ser_len -= sizeof (unsigned int); |
284 | return GNUNET_SYSERR; | 358 | ptr = code_payload; |
285 | } | 359 | signature_offset = |
286 | ticket_str = json_string_value (ticket_json); | 360 | code_payload_len - sizeof (struct GNUNET_CRYPTO_EcdsaSignature); |
287 | signature_str = json_string_value (signature_json); | 361 | signature = (struct GNUNET_CRYPTO_EcdsaSignature *)&ptr[signature_offset]; |
288 | nonce_str = NULL; | 362 | attrs_ser_len -= sizeof (struct GNUNET_CRYPTO_EcdsaSignature); |
289 | if (NULL != nonce_json) | 363 | attrs_ser = ((char *) &ticket[1]) + sizeof (unsigned int); |
290 | nonce_str = json_string_value (nonce_json); | 364 | *attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attrs_ser, attrs_ser_len); |
291 | signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); | 365 | if (0 != GNUNET_memcmp (audience, &ticket->audience)) |
292 | if (NULL != nonce_str) | 366 | { |
293 | signature_payload_len += strlen (nonce_str); | 367 | GNUNET_RECLAIM_ATTRIBUTE_list_destroy (*attrs); |
294 | purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | 368 | GNUNET_free (code_payload); |
295 | signature_payload_len); | ||
296 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | ||
297 | signature_payload_len); | ||
298 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); | ||
299 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data ( | ||
300 | ticket_str, strlen (ticket_str), &purpose[1], | ||
301 | sizeof (struct GNUNET_RECLAIM_Ticket))) { | ||
302 | GNUNET_free (purpose); | ||
303 | json_decref (code_json); | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot parse ticket!\n"); | ||
305 | return GNUNET_SYSERR; | ||
306 | } | ||
307 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data ( | ||
308 | signature_str, strlen (signature_str), &signature, | ||
309 | sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) { | ||
310 | GNUNET_free (purpose); | ||
311 | json_decref (code_json); | ||
312 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot parse signature!\n"); | ||
313 | return GNUNET_SYSERR; | ||
314 | } | ||
315 | *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); | ||
316 | memcpy (*ticket, &purpose[1], sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
317 | if (0 != GNUNET_memcmp (audience, &(*ticket)->audience)) { | ||
318 | GNUNET_free (purpose); | ||
319 | GNUNET_free (*ticket); | ||
320 | json_decref (code_json); | ||
321 | *ticket = NULL; | ||
322 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 369 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
323 | "Audience in ticket does not match client!\n"); | 370 | "Audience in ticket does not match client!\n"); |
324 | return GNUNET_SYSERR; | 371 | return GNUNET_SYSERR; |
325 | } | 372 | } |
326 | if (NULL != nonce_str) | ||
327 | memcpy (((char *)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket), | ||
328 | nonce_str, strlen (nonce_str)); | ||
329 | if (GNUNET_OK != | 373 | if (GNUNET_OK != |
330 | GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, | 374 | GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, |
331 | purpose, &signature, &(*ticket)->identity)) { | 375 | purpose, |
332 | GNUNET_free (purpose); | 376 | signature, |
333 | GNUNET_free (*ticket); | 377 | &ticket->identity)) |
334 | json_decref (code_json); | 378 | { |
335 | *ticket = NULL; | 379 | GNUNET_RECLAIM_ATTRIBUTE_list_destroy (*attrs); |
336 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of authZ code invalid!\n"); | 380 | GNUNET_free (code_payload); |
381 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n"); | ||
337 | return GNUNET_SYSERR; | 382 | return GNUNET_SYSERR; |
338 | } | 383 | } |
339 | *nonce = GNUNET_strdup (nonce_str); | 384 | *nonce_str = NULL; |
385 | if (nonce != 0) | ||
386 | GNUNET_asprintf (nonce_str, "%u", nonce); | ||
340 | return GNUNET_OK; | 387 | return GNUNET_OK; |
341 | } | 388 | } |
342 | 389 | ||
390 | |||
343 | /** | 391 | /** |
344 | * Build a token response for a token request | 392 | * Build a token response for a token request |
345 | * TODO: Maybe we should add the scope here? | 393 | * TODO: Maybe we should add the scope here? |
@@ -350,7 +398,8 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | |||
350 | * @param token_response where to store the response | 398 | * @param token_response where to store the response |
351 | */ | 399 | */ |
352 | void | 400 | void |
353 | OIDC_build_token_response (const char *access_token, const char *id_token, | 401 | OIDC_build_token_response (const char *access_token, |
402 | const char *id_token, | ||
354 | const struct GNUNET_TIME_Relative *expiration_time, | 403 | const struct GNUNET_TIME_Relative *expiration_time, |
355 | char **token_response) | 404 | char **token_response) |
356 | { | 405 | { |
@@ -364,8 +413,9 @@ OIDC_build_token_response (const char *access_token, const char *id_token, | |||
364 | json_object_set_new (root_json, "access_token", json_string (access_token)); | 413 | json_object_set_new (root_json, "access_token", json_string (access_token)); |
365 | json_object_set_new (root_json, "token_type", json_string ("Bearer")); | 414 | json_object_set_new (root_json, "token_type", json_string ("Bearer")); |
366 | json_object_set_new ( | 415 | json_object_set_new ( |
367 | root_json, "expires_in", | 416 | root_json, |
368 | json_integer (expiration_time->rel_value_us / (1000 * 1000))); | 417 | "expires_in", |
418 | json_integer (expiration_time->rel_value_us / (1000 * 1000))); | ||
369 | json_object_set_new (root_json, "id_token", json_string (id_token)); | 419 | json_object_set_new (root_json, "id_token", json_string (id_token)); |
370 | *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT); | 420 | *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT); |
371 | json_decref (root_json); | 421 | json_decref (root_json); |
@@ -382,9 +432,10 @@ OIDC_access_token_new () | |||
382 | uint64_t random_number; | 432 | uint64_t random_number; |
383 | 433 | ||
384 | random_number = | 434 | random_number = |
385 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); | 435 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); |
386 | GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number); | 436 | GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number); |
387 | GNUNET_STRINGS_base64_encode (access_token_number, | 437 | GNUNET_STRINGS_base64_encode (access_token_number, |
388 | strlen (access_token_number), &access_token); | 438 | strlen (access_token_number), |
439 | &access_token); | ||
389 | return access_token; | 440 | return access_token; |
390 | } | 441 | } |
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h index d718b7a78..3c57dc235 100644 --- a/src/reclaim/oidc_helper.h +++ b/src/reclaim/oidc_helper.h | |||
@@ -11,7 +11,7 @@ | |||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Affero General Public License for more details. | 13 | Affero General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU Affero General Public License | 15 | You should have received a copy of the GNU Affero General Public License |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 | ||
@@ -62,12 +62,14 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
62 | * | 62 | * |
63 | * @param issuer the issuer of the ticket, used to sign the ticket and nonce | 63 | * @param issuer the issuer of the ticket, used to sign the ticket and nonce |
64 | * @param ticket the ticket to include in the code | 64 | * @param ticket the ticket to include in the code |
65 | * @param attrs list of attributes to share | ||
65 | * @param nonce the nonce to include in the code | 66 | * @param nonce the nonce to include in the code |
66 | * @return a new authorization code (caller must free) | 67 | * @return a new authorization code (caller must free) |
67 | */ | 68 | */ |
68 | char* | 69 | char* |
69 | OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | 70 | OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, |
70 | const struct GNUNET_RECLAIM_Ticket *ticket, | 71 | const struct GNUNET_RECLAIM_Ticket *ticket, |
72 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, | ||
71 | const char* nonce); | 73 | const char* nonce); |
72 | 74 | ||
73 | /** | 75 | /** |
@@ -78,13 +80,15 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | |||
78 | * @param audience the expected audience of the code | 80 | * @param audience the expected audience of the code |
79 | * @param code the string representation of the code | 81 | * @param code the string representation of the code |
80 | * @param ticket where to store the ticket | 82 | * @param ticket where to store the ticket |
83 | * @param attrs the attributes found in the code | ||
81 | * @param nonce where to store the nonce | 84 | * @param nonce where to store the nonce |
82 | * @return GNUNET_OK if successful, else GNUNET_SYSERR | 85 | * @return GNUNET_OK if successful, else GNUNET_SYSERR |
83 | */ | 86 | */ |
84 | int | 87 | int |
85 | OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | 88 | OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, |
86 | const char* code, | 89 | const char* code, |
87 | struct GNUNET_RECLAIM_Ticket **ticket, | 90 | struct GNUNET_RECLAIM_Ticket *ticket, |
91 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs, | ||
88 | char **nonce); | 92 | char **nonce); |
89 | 93 | ||
90 | /** | 94 | /** |
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 6cf1ffdee..07cb55d79 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c | |||
@@ -676,37 +676,6 @@ return_userinfo_response (void *cls) | |||
676 | cleanup_handle (handle); | 676 | cleanup_handle (handle); |
677 | } | 677 | } |
678 | 678 | ||
679 | /** | ||
680 | * Returns base64 encoded string urlencoded | ||
681 | * | ||
682 | * @param string the string to encode | ||
683 | * @return base64 encoded string | ||
684 | */ | ||
685 | static char * | ||
686 | base64_encode (const char *s) | ||
687 | { | ||
688 | char *enc; | ||
689 | char *enc_urlencode; | ||
690 | char *tmp; | ||
691 | int i; | ||
692 | int num_pads = 0; | ||
693 | |||
694 | GNUNET_STRINGS_base64_encode (s, strlen (s), &enc); | ||
695 | tmp = strchr (enc, '='); | ||
696 | num_pads = strlen (enc) - (tmp - enc); | ||
697 | GNUNET_assert ((3 > num_pads) && (0 <= num_pads)); | ||
698 | if (0 == num_pads) | ||
699 | return enc; | ||
700 | enc_urlencode = GNUNET_malloc (strlen (enc) + num_pads * 2); | ||
701 | strcpy (enc_urlencode, enc); | ||
702 | GNUNET_free (enc); | ||
703 | tmp = strchr (enc_urlencode, '='); | ||
704 | for (i = 0; i < num_pads; i++) { | ||
705 | strcpy (tmp, "%3D"); // replace '=' with '%3D' | ||
706 | tmp += 3; | ||
707 | } | ||
708 | return enc_urlencode; | ||
709 | } | ||
710 | 679 | ||
711 | /** | 680 | /** |
712 | * Respond to OPTIONS request | 681 | * Respond to OPTIONS request |
@@ -870,8 +839,7 @@ oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket) | |||
870 | struct MHD_Response *resp; | 839 | struct MHD_Response *resp; |
871 | char *ticket_str; | 840 | char *ticket_str; |
872 | char *redirect_uri; | 841 | char *redirect_uri; |
873 | char *code_json_string; | 842 | char *code_string; |
874 | char *code_base64_final_string; | ||
875 | 843 | ||
876 | handle->idp_op = NULL; | 844 | handle->idp_op = NULL; |
877 | handle->ticket = *ticket; | 845 | handle->ticket = *ticket; |
@@ -884,20 +852,20 @@ oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket) | |||
884 | ticket_str = GNUNET_STRINGS_data_to_string_alloc ( | 852 | ticket_str = GNUNET_STRINGS_data_to_string_alloc ( |
885 | &handle->ticket, sizeof (struct GNUNET_RECLAIM_Ticket)); | 853 | &handle->ticket, sizeof (struct GNUNET_RECLAIM_Ticket)); |
886 | // TODO change if more attributes are needed (see max_age) | 854 | // TODO change if more attributes are needed (see max_age) |
887 | code_json_string = OIDC_build_authz_code (&handle->priv_key, &handle->ticket, | 855 | code_string = OIDC_build_authz_code (&handle->priv_key, &handle->ticket, |
856 | handle->attr_list, | ||
888 | handle->oidc->nonce); | 857 | handle->oidc->nonce); |
889 | code_base64_final_string = base64_encode (code_json_string); | ||
890 | if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) && | 858 | if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) && |
891 | (NULL != handle->tld)) { | 859 | (NULL != handle->tld)) { |
892 | 860 | ||
893 | GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", | 861 | GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", |
894 | handle->redirect_prefix, handle->tld, | 862 | handle->redirect_prefix, handle->tld, |
895 | handle->redirect_suffix, handle->oidc->response_type, | 863 | handle->redirect_suffix, handle->oidc->response_type, |
896 | code_base64_final_string, handle->oidc->state); | 864 | code_string, handle->oidc->state); |
897 | } else { | 865 | } else { |
898 | GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s", | 866 | GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s", |
899 | handle->oidc->redirect_uri, handle->oidc->response_type, | 867 | handle->oidc->redirect_uri, handle->oidc->response_type, |
900 | code_base64_final_string, handle->oidc->state); | 868 | code_string, handle->oidc->state); |
901 | } | 869 | } |
902 | resp = GNUNET_REST_create_response (""); | 870 | resp = GNUNET_REST_create_response (""); |
903 | MHD_add_response_header (resp, "Location", redirect_uri); | 871 | MHD_add_response_header (resp, "Location", redirect_uri); |
@@ -905,8 +873,7 @@ oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket) | |||
905 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | 873 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); |
906 | GNUNET_free (redirect_uri); | 874 | GNUNET_free (redirect_uri); |
907 | GNUNET_free (ticket_str); | 875 | GNUNET_free (ticket_str); |
908 | GNUNET_free (code_json_string); | 876 | GNUNET_free (code_string); |
909 | GNUNET_free (code_base64_final_string); | ||
910 | } | 877 | } |
911 | 878 | ||
912 | static void | 879 | static void |
@@ -1653,7 +1620,8 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, const char *url, | |||
1653 | } | 1620 | } |
1654 | 1621 | ||
1655 | // decode code | 1622 | // decode code |
1656 | if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, &ticket, &nonce)) { | 1623 | ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); |
1624 | if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, ticket, &cl, &nonce)) { | ||
1657 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); | 1625 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); |
1658 | handle->edesc = GNUNET_strdup ("invalid code"); | 1626 | handle->edesc = GNUNET_strdup ("invalid code"); |
1659 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1627 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
@@ -1692,7 +1660,6 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, const char *url, | |||
1692 | return; | 1660 | return; |
1693 | } | 1661 | } |
1694 | // TODO We should collect the attributes here. cl always empty | 1662 | // TODO We should collect the attributes here. cl always empty |
1695 | cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); | ||
1696 | id_token = OIDC_id_token_new (&ticket->audience, &ticket->identity, cl, | 1663 | id_token = OIDC_id_token_new (&ticket->audience, &ticket->identity, cl, |
1697 | &expiration_time, | 1664 | &expiration_time, |
1698 | (NULL != nonce) ? nonce : NULL, jwt_secret); | 1665 | (NULL != nonce) ? nonce : NULL, jwt_secret); |