update
[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    * The reclaim ticket
45    */
46   struct GNUNET_RECLAIM_Ticket ticket;
47
48   /**
49    * The nonce
50    */
51   uint32_t nonce GNUNET_PACKED;
52
53   /**
54    * The length of the PKCE code_challenge
55    */
56   uint32_t code_challenge_len GNUNET_PACKED;
57
58   /**
59    * The length of the attributes list
60    */
61   uint32_t attr_list_len GNUNET_PACKED;
62 };
63
64 GNUNET_NETWORK_STRUCT_END
65
66 static char *
67 create_jwt_header(void)
68 {
69   json_t *root;
70   char *json_str;
71
72   root = json_object();
73   json_object_set_new(root, JWT_ALG, json_string(JWT_ALG_VALUE));
74   json_object_set_new(root, JWT_TYP, json_string(JWT_TYP_VALUE));
75
76   json_str = json_dumps(root, JSON_INDENT(0) | JSON_COMPACT);
77   json_decref(root);
78   return json_str;
79 }
80
81 static void
82 replace_char(char *str, char find, char replace)
83 {
84   char *current_pos = strchr(str, find);
85
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
244   return hex[code & 15];
245 }
246
247 /* Returns a url-encoded version of str */
248 /* IMPORTANT: be sure to free() the returned string after use */
249 static char *
250 url_encode(const char *str)
251 {
252   char *pstr = (char *)str;
253   char *buf = GNUNET_malloc(strlen(str) * 3 + 1);
254   char *pbuf = buf;
255
256   while (*pstr)
257     {
258       if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' ||
259           *pstr == '~')
260         *pbuf++ = *pstr;
261       else if (*pstr == ' ')
262         *pbuf++ = '+';
263       else
264         {
265           *pbuf++ = '%';
266           *pbuf++ = to_hex(*pstr >> 4);
267           *pbuf++ = to_hex(*pstr & 15);
268         }
269       pstr++;
270     }
271   *pbuf = '\0';
272   return buf;
273 }
274
275
276 /* Returns a url-decoded version of str */
277 /* IMPORTANT: be sure to free() the returned string after use */
278 static char *
279 url_decode(const char *str)
280 {
281   char *pstr = (char *)str;
282   char *buf = GNUNET_malloc(strlen(str) + 1);
283   char *pbuf = buf;
284
285   while (*pstr)
286     {
287       if (*pstr == '%')
288         {
289           if (pstr[1] && pstr[2])
290             {
291               *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
292               pstr += 2;
293             }
294         }
295       else if (*pstr == '+')
296         {
297           *pbuf++ = ' ';
298         }
299       else
300         {
301           *pbuf++ = *pstr;
302         }
303       pstr++;
304     }
305   *pbuf = '\0';
306   return buf;
307 }
308
309 /**
310  * Returns base64 encoded string urlencoded
311  *
312  * @param string the string to encode
313  * @return base64 encoded string
314  */
315 static char *
316 base64_and_urlencode(const char *data, size_t data_size)
317 {
318   char *enc;
319   char *urlenc;
320
321   GNUNET_STRINGS_base64_encode(data, data_size, &enc);
322   urlenc = url_encode(enc);
323   GNUNET_free(enc);
324   return urlenc;
325 }
326
327
328 /**
329  * Returns base64 encoded string urlencoded
330  *
331  * @param string the string to encode
332  * @return base64 encoded string
333  */
334 static char *
335 base64url_encode(const char *data, size_t data_size)
336 {
337   char *enc;
338   size_t pos;
339
340   GNUNET_STRINGS_base64_encode(data, data_size, &enc);
341   //Replace with correct characters for base64url
342   pos = 0;
343   while ('\0' != enc[pos])
344     {
345       if ('+' == enc[pos])
346         enc[pos] = '-';
347       if ('/' == enc[pos])
348         enc[pos] = '_';
349       if ('=' == enc[pos])
350         {
351           enc[pos] = '\0';
352           break;
353         }
354       pos++;
355     }
356   return enc;
357 }
358
359
360 static void
361 derive_aes_key(struct GNUNET_CRYPTO_SymmetricSessionKey *key,
362                struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
363                struct GNUNET_HashCode *key_material)
364 {
365   static const char ctx_key[] = "reclaim-aes-ctx-key";
366   static const char ctx_iv[] = "reclaim-aes-ctx-iv";
367
368   GNUNET_CRYPTO_kdf(key,
369                     sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
370                     ctx_key,
371                     strlen(ctx_key),
372                     key_material,
373                     sizeof(struct GNUNET_HashCode),
374                     NULL);
375   GNUNET_CRYPTO_kdf(iv,
376                     sizeof(
377                       struct GNUNET_CRYPTO_SymmetricInitializationVector),
378                     ctx_iv,
379                     strlen(ctx_iv),
380                     key_material,
381                     sizeof(struct GNUNET_HashCode),
382                     NULL);
383 }
384
385
386 static void
387 calculate_key_priv(struct GNUNET_CRYPTO_SymmetricSessionKey *key,
388                    struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
389                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
390                    const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub)
391 {
392   struct GNUNET_HashCode key_material;
393
394   GNUNET_CRYPTO_ecdsa_ecdh(ecdsa_priv, ecdh_pub, &key_material);
395   derive_aes_key(key, iv, &key_material);
396 }
397
398
399 static void
400 calculate_key_pub(struct GNUNET_CRYPTO_SymmetricSessionKey *key,
401                   struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
402                   const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
403                   const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv)
404 {
405   struct GNUNET_HashCode key_material;
406
407   GNUNET_CRYPTO_ecdh_ecdsa(ecdh_priv, ecdsa_pub, &key_material);
408   derive_aes_key(key, iv, &key_material);
409 }
410
411
412 static void
413 decrypt_payload(const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
414                 const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub,
415                 const char *ct,
416                 size_t ct_len,
417                 char *buf)
418 {
419   struct GNUNET_CRYPTO_SymmetricSessionKey key;
420   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
421
422   calculate_key_priv(&key, &iv, ecdsa_priv, ecdh_pub);
423   GNUNET_break(GNUNET_CRYPTO_symmetric_decrypt(ct, ct_len, &key, &iv, buf));
424 }
425
426
427 static void
428 encrypt_payload(const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
429                 const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv,
430                 const char *payload,
431                 size_t payload_len,
432                 char *buf)
433 {
434   struct GNUNET_CRYPTO_SymmetricSessionKey key;
435   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
436
437   calculate_key_pub(&key, &iv, ecdsa_pub, ecdh_priv);
438   GNUNET_break(
439     GNUNET_CRYPTO_symmetric_encrypt(payload, payload_len, &key, &iv, buf));
440 }
441
442 /**
443  * Builds an OIDC authorization code including
444  * a reclaim ticket and nonce
445  *
446  * @param issuer the issuer of the ticket, used to sign the ticket and nonce
447  * @param ticket the ticket to include in the code
448  * @param attrs list of attributes which are shared
449  * @param nonce the nonce to include in the code
450  * @param code_challenge PKCE code challenge
451  * @return a new authorization code (caller must free)
452  */
453 char *
454 OIDC_build_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
455                       const struct GNUNET_RECLAIM_Ticket *ticket,
456                       struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
457                       const char *nonce_str,
458                       const char *code_challenge)
459 {
460   struct OIDC_Parameters params;
461   char *code_payload;
462   char *payload;
463   char *tmp;
464   char *code_str;
465   char *buf_ptr = NULL;
466   size_t payload_len;
467   size_t code_payload_len;
468   size_t attr_list_len = 0;
469   size_t code_challenge_len = 0;
470   uint32_t nonce;
471   uint32_t nonce_tmp;
472   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
473   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv;
474   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pub;
475
476   /** PLAINTEXT **/
477   // Assign ticket
478   memset(&params, 0, sizeof(params));
479   params.ticket = *ticket;
480   // Assign nonce
481   nonce = 0;
482   payload_len = sizeof(struct OIDC_Parameters);
483   if (NULL != nonce_str && strcmp("", nonce_str) != 0)
484     {
485       if ((1 != sscanf(nonce_str, "%u", &nonce)) || (nonce > UINT32_MAX))
486         {
487           GNUNET_break(0);
488           GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Invalid nonce %s\n", nonce_str);
489           return NULL;
490         }
491       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
492                  "Got nonce: %u from %s\n",
493                  nonce,
494                  nonce_str);
495     }
496   nonce_tmp = htonl(nonce);
497   params.nonce = nonce_tmp;
498   // Assign code challenge
499   if (NULL != code_challenge)
500     code_challenge_len = strlen(code_challenge);
501   payload_len += code_challenge_len;
502   params.code_challenge_len = htonl(code_challenge_len);
503   // Assign attributes
504   if (NULL != attrs)
505     {
506       // Get length
507       attr_list_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size(attrs);
508       params.attr_list_len = htonl(attr_list_len);
509       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
510                  "Length of serialized attributes: %lu\n",
511                  attr_list_len);
512       // Get serialized attributes
513       payload_len += attr_list_len;
514     }
515   // Get plaintext length
516   payload = GNUNET_malloc(payload_len);
517   memcpy(payload, &params, sizeof(params));
518   tmp = payload + sizeof(params);
519   if (0 < code_challenge_len)
520     {
521       memcpy(tmp, code_challenge, code_challenge_len);
522       tmp += code_challenge_len;
523     }
524   if (0 < attr_list_len)
525     GNUNET_RECLAIM_ATTRIBUTE_list_serialize(attrs, tmp);
526   /** END **/
527
528   /** ENCRYPT **/
529   // Get length
530   code_payload_len = sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) +
531                      sizeof(struct GNUNET_CRYPTO_EcdhePublicKey) +
532                      payload_len + sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
533   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
534              "Length of data to encode: %lu\n",
535              code_payload_len);
536
537   // Generate ECDH key
538   ecdh_priv = GNUNET_CRYPTO_ecdhe_key_create();
539   GNUNET_CRYPTO_ecdhe_key_get_public(ecdh_priv, &ecdh_pub);
540   // Initialize code payload
541   code_payload = GNUNET_malloc(code_payload_len);
542   GNUNET_assert(NULL != code_payload);
543   purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)code_payload;
544   purpose->size = htonl(sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) +
545                         sizeof(ecdh_pub) + payload_len);
546   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
547   // Store pubkey
548   buf_ptr = (char *)&purpose[1];
549   memcpy(buf_ptr, &ecdh_pub, sizeof(ecdh_pub));
550   buf_ptr += sizeof(ecdh_pub);
551   // Encrypt plaintext and store
552   encrypt_payload(&ticket->audience, ecdh_priv, payload, payload_len, buf_ptr);
553   GNUNET_free(ecdh_priv);
554   GNUNET_free(payload);
555   buf_ptr += payload_len;
556   // Sign and store signature
557   if (GNUNET_SYSERR ==
558       GNUNET_CRYPTO_ecdsa_sign(issuer,
559                                purpose,
560                                (struct GNUNET_CRYPTO_EcdsaSignature *)
561                                buf_ptr))
562     {
563       GNUNET_break(0);
564       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n");
565       GNUNET_free(code_payload);
566       return NULL;
567     }
568   code_str = base64_and_urlencode(code_payload, code_payload_len);
569   GNUNET_free(code_payload);
570   return code_str;
571 }
572
573
574 /**
575  * Parse reclaim ticket and nonce from
576  * authorization code.
577  * This also verifies the signature in the code.
578  *
579  * @param audience the expected audience of the code
580  * @param code the string representation of the code
581  * @param code_verfier PKCE code verifier
582  * @param ticket where to store the ticket
583  * @param attrs the attributes in the code
584  * @param nonce where to store the nonce
585  * @return GNUNET_OK if successful, else GNUNET_SYSERR
586  */
587 int
588 OIDC_parse_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
589                       const char *code,
590                       const char *code_verifier,
591                       struct GNUNET_RECLAIM_Ticket *ticket,
592                       struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs,
593                       char **nonce_str)
594 {
595   char *code_payload;
596   char *ptr;
597   char *plaintext;
598   char *attrs_ser;
599   char *expected_code_challenge;
600   char *code_challenge;
601   char *code_verifier_hash;
602   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
603   struct GNUNET_CRYPTO_EcdsaSignature *signature;
604   struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_pub;
605   struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub;
606   uint32_t code_challenge_len;
607   uint32_t attrs_ser_len;
608   size_t plaintext_len;
609   size_t code_payload_len;
610   uint32_t nonce = 0;
611   struct OIDC_Parameters *params;
612
613   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
614   code_payload = NULL;
615   code_payload_len =
616     GNUNET_STRINGS_base64_decode(code, strlen(code), (void **)&code_payload);
617   if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) +
618       sizeof(struct GNUNET_CRYPTO_EcdhePublicKey) +
619       sizeof(struct OIDC_Parameters) +
620       sizeof(struct GNUNET_CRYPTO_EcdsaSignature))
621     {
622       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n");
623       GNUNET_free_non_null(code_payload);
624       return GNUNET_SYSERR;
625     }
626
627   purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)code_payload;
628   plaintext_len = code_payload_len;
629   plaintext_len -= sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose);
630   ptr = (char *)&purpose[1];
631   // Public ECDH key
632   ecdh_pub = (struct GNUNET_CRYPTO_EcdhePublicKey *)ptr;
633   ptr += sizeof(struct GNUNET_CRYPTO_EcdhePublicKey);
634   plaintext_len -= sizeof(struct GNUNET_CRYPTO_EcdhePublicKey);
635
636   // Decrypt ciphertext
637   plaintext_len -= sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
638   plaintext = GNUNET_malloc(plaintext_len);
639   decrypt_payload(ecdsa_priv, ecdh_pub, ptr, plaintext_len, plaintext);
640   //ptr = plaintext;
641   ptr += plaintext_len;
642   signature = (struct GNUNET_CRYPTO_EcdsaSignature *)ptr;
643   params = (struct OIDC_Parameters *)plaintext;
644
645   // cmp code_challenge code_verifier
646   code_challenge_len = ntohl(params->code_challenge_len);
647   if (0 != code_challenge_len) /* Only check if this code requires a CV */
648     {
649       code_verifier_hash = GNUNET_malloc(256 / 8);
650       // hash code verifier
651       gcry_md_hash_buffer(GCRY_MD_SHA256,
652                           code_verifier_hash,
653                           code_verifier,
654                           strlen(code_verifier));
655       // encode code verifier
656       expected_code_challenge = base64url_encode(code_verifier_hash, 256 / 8);
657       code_challenge = (char *)&params[1];
658       GNUNET_free(code_verifier_hash);
659       if ((strlen(expected_code_challenge) != code_challenge_len) ||
660           (0 !=
661            strncmp(expected_code_challenge, code_challenge, code_challenge_len)))
662         {
663           GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
664                      "Invalid code verifier! Expected: %s, Got: %.*s\n",
665                      expected_code_challenge,
666                      code_challenge_len,
667                      code_challenge);
668           GNUNET_free_non_null(code_payload);
669           GNUNET_free(expected_code_challenge);
670           return GNUNET_SYSERR;
671         }
672       GNUNET_free(expected_code_challenge);
673     }
674   // Ticket
675   memcpy(ticket, &params->ticket, sizeof(params->ticket));
676   // Nonce
677   nonce = ntohl(params->nonce);  //ntohl (*((uint32_t *) ptr));
678   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %u\n", nonce);
679   // Signature
680   GNUNET_CRYPTO_ecdsa_key_get_public(ecdsa_priv, &ecdsa_pub);
681   if (0 != GNUNET_memcmp(&ecdsa_pub, &ticket->audience))
682     {
683       GNUNET_free(code_payload);
684       GNUNET_free(plaintext);
685       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
686                  "Audience in ticket does not match client!\n");
687       return GNUNET_SYSERR;
688     }
689   if (GNUNET_OK !=
690       GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
691                                  purpose,
692                                  signature,
693                                  &ticket->identity))
694     {
695       GNUNET_free(code_payload);
696       GNUNET_free(plaintext);
697       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
698       return GNUNET_SYSERR;
699     }
700   // Attributes
701   attrs_ser = ((char *)&params[1]) + code_challenge_len;
702   attrs_ser_len = ntohl(params->attr_list_len);
703   *attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize(attrs_ser, attrs_ser_len);
704
705   *nonce_str = NULL;
706   if (nonce != 0)
707     GNUNET_asprintf(nonce_str, "%u", nonce);
708   GNUNET_free(code_payload);
709   GNUNET_free(plaintext);
710   return GNUNET_OK;
711 }
712
713
714 /**
715  * Build a token response for a token request
716  * TODO: Maybe we should add the scope here?
717  *
718  * @param access_token the access token to include
719  * @param id_token the id_token to include
720  * @param expiration_time the expiration time of the token(s)
721  * @param token_response where to store the response
722  */
723 void
724 OIDC_build_token_response(const char *access_token,
725                           const char *id_token,
726                           const struct GNUNET_TIME_Relative *expiration_time,
727                           char **token_response)
728 {
729   json_t *root_json;
730
731   root_json = json_object();
732
733   GNUNET_assert(NULL != access_token);
734   GNUNET_assert(NULL != id_token);
735   GNUNET_assert(NULL != expiration_time);
736   json_object_set_new(root_json, "access_token", json_string(access_token));
737   json_object_set_new(root_json, "token_type", json_string("Bearer"));
738   json_object_set_new(root_json,
739                       "expires_in",
740                       json_integer(expiration_time->rel_value_us /
741                                    (1000 * 1000)));
742   json_object_set_new(root_json, "id_token", json_string(id_token));
743   *token_response = json_dumps(root_json, JSON_INDENT(0) | JSON_COMPACT);
744   json_decref(root_json);
745 }
746
747 /**
748  * Generate a new access token
749  */
750 char *
751 OIDC_access_token_new()
752 {
753   char *access_token;
754   uint64_t random_number;
755
756   random_number =
757     GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
758   GNUNET_STRINGS_base64_encode(&random_number,
759                                sizeof(uint64_t),
760                                &access_token);
761   return access_token;
762 }