add changelog
[oweals/gnunet.git] / src / reclaim / oidc_helper.c
1 /*
2    This file is part of GNUnet
3    Copyright (C) 2010-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Affero General Public License for more details.
14
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/>.
17
18    SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file reclaim/oidc_helper.c
23  * @brief helper library for OIDC related functions
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include <inttypes.h>
28 #include <jansson.h>
29 #include "gnunet_util_lib.h"
30 #include "gnunet_reclaim_attribute_lib.h"
31 #include "gnunet_reclaim_service.h"
32 #include "gnunet_signatures.h"
33 #include "oidc_helper.h"
34 // #include "benchmark.h"
35 #include <gcrypt.h>
36
37 GNUNET_NETWORK_STRUCT_BEGIN
38
39 /**
40  * The signature used to generate the authorization code
41  */
42 struct OIDC_Parameters
43 {
44   /**
45    * The reclaim ticket
46    */
47   struct GNUNET_RECLAIM_Ticket ticket;
48
49   /**
50    * The nonce
51    */
52   uint32_t nonce GNUNET_PACKED;
53
54   /**
55    * The length of the PKCE code_challenge
56    */
57   uint32_t code_challenge_len GNUNET_PACKED;
58
59   /**
60    * The length of the attributes list
61    */
62   uint32_t attr_list_len GNUNET_PACKED;
63 };
64
65 GNUNET_NETWORK_STRUCT_END
66
67 static char *
68 create_jwt_header (void)
69 {
70   json_t *root;
71   char *json_str;
72
73   root = json_object ();
74   json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
75   json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
76
77   json_str = json_dumps (root, JSON_INDENT (0) | JSON_COMPACT);
78   json_decref (root);
79   return json_str;
80 }
81
82
83 static void
84 replace_char (char *str, char find, char replace)
85 {
86   char *current_pos = strchr (str, find);
87
88   while (current_pos)
89   {
90     *current_pos = replace;
91     current_pos = strchr (current_pos, find);
92   }
93 }
94
95
96 // RFC4648
97 static void
98 fix_base64 (char *str)
99 {
100   // Replace + with -
101   replace_char (str, '+', '-');
102
103   // Replace / with _
104   replace_char (str, '/', '_');
105 }
106
107
108 /**
109  * Create a JWT from attributes
110  *
111  * @param aud_key the public of the audience
112  * @param sub_key the public key of the subject
113  * @param attrs the attribute list
114  * @param expiration_time the validity of the token
115  * @param secret_key the key used to sign the JWT
116  * @return a new base64-encoded JWT string.
117  */
118 char *
119 OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
120                    const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
121                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
122                    const struct GNUNET_TIME_Relative *expiration_time,
123                    const char *nonce,
124                    const char *secret_key)
125 {
126   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
127   struct GNUNET_HashCode signature;
128   struct GNUNET_TIME_Absolute exp_time;
129   struct GNUNET_TIME_Absolute time_now;
130   char *audience;
131   char *subject;
132   char *header;
133   char *body_str;
134   char *result;
135   char *header_base64;
136   char *body_base64;
137   char *signature_target;
138   char *signature_base64;
139   char *attr_val_str;
140   json_t *body;
141
142   // iat REQUIRED time now
143   time_now = GNUNET_TIME_absolute_get ();
144   // exp REQUIRED time expired from config
145   exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time);
146   // auth_time only if max_age
147   // nonce only if nonce
148   // OPTIONAL acr,amr,azp
149   subject =
150     GNUNET_STRINGS_data_to_string_alloc (sub_key,
151                                          sizeof(struct
152                                                 GNUNET_CRYPTO_EcdsaPublicKey));
153   audience =
154     GNUNET_STRINGS_data_to_string_alloc (aud_key,
155                                          sizeof(struct
156                                                 GNUNET_CRYPTO_EcdsaPublicKey));
157   header = create_jwt_header ();
158   body = json_object ();
159
160   // iss REQUIRED case sensitive server uri with https
161   // The issuer is the local reclaim instance (e.g.
162   // https://reclaim.id/api/openid)
163   json_object_set_new (body, "iss", json_string (SERVER_ADDRESS));
164   // sub REQUIRED public key identity, not exceed 255 ASCII  length
165   json_object_set_new (body, "sub", json_string (subject));
166   // aud REQUIRED public key client_id must be there
167   json_object_set_new (body, "aud", json_string (audience));
168   // iat
169   json_object_set_new (body,
170                        "iat",
171                        json_integer (time_now.abs_value_us / (1000 * 1000)));
172   // exp
173   json_object_set_new (body,
174                        "exp",
175                        json_integer (exp_time.abs_value_us / (1000 * 1000)));
176   // nbf
177   json_object_set_new (body,
178                        "nbf",
179                        json_integer (time_now.abs_value_us / (1000 * 1000)));
180   // nonce
181   if (NULL != nonce)
182     json_object_set_new (body, "nonce", json_string (nonce));
183
184   for (le = attrs->list_head; NULL != le; le = le->next)
185   {
186     attr_val_str =
187       GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type,
188                                                 le->claim->data,
189                                                 le->claim->data_size);
190     json_object_set_new (body, le->claim->name, json_string (attr_val_str));
191     GNUNET_free (attr_val_str);
192   }
193   body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
194   json_decref (body);
195
196   GNUNET_STRINGS_base64_encode (header, strlen (header), &header_base64);
197   fix_base64 (header_base64);
198
199   GNUNET_STRINGS_base64_encode (body_str, strlen (body_str), &body_base64);
200   fix_base64 (body_base64);
201
202   GNUNET_free (subject);
203   GNUNET_free (audience);
204
205   /**
206    * Creating the JWT signature. This might not be
207    * standards compliant, check.
208    */
209   GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64);
210   GNUNET_CRYPTO_hmac_raw (secret_key,
211                           strlen (secret_key),
212                           signature_target,
213                           strlen (signature_target),
214                           &signature);
215   GNUNET_STRINGS_base64_encode ((const char *) &signature,
216                                 sizeof(struct GNUNET_HashCode),
217                                 &signature_base64);
218   fix_base64 (signature_base64);
219
220   GNUNET_asprintf (&result,
221                    "%s.%s.%s",
222                    header_base64,
223                    body_base64,
224                    signature_base64);
225
226   GNUNET_free (signature_target);
227   GNUNET_free (header);
228   GNUNET_free (body_str);
229   GNUNET_free (signature_base64);
230   GNUNET_free (body_base64);
231   GNUNET_free (header_base64);
232   return result;
233 }
234
235
236 /* Converts a hex character to its integer value */
237 static char
238 from_hex (char ch)
239 {
240   return isdigit (ch) ? ch - '0' : tolower (ch) - 'a' + 10;
241 }
242
243
244 /* Converts an integer value to its hex character*/
245 static char
246 to_hex (char code)
247 {
248   static char hex[] = "0123456789abcdef";
249
250   return hex[code & 15];
251 }
252
253
254 /* Returns a url-encoded version of str */
255 /* IMPORTANT: be sure to free() the returned string after use */
256 static char *
257 url_encode (const char *str)
258 {
259   char *pstr = (char *) str;
260   char *buf = GNUNET_malloc (strlen (str) * 3 + 1);
261   char *pbuf = buf;
262
263   while (*pstr)
264   {
265     if (isalnum (*pstr) || (*pstr == '-') || (*pstr == '_') || (*pstr == '.') ||
266         (*pstr == '~') )
267       *pbuf++ = *pstr;
268     else if (*pstr == ' ')
269       *pbuf++ = '+';
270     else
271     {
272       *pbuf++ = '%';
273       *pbuf++ = to_hex (*pstr >> 4);
274       *pbuf++ = to_hex (*pstr & 15);
275     }
276     pstr++;
277   }
278   *pbuf = '\0';
279   return buf;
280 }
281
282
283 /* Returns a url-decoded version of str */
284 /* IMPORTANT: be sure to free() the returned string after use */
285 static char *
286 url_decode (const char *str)
287 {
288   char *pstr = (char *) str;
289   char *buf = GNUNET_malloc (strlen (str) + 1);
290   char *pbuf = buf;
291
292   while (*pstr)
293   {
294     if (*pstr == '%')
295     {
296       if (pstr[1] && pstr[2])
297       {
298         *pbuf++ = from_hex (pstr[1]) << 4 | from_hex (pstr[2]);
299         pstr += 2;
300       }
301     }
302     else if (*pstr == '+')
303     {
304       *pbuf++ = ' ';
305     }
306     else
307     {
308       *pbuf++ = *pstr;
309     }
310     pstr++;
311   }
312   *pbuf = '\0';
313   return buf;
314 }
315
316
317 /**
318  * Returns base64 encoded string urlencoded
319  *
320  * @param string the string to encode
321  * @return base64 encoded string
322  */
323 static char *
324 base64_and_urlencode (const char *data, size_t data_size)
325 {
326   char *enc;
327   char *urlenc;
328
329   GNUNET_STRINGS_base64_encode (data, data_size, &enc);
330   urlenc = url_encode (enc);
331   GNUNET_free (enc);
332   return urlenc;
333 }
334
335
336 /**
337  * Returns base64 encoded string urlencoded
338  *
339  * @param string the string to encode
340  * @return base64 encoded string
341  */
342 static char *
343 base64url_encode (const char *data, size_t data_size)
344 {
345   char *enc;
346   size_t pos;
347
348   GNUNET_STRINGS_base64_encode (data, data_size, &enc);
349   // Replace with correct characters for base64url
350   pos = 0;
351   while ('\0' != enc[pos])
352   {
353     if ('+' == enc[pos])
354       enc[pos] = '-';
355     if ('/' == enc[pos])
356       enc[pos] = '_';
357     if ('=' == enc[pos])
358     {
359       enc[pos] = '\0';
360       break;
361     }
362     pos++;
363   }
364   return enc;
365 }
366
367
368 static void
369 derive_aes_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
370                 struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
371                 struct GNUNET_HashCode *key_material)
372 {
373   static const char ctx_key[] = "reclaim-aes-ctx-key";
374   static const char ctx_iv[] = "reclaim-aes-ctx-iv";
375
376   GNUNET_CRYPTO_kdf (key,
377                      sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
378                      ctx_key,
379                      strlen (ctx_key),
380                      key_material,
381                      sizeof(struct GNUNET_HashCode),
382                      NULL);
383   GNUNET_CRYPTO_kdf (iv,
384                      sizeof(
385                        struct GNUNET_CRYPTO_SymmetricInitializationVector),
386                      ctx_iv,
387                      strlen (ctx_iv),
388                      key_material,
389                      sizeof(struct GNUNET_HashCode),
390                      NULL);
391 }
392
393
394 static void
395 calculate_key_priv (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
396                     struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
397                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
398                     const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub)
399 {
400   struct GNUNET_HashCode key_material;
401
402   GNUNET_CRYPTO_ecdsa_ecdh (ecdsa_priv, ecdh_pub, &key_material);
403   derive_aes_key (key, iv, &key_material);
404 }
405
406
407 static void
408 calculate_key_pub (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
409                    struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
410                    const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
411                    const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv)
412 {
413   struct GNUNET_HashCode key_material;
414
415   GNUNET_CRYPTO_ecdh_ecdsa (ecdh_priv, ecdsa_pub, &key_material);
416   derive_aes_key (key, iv, &key_material);
417 }
418
419
420 static void
421 decrypt_payload (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
422                  const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub,
423                  const char *ct,
424                  size_t ct_len,
425                  char *buf)
426 {
427   struct GNUNET_CRYPTO_SymmetricSessionKey key;
428   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
429
430   calculate_key_priv (&key, &iv, ecdsa_priv, ecdh_pub);
431   GNUNET_break (GNUNET_CRYPTO_symmetric_decrypt (ct, ct_len, &key, &iv, buf));
432 }
433
434
435 static void
436 encrypt_payload (const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
437                  const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv,
438                  const char *payload,
439                  size_t payload_len,
440                  char *buf)
441 {
442   struct GNUNET_CRYPTO_SymmetricSessionKey key;
443   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
444
445   calculate_key_pub (&key, &iv, ecdsa_pub, ecdh_priv);
446   GNUNET_break (
447     GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len, &key, &iv, buf));
448 }
449
450
451 /**
452  * Builds an OIDC authorization code including
453  * a reclaim ticket and nonce
454  *
455  * @param issuer the issuer of the ticket, used to sign the ticket and nonce
456  * @param ticket the ticket to include in the code
457  * @param attrs list of attributes which are shared
458  * @param nonce the nonce to include in the code
459  * @param code_challenge PKCE code challenge
460  * @return a new authorization code (caller must free)
461  */
462 char *
463 OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
464                        const struct GNUNET_RECLAIM_Ticket *ticket,
465                        struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
466                        const char *nonce_str,
467                        const char *code_challenge)
468 {
469   struct OIDC_Parameters params;
470   char *code_payload;
471   char *payload;
472   char *tmp;
473   char *code_str;
474   char *buf_ptr = NULL;
475   size_t payload_len;
476   size_t code_payload_len;
477   size_t attr_list_len = 0;
478   size_t code_challenge_len = 0;
479   uint32_t nonce;
480   uint32_t nonce_tmp;
481   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
482   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv;
483   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pub;
484
485   /** PLAINTEXT **/
486   // Assign ticket
487   memset (&params, 0, sizeof(params));
488   params.ticket = *ticket;
489   // Assign nonce
490   nonce = 0;
491   payload_len = sizeof(struct OIDC_Parameters);
492   if ((NULL != nonce_str) && (strcmp ("", nonce_str) != 0))
493   {
494     if ((1 != sscanf (nonce_str, "%u", &nonce)) || (nonce > UINT32_MAX))
495     {
496       GNUNET_break (0);
497       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid nonce %s\n", nonce_str);
498       return NULL;
499     }
500     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501                 "Got nonce: %u from %s\n",
502                 nonce,
503                 nonce_str);
504   }
505   nonce_tmp = htonl (nonce);
506   params.nonce = nonce_tmp;
507   // Assign code challenge
508   if (NULL != code_challenge)
509     code_challenge_len = strlen (code_challenge);
510   payload_len += code_challenge_len;
511   params.code_challenge_len = htonl (code_challenge_len);
512   // Assign attributes
513   if (NULL != attrs)
514   {
515     // Get length
516     attr_list_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
517     params.attr_list_len = htonl (attr_list_len);
518     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519                 "Length of serialized attributes: %lu\n",
520                 attr_list_len);
521     // Get serialized attributes
522     payload_len += attr_list_len;
523   }
524   // Get plaintext length
525   payload = GNUNET_malloc (payload_len);
526   memcpy (payload, &params, sizeof(params));
527   tmp = payload + sizeof(params);
528   if (0 < code_challenge_len)
529   {
530     memcpy (tmp, code_challenge, code_challenge_len);
531     tmp += code_challenge_len;
532   }
533   if (0 < attr_list_len)
534     GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, tmp);
535   /** END **/
536
537   /** ENCRYPT **/
538   // Get length
539   code_payload_len = sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
540                      + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)
541                      + payload_len + sizeof(struct
542                                             GNUNET_CRYPTO_EcdsaSignature);
543   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544               "Length of data to encode: %lu\n",
545               code_payload_len);
546
547   // Generate ECDH key
548   ecdh_priv = GNUNET_CRYPTO_ecdhe_key_create ();
549   GNUNET_CRYPTO_ecdhe_key_get_public (ecdh_priv, &ecdh_pub);
550   // Initialize code payload
551   code_payload = GNUNET_malloc (code_payload_len);
552   GNUNET_assert (NULL != code_payload);
553   purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
554   purpose->size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
555                          + sizeof(ecdh_pub) + payload_len);
556   purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
557   // Store pubkey
558   buf_ptr = (char *) &purpose[1];
559   memcpy (buf_ptr, &ecdh_pub, sizeof(ecdh_pub));
560   buf_ptr += sizeof(ecdh_pub);
561   // Encrypt plaintext and store
562   encrypt_payload (&ticket->audience, ecdh_priv, payload, payload_len, buf_ptr);
563   GNUNET_free (ecdh_priv);
564   GNUNET_free (payload);
565   buf_ptr += payload_len;
566   // Sign and store signature
567   if (GNUNET_SYSERR ==
568       GNUNET_CRYPTO_ecdsa_sign (issuer,
569                                 purpose,
570                                 (struct GNUNET_CRYPTO_EcdsaSignature *)
571                                 buf_ptr))
572   {
573     GNUNET_break (0);
574     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n");
575     GNUNET_free (code_payload);
576     return NULL;
577   }
578   code_str = base64_and_urlencode (code_payload, code_payload_len);
579   GNUNET_free (code_payload);
580   return code_str;
581 }
582
583
584 /**
585  * Parse reclaim ticket and nonce from
586  * authorization code.
587  * This also verifies the signature in the code.
588  *
589  * @param audience the expected audience of the code
590  * @param code the string representation of the code
591  * @param code_verfier PKCE code verifier
592  * @param ticket where to store the ticket
593  * @param attrs the attributes in the code
594  * @param nonce where to store the nonce
595  * @return GNUNET_OK if successful, else GNUNET_SYSERR
596  */
597 int
598 OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
599                        const char *code,
600                        const char *code_verifier,
601                        struct GNUNET_RECLAIM_Ticket *ticket,
602                        struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs,
603                        char **nonce_str)
604 {
605   char *code_payload;
606   char *ptr;
607   char *plaintext;
608   char *attrs_ser;
609   char *expected_code_challenge;
610   char *code_challenge;
611   char *code_verifier_hash;
612   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
613   struct GNUNET_CRYPTO_EcdsaSignature *signature;
614   struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_pub;
615   struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub;
616   uint32_t code_challenge_len;
617   uint32_t attrs_ser_len;
618   size_t plaintext_len;
619   size_t code_payload_len;
620   uint32_t nonce = 0;
621   struct OIDC_Parameters *params;
622
623   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
624   code_payload = NULL;
625   code_payload_len =
626     GNUNET_STRINGS_base64_decode (code, strlen (code), (void **) &code_payload);
627   if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
628       + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)
629       + sizeof(struct OIDC_Parameters)
630       + sizeof(struct GNUNET_CRYPTO_EcdsaSignature))
631   {
632     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n");
633     GNUNET_free_non_null (code_payload);
634     return GNUNET_SYSERR;
635   }
636
637   purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
638   plaintext_len = code_payload_len;
639   plaintext_len -= sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose);
640   ptr = (char *) &purpose[1];
641   // Public ECDH key
642   ecdh_pub = (struct GNUNET_CRYPTO_EcdhePublicKey *) ptr;
643   ptr += sizeof(struct GNUNET_CRYPTO_EcdhePublicKey);
644   plaintext_len -= sizeof(struct GNUNET_CRYPTO_EcdhePublicKey);
645
646   // Decrypt ciphertext
647   plaintext_len -= sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
648   plaintext = GNUNET_malloc (plaintext_len);
649   decrypt_payload (ecdsa_priv, ecdh_pub, ptr, plaintext_len, plaintext);
650   // ptr = plaintext;
651   ptr += plaintext_len;
652   signature = (struct GNUNET_CRYPTO_EcdsaSignature *) ptr;
653   params = (struct OIDC_Parameters *) plaintext;
654
655   // cmp code_challenge code_verifier
656   code_challenge_len = ntohl (params->code_challenge_len);
657   if (0 != code_challenge_len) /* Only check if this code requires a CV */
658   {
659     if (NULL == code_verifier)
660     {
661       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
662                   "Expected code verifier!\n");
663       GNUNET_free_non_null (code_payload);
664       return GNUNET_SYSERR;
665     }
666     code_verifier_hash = GNUNET_malloc (256 / 8);
667     // hash code verifier
668     gcry_md_hash_buffer (GCRY_MD_SHA256,
669                          code_verifier_hash,
670                          code_verifier,
671                          strlen (code_verifier));
672     // encode code verifier
673     expected_code_challenge = base64url_encode (code_verifier_hash, 256 / 8);
674     code_challenge = (char *) &params[1];
675     GNUNET_free (code_verifier_hash);
676     if ((strlen (expected_code_challenge) != code_challenge_len) ||
677         (0 !=
678          strncmp (expected_code_challenge, code_challenge, code_challenge_len)))
679     {
680       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
681                   "Invalid code verifier! Expected: %s, Got: %.*s\n",
682                   expected_code_challenge,
683                   code_challenge_len,
684                   code_challenge);
685       GNUNET_free_non_null (code_payload);
686       GNUNET_free (expected_code_challenge);
687       return GNUNET_SYSERR;
688     }
689     GNUNET_free (expected_code_challenge);
690   }
691   // Ticket
692   memcpy (ticket, &params->ticket, sizeof(params->ticket));
693   // Nonce
694   nonce = ntohl (params->nonce);  // ntohl (*((uint32_t *) ptr));
695   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %u\n", nonce);
696   // Signature
697   GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub);
698   if (0 != GNUNET_memcmp (&ecdsa_pub, &ticket->audience))
699   {
700     GNUNET_free (code_payload);
701     GNUNET_free (plaintext);
702     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703                 "Audience in ticket does not match client!\n");
704     return GNUNET_SYSERR;
705   }
706   if (GNUNET_OK !=
707       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
708                                   purpose,
709                                   signature,
710                                   &ticket->identity))
711   {
712     GNUNET_free (code_payload);
713     GNUNET_free (plaintext);
714     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
715     return GNUNET_SYSERR;
716   }
717   // Attributes
718   attrs_ser = ((char *) &params[1]) + code_challenge_len;
719   attrs_ser_len = ntohl (params->attr_list_len);
720   *attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attrs_ser, attrs_ser_len);
721
722   *nonce_str = NULL;
723   if (nonce != 0)
724     GNUNET_asprintf (nonce_str, "%u", nonce);
725   GNUNET_free (code_payload);
726   GNUNET_free (plaintext);
727   return GNUNET_OK;
728 }
729
730
731 /**
732  * Build a token response for a token request
733  * TODO: Maybe we should add the scope here?
734  *
735  * @param access_token the access token to include
736  * @param id_token the id_token to include
737  * @param expiration_time the expiration time of the token(s)
738  * @param token_response where to store the response
739  */
740 void
741 OIDC_build_token_response (const char *access_token,
742                            const char *id_token,
743                            const struct GNUNET_TIME_Relative *expiration_time,
744                            char **token_response)
745 {
746   json_t *root_json;
747
748   root_json = json_object ();
749
750   GNUNET_assert (NULL != access_token);
751   GNUNET_assert (NULL != id_token);
752   GNUNET_assert (NULL != expiration_time);
753   json_object_set_new (root_json, "access_token", json_string (access_token));
754   json_object_set_new (root_json, "token_type", json_string ("Bearer"));
755   json_object_set_new (root_json,
756                        "expires_in",
757                        json_integer (expiration_time->rel_value_us
758                                      / (1000 * 1000)));
759   json_object_set_new (root_json, "id_token", json_string (id_token));
760   *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT);
761   json_decref (root_json);
762 }
763
764
765 /**
766  * Generate a new access token
767  */
768 char *
769 OIDC_access_token_new ()
770 {
771   char *access_token;
772   uint64_t random_number;
773
774   random_number =
775     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
776   GNUNET_STRINGS_base64_encode (&random_number,
777                                 sizeof(uint64_t),
778                                 &access_token);
779   return access_token;
780 }