-fix makefile
[oweals/gnunet.git] / src / identity-provider / jwt.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
6       it under the terms of the GNU General Public License as published
7       by the Free Software Foundation; either version 3, or (at your
8       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       General Public License for more details.
14
15       You should have received a copy of the GNU General Public License
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18       Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file identity-provider/jwt.c
23  * @brief helper library for JSON-Web-Tokens
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_signatures.h"
29 #include "identity_attribute.h"
30 #include <jansson.h>
31
32
33 #define JWT_ALG "alg"
34
35 /*TODO is this the correct way to define new algs? */
36 #define JWT_ALG_VALUE "ED512"
37
38 #define JWT_TYP "typ"
39
40 #define JWT_TYP_VALUE "jwt"
41
42 static char*
43 create_jwt_header(void)
44 {
45   json_t *root;
46   char *json_str;
47
48   root = json_object ();
49   json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
50   json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
51
52   json_str = json_dumps (root, JSON_INDENT(1));
53   json_decref (root);
54   return json_str;
55 }
56
57 /**
58  * Create a JWT from a ticket and attributes
59  *
60  * @param ticket the ticket
61  * @param attrs the attribute list
62  * @return a new base64-encoded JWT string.
63  */
64 char*
65 jwt_create (const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
66             const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs,
67             const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key)
68 {
69   struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le;
70   struct GNUNET_CRYPTO_EcdsaSignature signature;
71   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
72   char* audience;
73   char* issuer;
74   char* header;
75   char* padding;
76   char* body_str;
77   char* result;
78   char* header_base64;
79   char* body_base64;
80   char* signature_target;
81   char* signature_base64;
82   json_t* body;
83
84   /* TODO maybe we should use a local identity here */
85   issuer = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
86                                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
87   audience = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
88                                                   sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
89   header = create_jwt_header ();
90   body = json_object ();
91   /* TODO who is the issuer? local IdP or subject ? See self-issued tokens? */
92   json_object_set_new (body,
93                        "iss", json_string (issuer));
94   json_object_set_new (body,
95                        "sub", json_string (issuer));
96   /* TODO what should be in here exactly? */
97   json_object_set_new (body,
98                        "aud", json_string (audience));
99   for (le = attrs->list_head; NULL != le; le = le->next)
100   {
101     /**
102      * TODO here we should have a function that
103      * calls the Attribute plugins to create a
104      * json representation for its value
105      */
106     json_object_set_new (body,
107                          le->attribute->name,
108                          json_string (le->attribute->data));
109   }
110   body_str = json_dumps (body, JSON_INDENT(0));
111   json_decref (body);
112
113   GNUNET_STRINGS_base64_encode (header,
114                                 strlen (header),
115                                 &header_base64);
116   //Remove GNUNET padding of base64
117   padding = strtok(header_base64, "=");
118   while (NULL != padding)
119     padding = strtok(NULL, "=");
120
121   GNUNET_STRINGS_base64_encode (body_str,
122                                 strlen (body_str),
123                                 &body_base64);
124
125   //Remove GNUNET padding of base64
126   padding = strtok(body_base64, "=");
127   while (NULL != padding)
128     padding = strtok(NULL, "=");
129
130   GNUNET_free (issuer);
131   GNUNET_free (audience);
132
133   /**
134    * TODO
135    * Creating the JWT signature. This might not be
136    * standards compliant, check.
137    */
138   GNUNET_asprintf (&signature_target, "%s,%s", header_base64, body_base64);
139
140   purpose =
141     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
142                    strlen (signature_target));
143   purpose->size =
144     htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
145   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
146   GNUNET_memcpy (&purpose[1], signature_target, strlen (signature_target));
147   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
148                                              purpose,
149                                              (struct GNUNET_CRYPTO_EcdsaSignature *)&signature))
150   {
151     GNUNET_free (signature_target);
152     GNUNET_free (body_str);
153     GNUNET_free (body_base64);
154     GNUNET_free (header_base64);
155     GNUNET_free (purpose);
156     return NULL;
157   }
158   GNUNET_STRINGS_base64_encode ((const char*)&signature,
159                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
160                                 &signature_base64);
161   GNUNET_asprintf (&result, "%s.%s.%s",
162                    header_base64, body_base64, signature_base64);
163
164   GNUNET_free (signature_target);
165   GNUNET_free (header);
166   GNUNET_free (body_str);
167   GNUNET_free (signature_base64);
168   GNUNET_free (body_base64);
169   GNUNET_free (header_base64);
170   GNUNET_free (purpose);
171   return result;
172 }