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