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