diff options
author | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-07-23 12:42:18 +0200 |
---|---|---|
committer | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-07-23 12:42:18 +0200 |
commit | 97b5905aac2954fd0ce618b86ae80d11671fa1ba (patch) | |
tree | 0ea14c61e4c0a7ef3deadd82be45280075a8864c /src/reclaim | |
parent | 98defb69b11bc6ca89cd1b5419de5036004626c4 (diff) | |
download | gnunet-97b5905aac2954fd0ce618b86ae80d11671fa1ba.tar.gz gnunet-97b5905aac2954fd0ce618b86ae80d11671fa1ba.zip |
refactoring of OIDC plugin
Diffstat (limited to 'src/reclaim')
-rw-r--r-- | src/reclaim/Makefile.am | 5 | ||||
-rw-r--r-- | src/reclaim/jwt.c | 201 | ||||
-rw-r--r-- | src/reclaim/jwt.h | 23 | ||||
-rw-r--r-- | src/reclaim/oidc_helper.c | 440 | ||||
-rw-r--r-- | src/reclaim/oidc_helper.h | 109 | ||||
-rw-r--r-- | src/reclaim/plugin_rest_openid_connect.c | 531 |
6 files changed, 737 insertions, 572 deletions
diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am index 91a041f91..2ee43d21a 100644 --- a/src/reclaim/Makefile.am +++ b/src/reclaim/Makefile.am | |||
@@ -89,8 +89,7 @@ libgnunetreclaim_la_LDFLAGS = \ | |||
89 | -version-info 0:0:0 | 89 | -version-info 0:0:0 |
90 | 90 | ||
91 | libgnunet_plugin_rest_reclaim_la_SOURCES = \ | 91 | libgnunet_plugin_rest_reclaim_la_SOURCES = \ |
92 | plugin_rest_reclaim.c \ | 92 | plugin_rest_reclaim.c |
93 | jwt.c | ||
94 | libgnunet_plugin_rest_reclaim_la_LIBADD = \ | 93 | libgnunet_plugin_rest_reclaim_la_LIBADD = \ |
95 | $(top_builddir)/src/identity/libgnunetidentity.la \ | 94 | $(top_builddir)/src/identity/libgnunetidentity.la \ |
96 | libgnunetreclaim.la \ | 95 | libgnunetreclaim.la \ |
@@ -105,7 +104,7 @@ libgnunet_plugin_rest_reclaim_la_LDFLAGS = \ | |||
105 | 104 | ||
106 | libgnunet_plugin_rest_openid_connect_la_SOURCES = \ | 105 | libgnunet_plugin_rest_openid_connect_la_SOURCES = \ |
107 | plugin_rest_openid_connect.c \ | 106 | plugin_rest_openid_connect.c \ |
108 | jwt.c | 107 | oidc_helper.c |
109 | libgnunet_plugin_rest_openid_connect_la_LIBADD = \ | 108 | libgnunet_plugin_rest_openid_connect_la_LIBADD = \ |
110 | $(top_builddir)/src/identity/libgnunetidentity.la \ | 109 | $(top_builddir)/src/identity/libgnunetidentity.la \ |
111 | libgnunetreclaim.la \ | 110 | libgnunetreclaim.la \ |
diff --git a/src/reclaim/jwt.c b/src/reclaim/jwt.c index 94db19b14..8b1378917 100644 --- a/src/reclaim/jwt.c +++ b/src/reclaim/jwt.c | |||
@@ -1,202 +1 @@ | |||
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 | |||
19 | /** | ||
20 | * @file reclaim/jwt.c | ||
21 | * @brief helper library for JSON-Web-Tokens | ||
22 | * @author Martin Schanzenbach | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | #include "gnunet_signatures.h" | ||
27 | #include "gnunet_reclaim_attribute_lib.h" | ||
28 | #include <jansson.h> | ||
29 | |||
30 | |||
31 | #define JWT_ALG "alg" | ||
32 | |||
33 | /* Use 512bit HMAC */ | ||
34 | #define JWT_ALG_VALUE "HS512" | ||
35 | |||
36 | #define JWT_TYP "typ" | ||
37 | |||
38 | #define JWT_TYP_VALUE "jwt" | ||
39 | |||
40 | #define SERVER_ADDRESS "https://reclaim.id" | ||
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(0) | JSON_COMPACT); | ||
53 | json_decref (root); | ||
54 | return json_str; | ||
55 | } | ||
56 | |||
57 | static void | ||
58 | replace_char(char* str, char find, char replace){ | ||
59 | char *current_pos = strchr(str,find); | ||
60 | while (current_pos){ | ||
61 | *current_pos = replace; | ||
62 | current_pos = strchr(current_pos,find); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | //RFC4648 | ||
67 | static void | ||
68 | fix_base64(char* str) { | ||
69 | char *padding; | ||
70 | //First, remove trailing padding '=' | ||
71 | padding = strtok(str, "="); | ||
72 | while (NULL != padding) | ||
73 | padding = strtok(NULL, "="); | ||
74 | |||
75 | //Replace + with - | ||
76 | replace_char (str, '+', '-'); | ||
77 | |||
78 | //Replace / with _ | ||
79 | replace_char (str, '/', '_'); | ||
80 | |||
81 | } | ||
82 | |||
83 | /** | ||
84 | * Create a JWT from attributes | ||
85 | * | ||
86 | * @param aud_key the public of the audience | ||
87 | * @param sub_key the public key of the subject | ||
88 | * @param attrs the attribute list | ||
89 | * @param expiration_time the validity of the token | ||
90 | * @param secret_key the key used to sign the JWT | ||
91 | * @return a new base64-encoded JWT string. | ||
92 | */ | ||
93 | char* | ||
94 | jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | ||
95 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
96 | const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, | ||
97 | const struct GNUNET_TIME_Relative *expiration_time, | ||
98 | const char *nonce, | ||
99 | const char *secret_key) | ||
100 | { | ||
101 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; | ||
102 | struct GNUNET_HashCode signature; | ||
103 | struct GNUNET_TIME_Absolute exp_time; | ||
104 | struct GNUNET_TIME_Absolute time_now; | ||
105 | char* audience; | ||
106 | char* subject; | ||
107 | char* header; | ||
108 | char* body_str; | ||
109 | char* result; | ||
110 | char* header_base64; | ||
111 | char* body_base64; | ||
112 | char* signature_target; | ||
113 | char* signature_base64; | ||
114 | char* attr_val_str; | ||
115 | json_t* body; | ||
116 | |||
117 | //iat REQUIRED time now | ||
118 | time_now = GNUNET_TIME_absolute_get(); | ||
119 | //exp REQUIRED time expired from config | ||
120 | exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); | ||
121 | //auth_time only if max_age | ||
122 | //nonce only if nonce | ||
123 | // OPTIONAL acr,amr,azp | ||
124 | subject = GNUNET_STRINGS_data_to_string_alloc (sub_key, | ||
125 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
126 | audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, | ||
127 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
128 | header = create_jwt_header (); | ||
129 | body = json_object (); | ||
130 | |||
131 | //iss REQUIRED case sensitive server uri with https | ||
132 | //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) | ||
133 | json_object_set_new (body, | ||
134 | "iss", json_string (SERVER_ADDRESS)); | ||
135 | //sub REQUIRED public key identity, not exceed 255 ASCII length | ||
136 | json_object_set_new (body, | ||
137 | "sub", json_string (subject)); | ||
138 | //aud REQUIRED public key client_id must be there | ||
139 | json_object_set_new (body, | ||
140 | "aud", json_string (audience)); | ||
141 | //iat | ||
142 | json_object_set_new (body, | ||
143 | "iat", json_integer (time_now.abs_value_us / (1000*1000))); | ||
144 | //exp | ||
145 | json_object_set_new (body, | ||
146 | "exp", json_integer (exp_time.abs_value_us / (1000*1000))); | ||
147 | //nbf | ||
148 | json_object_set_new (body, | ||
149 | "nbf", json_integer (time_now.abs_value_us / (1000*1000))); | ||
150 | //nonce | ||
151 | if (NULL != nonce) | ||
152 | json_object_set_new (body, | ||
153 | "nonce", json_string (nonce)); | ||
154 | |||
155 | for (le = attrs->list_head; NULL != le; le = le->next) | ||
156 | { | ||
157 | attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, | ||
158 | le->claim->data, | ||
159 | le->claim->data_size); | ||
160 | json_object_set_new (body, | ||
161 | le->claim->name, | ||
162 | json_string (attr_val_str)); | ||
163 | GNUNET_free (attr_val_str); | ||
164 | } | ||
165 | body_str = json_dumps (body, JSON_INDENT(0) | JSON_COMPACT); | ||
166 | json_decref (body); | ||
167 | |||
168 | GNUNET_STRINGS_base64_encode (header, | ||
169 | strlen (header), | ||
170 | &header_base64); | ||
171 | fix_base64(header_base64); | ||
172 | |||
173 | GNUNET_STRINGS_base64_encode (body_str, | ||
174 | strlen (body_str), | ||
175 | &body_base64); | ||
176 | fix_base64(body_base64); | ||
177 | |||
178 | GNUNET_free (subject); | ||
179 | GNUNET_free (audience); | ||
180 | |||
181 | /** | ||
182 | * Creating the JWT signature. This might not be | ||
183 | * standards compliant, check. | ||
184 | */ | ||
185 | GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); | ||
186 | GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target, strlen (signature_target), &signature); | ||
187 | GNUNET_STRINGS_base64_encode ((const char*)&signature, | ||
188 | sizeof (struct GNUNET_HashCode), | ||
189 | &signature_base64); | ||
190 | fix_base64(signature_base64); | ||
191 | |||
192 | GNUNET_asprintf (&result, "%s.%s.%s", | ||
193 | header_base64, body_base64, signature_base64); | ||
194 | |||
195 | GNUNET_free (signature_target); | ||
196 | GNUNET_free (header); | ||
197 | GNUNET_free (body_str); | ||
198 | GNUNET_free (signature_base64); | ||
199 | GNUNET_free (body_base64); | ||
200 | GNUNET_free (header_base64); | ||
201 | return result; | ||
202 | } | ||
diff --git a/src/reclaim/jwt.h b/src/reclaim/jwt.h deleted file mode 100644 index 12ff85b01..000000000 --- a/src/reclaim/jwt.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | #ifndef JWT_H | ||
2 | #define JWT_H | ||
3 | |||
4 | /** | ||
5 | * Create a JWT from attributes | ||
6 | * | ||
7 | * @param aud_key the public of the audience | ||
8 | * @param sub_key the public key of the subject | ||
9 | * @param attrs the attribute list | ||
10 | * @param expiration_time the validity of the token | ||
11 | * @param nonce the nonce, may be NULL | ||
12 | * @param secret_key the key used to sign the JWT | ||
13 | * @return a new base64-encoded JWT string. | ||
14 | */ | ||
15 | char* | ||
16 | jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | ||
17 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
18 | const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, | ||
19 | const struct GNUNET_TIME_Relative *expiration_time, | ||
20 | const char *nonce, | ||
21 | const char *secret_key); | ||
22 | |||
23 | #endif | ||
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c new file mode 100644 index 000000000..9a99c5668 --- /dev/null +++ b/src/reclaim/oidc_helper.c | |||
@@ -0,0 +1,440 @@ | |||
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 | |||
19 | /** | ||
20 | * @file reclaim/oidc_helper.c | ||
21 | * @brief helper library for OIDC related functions | ||
22 | * @author Martin Schanzenbach | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | #include "gnunet_signatures.h" | ||
27 | #include "gnunet_reclaim_service.h" | ||
28 | #include "gnunet_reclaim_attribute_lib.h" | ||
29 | #include <jansson.h> | ||
30 | #include <inttypes.h> | ||
31 | #include "oidc_helper.h" | ||
32 | |||
33 | static char* | ||
34 | create_jwt_header(void) | ||
35 | { | ||
36 | json_t *root; | ||
37 | char *json_str; | ||
38 | |||
39 | root = json_object (); | ||
40 | json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); | ||
41 | json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); | ||
42 | |||
43 | json_str = json_dumps (root, JSON_INDENT(0) | JSON_COMPACT); | ||
44 | json_decref (root); | ||
45 | return json_str; | ||
46 | } | ||
47 | |||
48 | static void | ||
49 | replace_char(char* str, char find, char replace){ | ||
50 | char *current_pos = strchr(str,find); | ||
51 | while (current_pos){ | ||
52 | *current_pos = replace; | ||
53 | current_pos = strchr(current_pos,find); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | //RFC4648 | ||
58 | static void | ||
59 | fix_base64(char* str) { | ||
60 | char *padding; | ||
61 | //First, remove trailing padding '=' | ||
62 | padding = strtok(str, "="); | ||
63 | while (NULL != padding) | ||
64 | padding = strtok(NULL, "="); | ||
65 | |||
66 | //Replace + with - | ||
67 | replace_char (str, '+', '-'); | ||
68 | |||
69 | //Replace / with _ | ||
70 | replace_char (str, '/', '_'); | ||
71 | |||
72 | } | ||
73 | |||
74 | /** | ||
75 | * Create a JWT from attributes | ||
76 | * | ||
77 | * @param aud_key the public of the audience | ||
78 | * @param sub_key the public key of the subject | ||
79 | * @param attrs the attribute list | ||
80 | * @param expiration_time the validity of the token | ||
81 | * @param secret_key the key used to sign the JWT | ||
82 | * @return a new base64-encoded JWT string. | ||
83 | */ | ||
84 | char* | ||
85 | OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | ||
86 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
87 | const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, | ||
88 | const struct GNUNET_TIME_Relative *expiration_time, | ||
89 | const char *nonce, | ||
90 | const char *secret_key) | ||
91 | { | ||
92 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; | ||
93 | struct GNUNET_HashCode signature; | ||
94 | struct GNUNET_TIME_Absolute exp_time; | ||
95 | struct GNUNET_TIME_Absolute time_now; | ||
96 | char* audience; | ||
97 | char* subject; | ||
98 | char* header; | ||
99 | char* body_str; | ||
100 | char* result; | ||
101 | char* header_base64; | ||
102 | char* body_base64; | ||
103 | char* signature_target; | ||
104 | char* signature_base64; | ||
105 | char* attr_val_str; | ||
106 | json_t* body; | ||
107 | |||
108 | //iat REQUIRED time now | ||
109 | time_now = GNUNET_TIME_absolute_get(); | ||
110 | //exp REQUIRED time expired from config | ||
111 | exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); | ||
112 | //auth_time only if max_age | ||
113 | //nonce only if nonce | ||
114 | // OPTIONAL acr,amr,azp | ||
115 | subject = GNUNET_STRINGS_data_to_string_alloc (sub_key, | ||
116 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
117 | audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, | ||
118 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
119 | header = create_jwt_header (); | ||
120 | body = json_object (); | ||
121 | |||
122 | //iss REQUIRED case sensitive server uri with https | ||
123 | //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) | ||
124 | json_object_set_new (body, | ||
125 | "iss", json_string (SERVER_ADDRESS)); | ||
126 | //sub REQUIRED public key identity, not exceed 255 ASCII length | ||
127 | json_object_set_new (body, | ||
128 | "sub", json_string (subject)); | ||
129 | //aud REQUIRED public key client_id must be there | ||
130 | json_object_set_new (body, | ||
131 | "aud", json_string (audience)); | ||
132 | //iat | ||
133 | json_object_set_new (body, | ||
134 | "iat", json_integer (time_now.abs_value_us / (1000*1000))); | ||
135 | //exp | ||
136 | json_object_set_new (body, | ||
137 | "exp", json_integer (exp_time.abs_value_us / (1000*1000))); | ||
138 | //nbf | ||
139 | json_object_set_new (body, | ||
140 | "nbf", json_integer (time_now.abs_value_us / (1000*1000))); | ||
141 | //nonce | ||
142 | if (NULL != nonce) | ||
143 | json_object_set_new (body, | ||
144 | "nonce", json_string (nonce)); | ||
145 | |||
146 | for (le = attrs->list_head; NULL != le; le = le->next) | ||
147 | { | ||
148 | attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, | ||
149 | le->claim->data, | ||
150 | le->claim->data_size); | ||
151 | json_object_set_new (body, | ||
152 | le->claim->name, | ||
153 | json_string (attr_val_str)); | ||
154 | GNUNET_free (attr_val_str); | ||
155 | } | ||
156 | body_str = json_dumps (body, JSON_INDENT(0) | JSON_COMPACT); | ||
157 | json_decref (body); | ||
158 | |||
159 | GNUNET_STRINGS_base64_encode (header, | ||
160 | strlen (header), | ||
161 | &header_base64); | ||
162 | fix_base64(header_base64); | ||
163 | |||
164 | GNUNET_STRINGS_base64_encode (body_str, | ||
165 | strlen (body_str), | ||
166 | &body_base64); | ||
167 | fix_base64(body_base64); | ||
168 | |||
169 | GNUNET_free (subject); | ||
170 | GNUNET_free (audience); | ||
171 | |||
172 | /** | ||
173 | * Creating the JWT signature. This might not be | ||
174 | * standards compliant, check. | ||
175 | */ | ||
176 | GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); | ||
177 | GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target, strlen (signature_target), &signature); | ||
178 | GNUNET_STRINGS_base64_encode ((const char*)&signature, | ||
179 | sizeof (struct GNUNET_HashCode), | ||
180 | &signature_base64); | ||
181 | fix_base64(signature_base64); | ||
182 | |||
183 | GNUNET_asprintf (&result, "%s.%s.%s", | ||
184 | header_base64, body_base64, signature_base64); | ||
185 | |||
186 | GNUNET_free (signature_target); | ||
187 | GNUNET_free (header); | ||
188 | GNUNET_free (body_str); | ||
189 | GNUNET_free (signature_base64); | ||
190 | GNUNET_free (body_base64); | ||
191 | GNUNET_free (header_base64); | ||
192 | return result; | ||
193 | } | ||
194 | /** | ||
195 | * Builds an OIDC authorization code including | ||
196 | * a reclaim ticket and nonce | ||
197 | * | ||
198 | * @param issuer the issuer of the ticket, used to sign the ticket and nonce | ||
199 | * @param ticket the ticket to include in the code | ||
200 | * @param nonce the nonce to include in the code | ||
201 | * @return a new authorization code (caller must free) | ||
202 | */ | ||
203 | char* | ||
204 | OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | ||
205 | const struct GNUNET_RECLAIM_Ticket *ticket, | ||
206 | const char* nonce) | ||
207 | { | ||
208 | char *ticket_str; | ||
209 | json_t *code_json; | ||
210 | char *signature_payload; | ||
211 | char *signature_str; | ||
212 | char *authz_code; | ||
213 | size_t signature_payload_len; | ||
214 | struct GNUNET_CRYPTO_EcdsaSignature signature; | ||
215 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | ||
216 | |||
217 | signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); | ||
218 | if (NULL != nonce) | ||
219 | signature_payload_len += strlen (nonce); | ||
220 | |||
221 | signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); | ||
222 | purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload; | ||
223 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); | ||
224 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); | ||
225 | memcpy (&purpose[1], | ||
226 | ticket, | ||
227 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
228 | if (NULL != nonce) | ||
229 | memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket), | ||
230 | nonce, | ||
231 | strlen (nonce)); | ||
232 | if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, | ||
233 | purpose, | ||
234 | &signature)) | ||
235 | { | ||
236 | GNUNET_free (signature_payload); | ||
237 | return NULL; | ||
238 | } | ||
239 | signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature, | ||
240 | sizeof (signature)); | ||
241 | ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, | ||
242 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
243 | |||
244 | code_json = json_object (); | ||
245 | json_object_set_new (code_json, | ||
246 | "ticket", | ||
247 | json_string (ticket_str)); | ||
248 | if (NULL != nonce) | ||
249 | json_object_set_new (code_json, | ||
250 | "nonce", | ||
251 | json_string (nonce)); | ||
252 | json_object_set_new (code_json, | ||
253 | "signature", | ||
254 | json_string (signature_str)); | ||
255 | authz_code = json_dumps (code_json, | ||
256 | JSON_INDENT(0) | JSON_COMPACT); | ||
257 | GNUNET_free (signature_payload); | ||
258 | GNUNET_free (signature_str); | ||
259 | GNUNET_free (ticket_str); | ||
260 | json_decref (code_json); | ||
261 | return authz_code; | ||
262 | } | ||
263 | |||
264 | |||
265 | |||
266 | |||
267 | /** | ||
268 | * Parse reclaim ticket and nonce from | ||
269 | * authorization code. | ||
270 | * This also verifies the signature in the code. | ||
271 | * | ||
272 | * @param audience the expected audience of the code | ||
273 | * @param code the string representation of the code | ||
274 | * @param ticket where to store the ticket | ||
275 | * @param nonce where to store the nonce | ||
276 | * @return GNUNET_OK if successful, else GNUNET_SYSERR | ||
277 | */ | ||
278 | int | ||
279 | OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | ||
280 | const char* code, | ||
281 | struct GNUNET_RECLAIM_Ticket **ticket, | ||
282 | char **nonce) | ||
283 | { | ||
284 | json_error_t error; | ||
285 | json_t *code_json; | ||
286 | json_t *ticket_json; | ||
287 | json_t *nonce_json; | ||
288 | json_t *signature_json; | ||
289 | const char *ticket_str; | ||
290 | const char *signature_str; | ||
291 | const char *nonce_str; | ||
292 | char *code_output; | ||
293 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | ||
294 | struct GNUNET_CRYPTO_EcdsaSignature signature; | ||
295 | size_t signature_payload_len; | ||
296 | |||
297 | code_output = NULL; | ||
298 | GNUNET_STRINGS_base64_decode (code, | ||
299 | strlen(code), | ||
300 | (void**)&code_output); | ||
301 | code_json = json_loads (code_output, 0 , &error); | ||
302 | GNUNET_free (code_output); | ||
303 | ticket_json = json_object_get (code_json, "ticket"); | ||
304 | nonce_json = json_object_get (code_json, "nonce"); | ||
305 | signature_json = json_object_get (code_json, "signature"); | ||
306 | *ticket = NULL; | ||
307 | *nonce = NULL; | ||
308 | |||
309 | if ((NULL == ticket_json || !json_is_string (ticket_json)) || | ||
310 | (NULL == signature_json || !json_is_string (signature_json))) | ||
311 | { | ||
312 | json_decref (code_json); | ||
313 | return GNUNET_SYSERR; | ||
314 | } | ||
315 | ticket_str = json_string_value (ticket_json); | ||
316 | signature_str = json_string_value (signature_json); | ||
317 | nonce_str = NULL; | ||
318 | if (NULL != nonce_json) | ||
319 | nonce_str = json_string_value (nonce_json); | ||
320 | signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); | ||
321 | if (NULL != nonce_str) | ||
322 | signature_payload_len += strlen (nonce_str); | ||
323 | purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | ||
324 | signature_payload_len); | ||
325 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); | ||
326 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); | ||
327 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ticket_str, | ||
328 | strlen (ticket_str), | ||
329 | &purpose[1], | ||
330 | sizeof (struct GNUNET_RECLAIM_Ticket))) | ||
331 | { | ||
332 | GNUNET_free (purpose); | ||
333 | json_decref (code_json); | ||
334 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
335 | "Cannot parse ticket!\n"); | ||
336 | return GNUNET_SYSERR; | ||
337 | } | ||
338 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_str, | ||
339 | strlen (signature_str), | ||
340 | &signature, | ||
341 | sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) | ||
342 | { | ||
343 | GNUNET_free (purpose); | ||
344 | json_decref (code_json); | ||
345 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
346 | "Cannot parse signature!\n"); | ||
347 | return GNUNET_SYSERR; | ||
348 | } | ||
349 | *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); | ||
350 | memcpy (*ticket, | ||
351 | &purpose[1], | ||
352 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
353 | if (0 != memcmp (audience, | ||
354 | &(*ticket)->audience, | ||
355 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
356 | { | ||
357 | GNUNET_free (purpose); | ||
358 | GNUNET_free (*ticket); | ||
359 | json_decref (code_json); | ||
360 | *ticket = NULL; | ||
361 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
362 | "Audience in ticket does not match client!\n"); | ||
363 | return GNUNET_SYSERR; | ||
364 | |||
365 | } | ||
366 | if (NULL != nonce_str) | ||
367 | memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket), | ||
368 | nonce_str, | ||
369 | strlen (nonce_str)); | ||
370 | if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, | ||
371 | purpose, | ||
372 | &signature, | ||
373 | &(*ticket)->identity)) | ||
374 | { | ||
375 | GNUNET_free (purpose); | ||
376 | GNUNET_free (*ticket); | ||
377 | json_decref (code_json); | ||
378 | *ticket = NULL; | ||
379 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
380 | "Signature of authZ code invalid!\n"); | ||
381 | return GNUNET_SYSERR; | ||
382 | } | ||
383 | *nonce = GNUNET_strdup (nonce_str); | ||
384 | return GNUNET_OK; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * Build a token response for a token request | ||
389 | * TODO: Maybe we should add the scope here? | ||
390 | * | ||
391 | * @param access_token the access token to include | ||
392 | * @param id_token the id_token to include | ||
393 | * @param expiration_time the expiration time of the token(s) | ||
394 | * @param token_response where to store the response | ||
395 | */ | ||
396 | void | ||
397 | OIDC_build_token_response (const char *access_token, | ||
398 | const char *id_token, | ||
399 | const struct GNUNET_TIME_Relative *expiration_time, | ||
400 | char **token_response) | ||
401 | { | ||
402 | json_t *root_json; | ||
403 | |||
404 | root_json = json_object (); | ||
405 | |||
406 | GNUNET_assert (NULL != access_token); | ||
407 | GNUNET_assert (NULL != id_token); | ||
408 | GNUNET_assert (NULL != expiration_time); | ||
409 | json_object_set_new (root_json, | ||
410 | "access_token", | ||
411 | json_string (access_token)); | ||
412 | json_object_set_new (root_json, | ||
413 | "token_type", | ||
414 | json_string ("Bearer")); | ||
415 | json_object_set_new (root_json, | ||
416 | "expires_in", | ||
417 | json_integer (expiration_time->rel_value_us / (1000 * 1000))); | ||
418 | json_object_set_new (root_json, | ||
419 | "id_token", | ||
420 | json_string (id_token)); | ||
421 | *token_response = json_dumps (root_json, | ||
422 | JSON_INDENT(0) | JSON_COMPACT); | ||
423 | json_decref (root_json); | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * Generate a new access token | ||
428 | */ | ||
429 | char* | ||
430 | OIDC_access_token_new () | ||
431 | { | ||
432 | char* access_token_number; | ||
433 | char* access_token; | ||
434 | uint64_t random_number; | ||
435 | |||
436 | random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); | ||
437 | GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number); | ||
438 | GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); | ||
439 | return access_token; | ||
440 | } | ||
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h new file mode 100644 index 000000000..7a0f45bf9 --- /dev/null +++ b/src/reclaim/oidc_helper.h | |||
@@ -0,0 +1,109 @@ | |||
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 | |||
19 | /** | ||
20 | * @file reclaim/oidc_helper.h | ||
21 | * @brief helper library for OIDC related functions | ||
22 | * @author Martin Schanzenbach | ||
23 | */ | ||
24 | |||
25 | #ifndef JWT_H | ||
26 | #define JWT_H | ||
27 | |||
28 | #define JWT_ALG "alg" | ||
29 | |||
30 | /* Use 512bit HMAC */ | ||
31 | #define JWT_ALG_VALUE "HS512" | ||
32 | |||
33 | #define JWT_TYP "typ" | ||
34 | |||
35 | #define JWT_TYP_VALUE "jwt" | ||
36 | |||
37 | #define SERVER_ADDRESS "https://reclaim.id" | ||
38 | |||
39 | /** | ||
40 | * Create a JWT from attributes | ||
41 | * | ||
42 | * @param aud_key the public of the audience | ||
43 | * @param sub_key the public key of the subject | ||
44 | * @param attrs the attribute list | ||
45 | * @param expiration_time the validity of the token | ||
46 | * @param secret_key the key used to sign the JWT | ||
47 | * @return a new base64-encoded JWT string. | ||
48 | */ | ||
49 | char* | ||
50 | OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | ||
51 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
52 | const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, | ||
53 | const struct GNUNET_TIME_Relative *expiration_time, | ||
54 | const char *nonce, | ||
55 | const char *secret_key); | ||
56 | |||
57 | /** | ||
58 | * Builds an OIDC authorization code including | ||
59 | * a reclaim ticket and nonce | ||
60 | * | ||
61 | * @param issuer the issuer of the ticket, used to sign the ticket and nonce | ||
62 | * @param ticket the ticket to include in the code | ||
63 | * @param nonce the nonce to include in the code | ||
64 | * @return a new authorization code (caller must free) | ||
65 | */ | ||
66 | char* | ||
67 | OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | ||
68 | const struct GNUNET_RECLAIM_Ticket *ticket, | ||
69 | const char* nonce); | ||
70 | |||
71 | /** | ||
72 | * Parse reclaim ticket and nonce from | ||
73 | * authorization code. | ||
74 | * This also verifies the signature in the code. | ||
75 | * | ||
76 | * @param audience the expected audience of the code | ||
77 | * @param code the string representation of the code | ||
78 | * @param ticket where to store the ticket | ||
79 | * @param nonce where to store the nonce | ||
80 | * @return GNUNET_OK if successful, else GNUNET_SYSERR | ||
81 | */ | ||
82 | int | ||
83 | OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | ||
84 | const char* code, | ||
85 | struct GNUNET_RECLAIM_Ticket **ticket, | ||
86 | char **nonce); | ||
87 | |||
88 | /** | ||
89 | * Build a token response for a token request | ||
90 | * TODO: Maybe we should add the scope here? | ||
91 | * | ||
92 | * @param access_token the access token to include | ||
93 | * @param id_token the id_token to include | ||
94 | * @param expiration_time the expiration time of the token(s) | ||
95 | * @param token_response where to store the response | ||
96 | */ | ||
97 | void | ||
98 | OIDC_build_token_response (const char *access_token, | ||
99 | const char *id_token, | ||
100 | const struct GNUNET_TIME_Relative *expiration_time, | ||
101 | char **token_response); | ||
102 | /** | ||
103 | * Generate a new access token | ||
104 | */ | ||
105 | char* | ||
106 | OIDC_access_token_new (); | ||
107 | |||
108 | |||
109 | #endif | ||
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 0f746f988..06815d9d1 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include "gnunet_signatures.h" | 38 | #include "gnunet_signatures.h" |
39 | #include "gnunet_reclaim_attribute_lib.h" | 39 | #include "gnunet_reclaim_attribute_lib.h" |
40 | #include "gnunet_reclaim_service.h" | 40 | #include "gnunet_reclaim_service.h" |
41 | #include "jwt.h" | 41 | #include "oidc_helper.h" |
42 | 42 | ||
43 | /** | 43 | /** |
44 | * REST root namespace | 44 | * REST root namespace |
@@ -823,177 +823,6 @@ oidc_iteration_error (void *cls) | |||
823 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 823 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
824 | } | 824 | } |
825 | 825 | ||
826 | static int | ||
827 | parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | ||
828 | const char* code, | ||
829 | struct GNUNET_RECLAIM_Ticket **ticket, | ||
830 | char **nonce) | ||
831 | { | ||
832 | json_error_t error; | ||
833 | json_t *code_json; | ||
834 | json_t *ticket_json; | ||
835 | json_t *nonce_json; | ||
836 | json_t *signature_json; | ||
837 | const char *ticket_str; | ||
838 | const char *signature_str; | ||
839 | const char *nonce_str; | ||
840 | char *code_output; | ||
841 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | ||
842 | struct GNUNET_CRYPTO_EcdsaSignature signature; | ||
843 | size_t signature_payload_len; | ||
844 | |||
845 | code_output = NULL; | ||
846 | GNUNET_STRINGS_base64_decode (code, | ||
847 | strlen(code), | ||
848 | (void**)&code_output); | ||
849 | code_json = json_loads (code_output, 0 , &error); | ||
850 | GNUNET_free (code_output); | ||
851 | ticket_json = json_object_get (code_json, "ticket"); | ||
852 | nonce_json = json_object_get (code_json, "nonce"); | ||
853 | signature_json = json_object_get (code_json, "signature"); | ||
854 | *ticket = NULL; | ||
855 | *nonce = NULL; | ||
856 | |||
857 | if ((NULL == ticket_json || !json_is_string (ticket_json)) || | ||
858 | (NULL == signature_json || !json_is_string (signature_json))) | ||
859 | { | ||
860 | json_decref (code_json); | ||
861 | return GNUNET_SYSERR; | ||
862 | } | ||
863 | ticket_str = json_string_value (ticket_json); | ||
864 | signature_str = json_string_value (signature_json); | ||
865 | nonce_str = NULL; | ||
866 | if (NULL != nonce_json) | ||
867 | nonce_str = json_string_value (nonce_json); | ||
868 | signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); | ||
869 | if (NULL != nonce_str) | ||
870 | signature_payload_len += strlen (nonce_str); | ||
871 | purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | ||
872 | signature_payload_len); | ||
873 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); | ||
874 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); | ||
875 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ticket_str, | ||
876 | strlen (ticket_str), | ||
877 | &purpose[1], | ||
878 | sizeof (struct GNUNET_RECLAIM_Ticket))) | ||
879 | { | ||
880 | GNUNET_free (purpose); | ||
881 | json_decref (code_json); | ||
882 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
883 | "Cannot parse ticket!\n"); | ||
884 | return GNUNET_SYSERR; | ||
885 | } | ||
886 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_str, | ||
887 | strlen (signature_str), | ||
888 | &signature, | ||
889 | sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) | ||
890 | { | ||
891 | GNUNET_free (purpose); | ||
892 | json_decref (code_json); | ||
893 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
894 | "Cannot parse signature!\n"); | ||
895 | return GNUNET_SYSERR; | ||
896 | } | ||
897 | *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); | ||
898 | memcpy (*ticket, | ||
899 | &purpose[1], | ||
900 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
901 | if (0 != memcmp (audience, | ||
902 | &(*ticket)->audience, | ||
903 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
904 | { | ||
905 | GNUNET_free (purpose); | ||
906 | GNUNET_free (*ticket); | ||
907 | json_decref (code_json); | ||
908 | *ticket = NULL; | ||
909 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
910 | "Audience in ticket does not match client!\n"); | ||
911 | return GNUNET_SYSERR; | ||
912 | |||
913 | } | ||
914 | if (NULL != nonce_str) | ||
915 | memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket), | ||
916 | nonce_str, | ||
917 | strlen (nonce_str)); | ||
918 | if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, | ||
919 | purpose, | ||
920 | &signature, | ||
921 | &(*ticket)->identity)) | ||
922 | { | ||
923 | GNUNET_free (purpose); | ||
924 | GNUNET_free (*ticket); | ||
925 | json_decref (code_json); | ||
926 | *ticket = NULL; | ||
927 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
928 | "Signature of authZ code invalid!\n"); | ||
929 | return GNUNET_SYSERR; | ||
930 | } | ||
931 | *nonce = GNUNET_strdup (nonce_str); | ||
932 | return GNUNET_OK; | ||
933 | } | ||
934 | |||
935 | static char* | ||
936 | build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, | ||
937 | const struct GNUNET_RECLAIM_Ticket *ticket, | ||
938 | const char* nonce) | ||
939 | { | ||
940 | char *ticket_str; | ||
941 | json_t *code_json; | ||
942 | char *signature_payload; | ||
943 | char *signature_str; | ||
944 | char *authz_code; | ||
945 | size_t signature_payload_len; | ||
946 | struct GNUNET_CRYPTO_EcdsaSignature signature; | ||
947 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | ||
948 | |||
949 | signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket); | ||
950 | if (NULL != nonce) | ||
951 | signature_payload_len += strlen (nonce); | ||
952 | |||
953 | signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); | ||
954 | purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload; | ||
955 | purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len); | ||
956 | purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); | ||
957 | memcpy (&purpose[1], | ||
958 | ticket, | ||
959 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
960 | if (NULL != nonce) | ||
961 | memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket), | ||
962 | nonce, | ||
963 | strlen (nonce)); | ||
964 | if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, | ||
965 | purpose, | ||
966 | &signature)) | ||
967 | { | ||
968 | GNUNET_free (signature_payload); | ||
969 | return NULL; | ||
970 | } | ||
971 | signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature, | ||
972 | sizeof (signature)); | ||
973 | ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, | ||
974 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
975 | |||
976 | code_json = json_object (); | ||
977 | json_object_set_new (code_json, | ||
978 | "ticket", | ||
979 | json_string (ticket_str)); | ||
980 | if (NULL != nonce) | ||
981 | json_object_set_new (code_json, | ||
982 | "nonce", | ||
983 | json_string (nonce)); | ||
984 | json_object_set_new (code_json, | ||
985 | "signature", | ||
986 | json_string (signature_str)); | ||
987 | authz_code = json_dumps (code_json, | ||
988 | JSON_INDENT(0) | JSON_COMPACT); | ||
989 | GNUNET_free (signature_payload); | ||
990 | GNUNET_free (signature_str); | ||
991 | GNUNET_free (ticket_str); | ||
992 | json_decref (code_json); | ||
993 | return authz_code; | ||
994 | } | ||
995 | |||
996 | |||
997 | static void | 826 | static void |
998 | get_client_name_result (void *cls, | 827 | get_client_name_result (void *cls, |
999 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, | 828 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, |
@@ -1011,9 +840,9 @@ get_client_name_result (void *cls, | |||
1011 | ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, | 840 | ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, |
1012 | sizeof (struct GNUNET_RECLAIM_Ticket)); | 841 | sizeof (struct GNUNET_RECLAIM_Ticket)); |
1013 | //TODO change if more attributes are needed (see max_age) | 842 | //TODO change if more attributes are needed (see max_age) |
1014 | code_json_string = build_authz_code (&handle->priv_key, | 843 | code_json_string = OIDC_build_authz_code (&handle->priv_key, |
1015 | &handle->ticket, | 844 | &handle->ticket, |
1016 | handle->oidc->nonce); | 845 | handle->oidc->nonce); |
1017 | code_base64_final_string = base_64_encode(code_json_string); | 846 | code_base64_final_string = base_64_encode(code_json_string); |
1018 | GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", | 847 | GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", |
1019 | handle->redirect_prefix, | 848 | handle->redirect_prefix, |
@@ -1532,36 +1361,19 @@ login_cont (struct GNUNET_REST_RequestHandle *con_handle, | |||
1532 | return; | 1361 | return; |
1533 | } | 1362 | } |
1534 | 1363 | ||
1535 | /** | 1364 | static int |
1536 | * Responds to token url-encoded POST request | 1365 | check_authorization (struct RequestHandle *handle, |
1537 | * | 1366 | struct GNUNET_CRYPTO_EcdsaPublicKey *cid) |
1538 | * @param con_handle the connection handle | ||
1539 | * @param url the url | ||
1540 | * @param cls the RequestHandle | ||
1541 | */ | ||
1542 | static void | ||
1543 | token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | ||
1544 | const char* url, | ||
1545 | void *cls) | ||
1546 | { | 1367 | { |
1547 | //TODO static strings | ||
1548 | struct RequestHandle *handle = cls; | ||
1549 | struct GNUNET_HashCode cache_key; | 1368 | struct GNUNET_HashCode cache_key; |
1550 | char *authorization, *credentials; | 1369 | char *authorization; |
1551 | char delimiter[]=" "; | 1370 | char *credentials; |
1552 | char delimiter_user_psw[]=":"; | 1371 | char *basic_authorization; |
1553 | char *grant_type, *code; | 1372 | char *client_id; |
1554 | char *user_psw = NULL, *client_id, *psw; | 1373 | char *pass; |
1555 | char *expected_psw; | 1374 | char *expected_pass; |
1556 | int client_exists = GNUNET_NO; | 1375 | int client_exists = GNUNET_NO; |
1557 | struct MHD_Response *resp; | ||
1558 | char *json_response; | ||
1559 | char *jwt_secret; | ||
1560 | char *nonce; | ||
1561 | 1376 | ||
1562 | /* | ||
1563 | * Check Authorization | ||
1564 | */ | ||
1565 | GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, | 1377 | GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, |
1566 | strlen (OIDC_AUTHORIZATION_HEADER_KEY), | 1378 | strlen (OIDC_AUTHORIZATION_HEADER_KEY), |
1567 | &cache_key); | 1379 | &cache_key); |
@@ -1571,80 +1383,75 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1571 | handle->emsg=GNUNET_strdup("invalid_client"); | 1383 | handle->emsg=GNUNET_strdup("invalid_client"); |
1572 | handle->edesc=GNUNET_strdup("missing authorization"); | 1384 | handle->edesc=GNUNET_strdup("missing authorization"); |
1573 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1385 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1574 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1386 | return GNUNET_SYSERR; |
1575 | return; | ||
1576 | } | 1387 | } |
1577 | authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); | 1388 | authorization = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, |
1389 | &cache_key); | ||
1578 | 1390 | ||
1579 | //split header in "Basic" and [content] | 1391 | //split header in "Basic" and [content] |
1580 | credentials = strtok (authorization, delimiter); | 1392 | credentials = strtok (authorization, " "); |
1581 | if (0 != strcmp ("Basic",credentials)) | 1393 | if (0 != strcmp ("Basic", credentials)) |
1582 | { | 1394 | { |
1583 | handle->emsg=GNUNET_strdup("invalid_client"); | 1395 | handle->emsg=GNUNET_strdup("invalid_client"); |
1584 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1396 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1585 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1397 | return GNUNET_SYSERR; |
1586 | return; | ||
1587 | } | 1398 | } |
1588 | credentials = strtok(NULL, delimiter); | 1399 | credentials = strtok(NULL, " "); |
1589 | if (NULL == credentials) | 1400 | if (NULL == credentials) |
1590 | { | 1401 | { |
1591 | handle->emsg=GNUNET_strdup("invalid_client"); | 1402 | handle->emsg=GNUNET_strdup("invalid_client"); |
1592 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1403 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1593 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1404 | return GNUNET_SYSERR; |
1594 | return; | ||
1595 | } | 1405 | } |
1596 | GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), (void**)&user_psw); | 1406 | GNUNET_STRINGS_base64_decode (credentials, |
1407 | strlen (credentials), | ||
1408 | (void**)&basic_authorization); | ||
1597 | 1409 | ||
1598 | if ( NULL == user_psw ) | 1410 | if ( NULL == basic_authorization ) |
1599 | { | 1411 | { |
1600 | handle->emsg=GNUNET_strdup("invalid_client"); | 1412 | handle->emsg=GNUNET_strdup("invalid_client"); |
1601 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1413 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1602 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1414 | return GNUNET_SYSERR; |
1603 | return; | ||
1604 | } | 1415 | } |
1605 | client_id = strtok (user_psw, delimiter_user_psw); | 1416 | client_id = strtok (basic_authorization, ":"); |
1606 | if ( NULL == client_id ) | 1417 | if ( NULL == client_id ) |
1607 | { | 1418 | { |
1608 | GNUNET_free_non_null(user_psw); | 1419 | GNUNET_free_non_null(basic_authorization); |
1609 | handle->emsg=GNUNET_strdup("invalid_client"); | 1420 | handle->emsg=GNUNET_strdup("invalid_client"); |
1610 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1421 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1611 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1422 | return GNUNET_SYSERR; |
1612 | return; | ||
1613 | } | 1423 | } |
1614 | psw = strtok (NULL, delimiter_user_psw); | 1424 | pass = strtok (NULL, ":"); |
1615 | if (NULL == psw) | 1425 | if (NULL == pass) |
1616 | { | 1426 | { |
1617 | GNUNET_free_non_null(user_psw); | 1427 | GNUNET_free_non_null(basic_authorization); |
1618 | handle->emsg=GNUNET_strdup("invalid_client"); | 1428 | handle->emsg=GNUNET_strdup("invalid_client"); |
1619 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1429 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1620 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1430 | return GNUNET_SYSERR; |
1621 | return; | ||
1622 | } | 1431 | } |
1623 | 1432 | ||
1624 | //check client password | 1433 | //check client password |
1625 | if ( GNUNET_OK | 1434 | if ( GNUNET_OK |
1626 | == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", | 1435 | == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", |
1627 | "psw", &expected_psw) ) | 1436 | "psw", &expected_pass) ) |
1628 | { | 1437 | { |
1629 | if (0 != strcmp (expected_psw, psw)) | 1438 | if (0 != strcmp (expected_pass, pass)) |
1630 | { | 1439 | { |
1631 | GNUNET_free_non_null(user_psw); | 1440 | GNUNET_free_non_null(basic_authorization); |
1632 | GNUNET_free(expected_psw); | 1441 | GNUNET_free(expected_pass); |
1633 | handle->emsg=GNUNET_strdup("invalid_client"); | 1442 | handle->emsg=GNUNET_strdup("invalid_client"); |
1634 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1443 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1635 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1444 | return GNUNET_SYSERR; |
1636 | return; | ||
1637 | } | 1445 | } |
1638 | GNUNET_free(expected_psw); | 1446 | GNUNET_free(expected_pass); |
1639 | } | 1447 | } |
1640 | else | 1448 | else |
1641 | { | 1449 | { |
1642 | GNUNET_free_non_null(user_psw); | 1450 | GNUNET_free_non_null(basic_authorization); |
1643 | handle->emsg = GNUNET_strdup("server_error"); | 1451 | handle->emsg = GNUNET_strdup("server_error"); |
1644 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); | 1452 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); |
1645 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | 1453 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
1646 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1454 | return GNUNET_SYSERR; |
1647 | return; | ||
1648 | } | 1455 | } |
1649 | 1456 | ||
1650 | //check client_id | 1457 | //check client_id |
@@ -1659,9 +1466,108 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1659 | } | 1466 | } |
1660 | if (GNUNET_NO == client_exists) | 1467 | if (GNUNET_NO == client_exists) |
1661 | { | 1468 | { |
1662 | GNUNET_free_non_null(user_psw); | 1469 | GNUNET_free_non_null(basic_authorization); |
1663 | handle->emsg=GNUNET_strdup("invalid_client"); | 1470 | handle->emsg=GNUNET_strdup("invalid_client"); |
1664 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | 1471 | handle->response_code = MHD_HTTP_UNAUTHORIZED; |
1472 | return GNUNET_SYSERR; | ||
1473 | } | ||
1474 | GNUNET_STRINGS_string_to_data (client_id, | ||
1475 | strlen(client_id), | ||
1476 | cid, | ||
1477 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
1478 | |||
1479 | GNUNET_free (client_id); | ||
1480 | GNUNET_free (basic_authorization); | ||
1481 | return GNUNET_OK; | ||
1482 | } | ||
1483 | |||
1484 | static int | ||
1485 | ego_exists (struct RequestHandle *handle, | ||
1486 | struct GNUNET_CRYPTO_EcdsaPublicKey *test_key) | ||
1487 | { | ||
1488 | struct EgoEntry *ego_entry; | ||
1489 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
1490 | |||
1491 | for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) | ||
1492 | { | ||
1493 | GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); | ||
1494 | if (0 == memcmp (&pub_key, | ||
1495 | test_key, | ||
1496 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
1497 | { | ||
1498 | break; | ||
1499 | } | ||
1500 | } | ||
1501 | if (NULL == ego_entry) | ||
1502 | return GNUNET_NO; | ||
1503 | return GNUNET_YES; | ||
1504 | } | ||
1505 | |||
1506 | static void | ||
1507 | store_ticket_reference (const struct RequestHandle *handle, | ||
1508 | const char* access_token, | ||
1509 | const struct GNUNET_RECLAIM_Ticket *ticket, | ||
1510 | const struct GNUNET_CRYPTO_EcdsaPublicKey *cid) | ||
1511 | { | ||
1512 | struct GNUNET_HashCode cache_key; | ||
1513 | char *id_ticket_combination; | ||
1514 | char *ticket_string; | ||
1515 | char *client_id; | ||
1516 | |||
1517 | GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); | ||
1518 | client_id = GNUNET_STRINGS_data_to_string_alloc (cid, | ||
1519 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
1520 | ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket, | ||
1521 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
1522 | GNUNET_asprintf(&id_ticket_combination, | ||
1523 | "%s;%s", | ||
1524 | client_id, | ||
1525 | ticket_string); | ||
1526 | GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, | ||
1527 | &cache_key, | ||
1528 | id_ticket_combination, | ||
1529 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
1530 | |||
1531 | GNUNET_free (client_id); | ||
1532 | GNUNET_free (ticket_string); | ||
1533 | } | ||
1534 | |||
1535 | /** | ||
1536 | * Responds to token url-encoded POST request | ||
1537 | * | ||
1538 | * @param con_handle the connection handle | ||
1539 | * @param url the url | ||
1540 | * @param cls the RequestHandle | ||
1541 | */ | ||
1542 | static void | ||
1543 | token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | ||
1544 | const char* url, | ||
1545 | void *cls) | ||
1546 | { | ||
1547 | struct RequestHandle *handle = cls; | ||
1548 | struct GNUNET_TIME_Relative expiration_time; | ||
1549 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl; | ||
1550 | struct GNUNET_RECLAIM_Ticket *ticket; | ||
1551 | struct GNUNET_CRYPTO_EcdsaPublicKey cid; | ||
1552 | struct GNUNET_HashCode cache_key; | ||
1553 | struct MHD_Response *resp; | ||
1554 | char *grant_type; | ||
1555 | char *code; | ||
1556 | char *json_response; | ||
1557 | char *id_token; | ||
1558 | char *access_token; | ||
1559 | char *jwt_secret; | ||
1560 | char *nonce; | ||
1561 | int i = 1; | ||
1562 | |||
1563 | /* | ||
1564 | * Check Authorization | ||
1565 | */ | ||
1566 | if (GNUNET_SYSERR == check_authorization (handle, | ||
1567 | &cid)) | ||
1568 | { | ||
1569 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1570 | "OIDC authorization for token endpoint failed\n"); | ||
1665 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1571 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
1666 | return; | 1572 | return; |
1667 | } | 1573 | } |
@@ -1673,27 +1579,25 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1673 | //TODO Do not allow multiple equal parameter names | 1579 | //TODO Do not allow multiple equal parameter names |
1674 | //REQUIRED grant_type | 1580 | //REQUIRED grant_type |
1675 | GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); | 1581 | GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); |
1676 | if ( GNUNET_NO | 1582 | if (GNUNET_NO == |
1677 | == GNUNET_CONTAINER_multihashmap_contains ( | 1583 | GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, |
1678 | handle->rest_handle->url_param_map, &cache_key) ) | 1584 | &cache_key)) |
1679 | { | 1585 | { |
1680 | GNUNET_free_non_null(user_psw); | ||
1681 | handle->emsg = GNUNET_strdup("invalid_request"); | 1586 | handle->emsg = GNUNET_strdup("invalid_request"); |
1682 | handle->edesc = GNUNET_strdup("missing parameter grant_type"); | 1587 | handle->edesc = GNUNET_strdup("missing parameter grant_type"); |
1683 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1588 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
1684 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1589 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
1685 | return; | 1590 | return; |
1686 | } | 1591 | } |
1687 | grant_type = GNUNET_CONTAINER_multihashmap_get ( | 1592 | grant_type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, |
1688 | handle->rest_handle->url_param_map, &cache_key); | 1593 | &cache_key); |
1689 | 1594 | ||
1690 | //REQUIRED code | 1595 | //REQUIRED code |
1691 | GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); | 1596 | GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); |
1692 | if ( GNUNET_NO | 1597 | if (GNUNET_NO == |
1693 | == GNUNET_CONTAINER_multihashmap_contains ( | 1598 | GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, |
1694 | handle->rest_handle->url_param_map, &cache_key) ) | 1599 | &cache_key)) |
1695 | { | 1600 | { |
1696 | GNUNET_free_non_null(user_psw); | ||
1697 | handle->emsg = GNUNET_strdup("invalid_request"); | 1601 | handle->emsg = GNUNET_strdup("invalid_request"); |
1698 | handle->edesc = GNUNET_strdup("missing parameter code"); | 1602 | handle->edesc = GNUNET_strdup("missing parameter code"); |
1699 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1603 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
@@ -1706,11 +1610,10 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1706 | //REQUIRED redirect_uri | 1610 | //REQUIRED redirect_uri |
1707 | GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), | 1611 | GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), |
1708 | &cache_key); | 1612 | &cache_key); |
1709 | if ( GNUNET_NO | 1613 | if (GNUNET_NO == |
1710 | == GNUNET_CONTAINER_multihashmap_contains ( | 1614 | GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, |
1711 | handle->rest_handle->url_param_map, &cache_key) ) | 1615 | &cache_key) ) |
1712 | { | 1616 | { |
1713 | GNUNET_free_non_null(user_psw); | ||
1714 | handle->emsg = GNUNET_strdup("invalid_request"); | 1617 | handle->emsg = GNUNET_strdup("invalid_request"); |
1715 | handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); | 1618 | handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); |
1716 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1619 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
@@ -1721,21 +1624,18 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1721 | //Check parameter grant_type == "authorization_code" | 1624 | //Check parameter grant_type == "authorization_code" |
1722 | if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) | 1625 | if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) |
1723 | { | 1626 | { |
1724 | GNUNET_free_non_null(user_psw); | ||
1725 | handle->emsg=GNUNET_strdup("unsupported_grant_type"); | 1627 | handle->emsg=GNUNET_strdup("unsupported_grant_type"); |
1726 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1628 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
1727 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1629 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
1728 | return; | 1630 | return; |
1729 | } | 1631 | } |
1730 | GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); | 1632 | GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); |
1731 | int i = 1; | 1633 | if (GNUNET_SYSERR == |
1732 | if ( GNUNET_SYSERR | 1634 | GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, |
1733 | == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, | 1635 | &cache_key, |
1734 | &cache_key, | 1636 | &i, |
1735 | &i, | 1637 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) |
1736 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) | ||
1737 | { | 1638 | { |
1738 | GNUNET_free_non_null(user_psw); | ||
1739 | handle->emsg = GNUNET_strdup("invalid_request"); | 1639 | handle->emsg = GNUNET_strdup("invalid_request"); |
1740 | handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); | 1640 | handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); |
1741 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1641 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
@@ -1744,18 +1644,11 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1744 | } | 1644 | } |
1745 | 1645 | ||
1746 | //decode code | 1646 | //decode code |
1747 | struct GNUNET_CRYPTO_EcdsaPublicKey cid; | 1647 | if(GNUNET_OK != OIDC_parse_authz_code (&cid, |
1748 | GNUNET_STRINGS_string_to_data (client_id, | 1648 | code, |
1749 | strlen(client_id), | 1649 | &ticket, |
1750 | &cid, | 1650 | &nonce)) |
1751 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); | ||
1752 | struct GNUNET_RECLAIM_Ticket *ticket; | ||
1753 | if(GNUNET_OK != parse_authz_code (&cid, | ||
1754 | code, | ||
1755 | &ticket, | ||
1756 | &nonce)) | ||
1757 | { | 1651 | { |
1758 | GNUNET_free_non_null(user_psw); | ||
1759 | handle->emsg = GNUNET_strdup("invalid_request"); | 1652 | handle->emsg = GNUNET_strdup("invalid_request"); |
1760 | handle->edesc = GNUNET_strdup("invalid code"); | 1653 | handle->edesc = GNUNET_strdup("invalid code"); |
1761 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1654 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
@@ -1763,27 +1656,13 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1763 | return; | 1656 | return; |
1764 | } | 1657 | } |
1765 | 1658 | ||
1766 | // this is the current client (relying party) | ||
1767 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
1768 | GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key); | ||
1769 | if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
1770 | { | ||
1771 | GNUNET_free_non_null(user_psw); | ||
1772 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
1773 | handle->edesc = GNUNET_strdup("invalid code"); | ||
1774 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
1775 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1776 | GNUNET_free(ticket); | ||
1777 | return; | ||
1778 | } | ||
1779 | |||
1780 | //create jwt | 1659 | //create jwt |
1781 | struct GNUNET_TIME_Relative expiration_time; | 1660 | if (GNUNET_OK != |
1782 | if ( GNUNET_OK | 1661 | GNUNET_CONFIGURATION_get_value_time(cfg, |
1783 | != GNUNET_CONFIGURATION_get_value_time(cfg, "reclaim-rest-plugin", | 1662 | "reclaim-rest-plugin", |
1784 | "expiration_time", &expiration_time) ) | 1663 | "expiration_time", |
1664 | &expiration_time)) | ||
1785 | { | 1665 | { |
1786 | GNUNET_free_non_null(user_psw); | ||
1787 | handle->emsg = GNUNET_strdup("server_error"); | 1666 | handle->emsg = GNUNET_strdup("server_error"); |
1788 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); | 1667 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); |
1789 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | 1668 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
@@ -1792,34 +1671,21 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1792 | return; | 1671 | return; |
1793 | } | 1672 | } |
1794 | 1673 | ||
1795 | struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); | ||
1796 | 1674 | ||
1797 | //TODO OPTIONAL acr,amr,azp | 1675 | //TODO OPTIONAL acr,amr,azp |
1798 | 1676 | if (GNUNET_NO == ego_exists (handle, | |
1799 | struct EgoEntry *ego_entry; | 1677 | &ticket->audience)) |
1800 | for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) | ||
1801 | { | ||
1802 | GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); | ||
1803 | if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
1804 | { | ||
1805 | break; | ||
1806 | } | ||
1807 | } | ||
1808 | if ( NULL == ego_entry ) | ||
1809 | { | 1678 | { |
1810 | GNUNET_free_non_null(user_psw); | ||
1811 | handle->emsg = GNUNET_strdup("invalid_request"); | 1679 | handle->emsg = GNUNET_strdup("invalid_request"); |
1812 | handle->edesc = GNUNET_strdup("invalid code..."); | 1680 | handle->edesc = GNUNET_strdup("invalid code..."); |
1813 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 1681 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
1814 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 1682 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
1815 | GNUNET_free(ticket); | 1683 | GNUNET_free(ticket); |
1816 | return; | ||
1817 | } | 1684 | } |
1818 | if ( GNUNET_OK | 1685 | if ( GNUNET_OK |
1819 | != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", | 1686 | != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", |
1820 | "jwt_secret", &jwt_secret) ) | 1687 | "jwt_secret", &jwt_secret) ) |
1821 | { | 1688 | { |
1822 | GNUNET_free_non_null(user_psw); | ||
1823 | handle->emsg = GNUNET_strdup("invalid_request"); | 1689 | handle->emsg = GNUNET_strdup("invalid_request"); |
1824 | handle->edesc = GNUNET_strdup("No signing secret configured!"); | 1690 | handle->edesc = GNUNET_strdup("No signing secret configured!"); |
1825 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | 1691 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
@@ -1827,56 +1693,31 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1827 | GNUNET_free(ticket); | 1693 | GNUNET_free(ticket); |
1828 | return; | 1694 | return; |
1829 | } | 1695 | } |
1830 | char *id_token = jwt_create_from_list(&ticket->audience, | 1696 | //TODO We should collect the attributes here. cl always empty |
1831 | &ticket->identity, | 1697 | cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); |
1832 | cl, | 1698 | id_token = OIDC_id_token_new (&ticket->audience, |
1833 | &expiration_time, | 1699 | &ticket->identity, |
1834 | (NULL != nonce) ? nonce : NULL, | 1700 | cl, |
1835 | jwt_secret); | 1701 | &expiration_time, |
1836 | 1702 | (NULL != nonce) ? nonce : NULL, | |
1837 | //Create random access_token | 1703 | jwt_secret); |
1838 | char* access_token_number; | 1704 | access_token = OIDC_access_token_new (); |
1839 | char* access_token; | 1705 | OIDC_build_token_response (access_token, |
1840 | uint64_t random_number; | 1706 | id_token, |
1841 | random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); | 1707 | &expiration_time, |
1842 | GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number); | 1708 | &json_response); |
1843 | GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); | 1709 | |
1844 | 1710 | store_ticket_reference (handle, | |
1845 | 1711 | access_token, | |
1846 | 1712 | ticket, | |
1847 | //TODO OPTIONAL add refresh_token and scope | 1713 | &cid); |
1848 | GNUNET_asprintf (&json_response, | ||
1849 | "{ \"access_token\" : \"%s\", " | ||
1850 | "\"token_type\" : \"Bearer\", " | ||
1851 | "\"expires_in\" : %d, " | ||
1852 | "\"id_token\" : \"%s\"}", | ||
1853 | access_token, | ||
1854 | expiration_time, | ||
1855 | id_token); | ||
1856 | GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); | ||
1857 | char *id_ticket_combination; | ||
1858 | char *ticket_string; | ||
1859 | ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket, | ||
1860 | sizeof (struct GNUNET_RECLAIM_Ticket)); | ||
1861 | GNUNET_asprintf(&id_ticket_combination, | ||
1862 | "%s;%s", | ||
1863 | client_id, | ||
1864 | ticket_string); | ||
1865 | GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, | ||
1866 | &cache_key, | ||
1867 | id_ticket_combination, | ||
1868 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
1869 | |||
1870 | resp = GNUNET_REST_create_response (json_response); | 1714 | resp = GNUNET_REST_create_response (json_response); |
1871 | MHD_add_response_header (resp, "Cache-Control", "no-store"); | 1715 | MHD_add_response_header (resp, "Cache-Control", "no-store"); |
1872 | MHD_add_response_header (resp, "Pragma", "no-cache"); | 1716 | MHD_add_response_header (resp, "Pragma", "no-cache"); |
1873 | MHD_add_response_header (resp, "Content-Type", "application/json"); | 1717 | MHD_add_response_header (resp, "Content-Type", "application/json"); |
1874 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 1718 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
1875 | |||
1876 | GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl); | 1719 | GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl); |
1877 | GNUNET_free(access_token_number); | ||
1878 | GNUNET_free(access_token); | 1720 | GNUNET_free(access_token); |
1879 | GNUNET_free(user_psw); | ||
1880 | GNUNET_free(json_response); | 1721 | GNUNET_free(json_response); |
1881 | GNUNET_free(ticket); | 1722 | GNUNET_free(ticket); |
1882 | GNUNET_free(id_token); | 1723 | GNUNET_free(id_token); |