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