diff options
Diffstat (limited to 'src/restclient/anastasis_api_policy_lookup.c')
-rw-r--r-- | src/restclient/anastasis_api_policy_lookup.c | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/src/restclient/anastasis_api_policy_lookup.c b/src/restclient/anastasis_api_policy_lookup.c new file mode 100644 index 0000000..1af95d7 --- /dev/null +++ b/src/restclient/anastasis_api_policy_lookup.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | This file is part of ANASTASIS | ||
3 | Copyright (C) 2014-2019 GNUnet e.V. and INRIA | ||
4 | |||
5 | ANASTASIS is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU Lesser General Public License as | ||
7 | published by the Free Software Foundation; either version 2.1, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | ANASTASIS 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 | ||
13 | GNU Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with ANASTASIS; see the file COPYING.LGPL. If not, | ||
17 | see <http://www.gnu.org/licenses/> | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file lib/anastasis_api_policy_lookup.c | ||
22 | * @brief Implementation of the /policy GET and POST | ||
23 | * @author Christian Grothoff | ||
24 | * @author Dennis Neufeld | ||
25 | * @author Dominik Meister | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include <curl/curl.h> | ||
29 | #include <jansson.h> | ||
30 | #include <microhttpd.h> /* just for HTTP status codes */ | ||
31 | #include "anastasis_service.h" | ||
32 | #include "anastasis_api_curl_defaults.h" | ||
33 | #include <taler/taler_signatures.h> | ||
34 | |||
35 | |||
36 | /** | ||
37 | * @brief A Contract Operation Handle | ||
38 | */ | ||
39 | struct ANASTASIS_PolicyLookupOperation | ||
40 | { | ||
41 | |||
42 | /** | ||
43 | * The url for this request, including parameters. | ||
44 | */ | ||
45 | char *url; | ||
46 | |||
47 | /** | ||
48 | * Handle for the request. | ||
49 | */ | ||
50 | struct GNUNET_CURL_Job *job; | ||
51 | |||
52 | /** | ||
53 | * Function to call with the result. | ||
54 | */ | ||
55 | ANASTASIS_PolicyLookupCallback cb; | ||
56 | |||
57 | /** | ||
58 | * Closure for @a cb. | ||
59 | */ | ||
60 | void *cb_cls; | ||
61 | |||
62 | /** | ||
63 | * Reference to the execution context. | ||
64 | */ | ||
65 | struct GNUNET_CURL_Context *ctx; | ||
66 | |||
67 | /** | ||
68 | * Public key of the account we are downloading from. | ||
69 | */ | ||
70 | struct ANASTASIS_CRYPTO_AccountPublicKeyP account_pub; | ||
71 | |||
72 | /** | ||
73 | * Signature returned in the #ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE | ||
74 | * header, or all zeros for none. | ||
75 | */ | ||
76 | struct ANASTASIS_AccountSignatureP account_sig; | ||
77 | |||
78 | /** | ||
79 | * Version of the policy. | ||
80 | */ | ||
81 | unsigned int version; | ||
82 | |||
83 | }; | ||
84 | |||
85 | |||
86 | void | ||
87 | ANASTASIS_policy_lookup_cancel (struct ANASTASIS_PolicyLookupOperation *plo) | ||
88 | { | ||
89 | if (NULL != plo->job) | ||
90 | { | ||
91 | GNUNET_CURL_job_cancel (plo->job); | ||
92 | plo->job = NULL; | ||
93 | } | ||
94 | GNUNET_free (plo->url); | ||
95 | GNUNET_free (plo); | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Process GET /policy response | ||
101 | */ | ||
102 | static void | ||
103 | handle_policy_lookup_finished (void *cls, | ||
104 | long response_code, | ||
105 | const void *data, | ||
106 | size_t data_size) | ||
107 | { | ||
108 | struct ANASTASIS_PolicyLookupOperation *plo = cls; | ||
109 | |||
110 | plo->job = NULL; | ||
111 | switch (response_code) | ||
112 | { | ||
113 | case 0: | ||
114 | /* Hard error */ | ||
115 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
116 | "Backend didn't even return from GET /policy\n"); | ||
117 | break; | ||
118 | case MHD_HTTP_OK: | ||
119 | { | ||
120 | struct ANASTASIS_DownloadDetails dd; | ||
121 | struct ANASTASIS_UploadSignaturePS usp = { | ||
122 | .purpose.purpose = htonl (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD), | ||
123 | .purpose.size = htonl (sizeof (usp)), | ||
124 | }; | ||
125 | |||
126 | GNUNET_CRYPTO_hash (data, | ||
127 | data_size, | ||
128 | &usp.new_recovery_data_hash); | ||
129 | if (GNUNET_OK != | ||
130 | GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD, | ||
131 | &usp, | ||
132 | &plo->account_sig.eddsa_sig, | ||
133 | &plo->account_pub.pub)) | ||
134 | { | ||
135 | GNUNET_break_op (0); | ||
136 | response_code = 0; | ||
137 | break; | ||
138 | } | ||
139 | /* Success, call callback with all details! */ | ||
140 | memset (&dd, 0, sizeof (dd)); | ||
141 | dd.sig = plo->account_sig; | ||
142 | dd.curr_policy_hash = usp.new_recovery_data_hash; | ||
143 | dd.policy = data; | ||
144 | dd.policy_size = data_size; | ||
145 | dd.version = plo->version; | ||
146 | plo->cb (plo->cb_cls, | ||
147 | response_code, | ||
148 | &dd); | ||
149 | plo->cb = NULL; | ||
150 | ANASTASIS_policy_lookup_cancel (plo); | ||
151 | return; | ||
152 | } | ||
153 | case MHD_HTTP_BAD_REQUEST: | ||
154 | /* This should never happen, either us or the anastasis server is buggy | ||
155 | (or API version conflict); just pass JSON reply to the application */ | ||
156 | break; | ||
157 | case MHD_HTTP_NOT_FOUND: | ||
158 | /* Nothing really to verify */ | ||
159 | break; | ||
160 | case MHD_HTTP_INTERNAL_SERVER_ERROR: | ||
161 | /* Server had an internal issue; we should retry, but this API | ||
162 | leaves this to the application */ | ||
163 | break; | ||
164 | default: | ||
165 | /* unexpected response code */ | ||
166 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
167 | "Unexpected response code %u\n", | ||
168 | (unsigned int) response_code); | ||
169 | GNUNET_break (0); | ||
170 | response_code = 0; | ||
171 | break; | ||
172 | } | ||
173 | plo->cb (plo->cb_cls, | ||
174 | response_code, | ||
175 | NULL); | ||
176 | plo->cb = NULL; | ||
177 | ANASTASIS_policy_lookup_cancel (plo); | ||
178 | } | ||
179 | |||
180 | |||
181 | /** | ||
182 | * Handle HTTP header received by curl. | ||
183 | * | ||
184 | * @param buffer one line of HTTP header data | ||
185 | * @param size size of an item | ||
186 | * @param nitems number of items passed | ||
187 | * @param userdata our `struct ANASTASIS_PolicyLookupOperation *` | ||
188 | * @return `size * nitems` | ||
189 | */ | ||
190 | static size_t | ||
191 | handle_header (char *buffer, | ||
192 | size_t size, | ||
193 | size_t nitems, | ||
194 | void *userdata) | ||
195 | { | ||
196 | struct ANASTASIS_PolicyLookupOperation *plo = userdata; | ||
197 | size_t total = size * nitems; | ||
198 | char *ndup; | ||
199 | const char *hdr_type; | ||
200 | char *hdr_val; | ||
201 | char *sp; | ||
202 | |||
203 | ndup = GNUNET_strndup (buffer, | ||
204 | total); | ||
205 | hdr_type = strtok_r (ndup, | ||
206 | ":", | ||
207 | &sp); | ||
208 | if (NULL == hdr_type) | ||
209 | { | ||
210 | GNUNET_free (ndup); | ||
211 | return total; | ||
212 | } | ||
213 | hdr_val = strtok_r (NULL, | ||
214 | "\n\r", | ||
215 | &sp); | ||
216 | if (NULL == hdr_val) | ||
217 | { | ||
218 | GNUNET_free (ndup); | ||
219 | return total; | ||
220 | } | ||
221 | if (' ' == *hdr_val) | ||
222 | hdr_val++; | ||
223 | if (0 == strcasecmp (hdr_type, | ||
224 | ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE)) | ||
225 | { | ||
226 | if (GNUNET_OK != | ||
227 | GNUNET_STRINGS_string_to_data ( | ||
228 | hdr_val, | ||
229 | strlen (hdr_val), | ||
230 | &plo->account_sig, | ||
231 | sizeof (struct ANASTASIS_AccountSignatureP))) | ||
232 | { | ||
233 | GNUNET_break_op (0); | ||
234 | GNUNET_free (ndup); | ||
235 | return 0; | ||
236 | } | ||
237 | } | ||
238 | if (0 == strcasecmp (hdr_type, | ||
239 | ANASTASIS_HTTP_HEADER_POLICY_VERSION)) | ||
240 | { | ||
241 | char dummy; | ||
242 | |||
243 | if (1 != | ||
244 | sscanf (hdr_val, | ||
245 | "%u%c", | ||
246 | &plo->version, | ||
247 | &dummy)) | ||
248 | { | ||
249 | GNUNET_break_op (0); | ||
250 | GNUNET_free (ndup); | ||
251 | return 0; | ||
252 | } | ||
253 | } | ||
254 | GNUNET_free (ndup); | ||
255 | return total; | ||
256 | } | ||
257 | |||
258 | |||
259 | struct ANASTASIS_PolicyLookupOperation * | ||
260 | ANASTASIS_policy_lookup ( | ||
261 | struct GNUNET_CURL_Context *ctx, | ||
262 | const char *backend_url, | ||
263 | const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub, | ||
264 | ANASTASIS_PolicyLookupCallback cb, | ||
265 | void *cb_cls) | ||
266 | { | ||
267 | struct ANASTASIS_PolicyLookupOperation *plo; | ||
268 | CURL *eh; | ||
269 | char *acc_pub_str; | ||
270 | char *path; | ||
271 | |||
272 | GNUNET_assert (NULL != cb); | ||
273 | plo = GNUNET_new (struct ANASTASIS_PolicyLookupOperation); | ||
274 | plo->account_pub = *anastasis_pub; | ||
275 | acc_pub_str = GNUNET_STRINGS_data_to_string_alloc (anastasis_pub, | ||
276 | sizeof (*anastasis_pub)); | ||
277 | GNUNET_asprintf (&path, | ||
278 | "policy/%s", | ||
279 | acc_pub_str); | ||
280 | GNUNET_free (acc_pub_str); | ||
281 | plo->url = TALER_url_join (backend_url, | ||
282 | path, | ||
283 | NULL); | ||
284 | GNUNET_free (path); | ||
285 | eh = ANASTASIS_curl_easy_get_ (plo->url); | ||
286 | GNUNET_assert (CURLE_OK == | ||
287 | curl_easy_setopt (eh, | ||
288 | CURLOPT_HEADERFUNCTION, | ||
289 | &handle_header)); | ||
290 | GNUNET_assert (CURLE_OK == | ||
291 | curl_easy_setopt (eh, | ||
292 | CURLOPT_HEADERDATA, | ||
293 | plo)); | ||
294 | plo->cb = cb; | ||
295 | plo->cb_cls = cb_cls; | ||
296 | plo->job = GNUNET_CURL_job_add_raw (ctx, | ||
297 | eh, | ||
298 | GNUNET_NO, | ||
299 | &handle_policy_lookup_finished, | ||
300 | plo); | ||
301 | return plo; | ||
302 | } | ||
303 | |||
304 | |||
305 | struct ANASTASIS_PolicyLookupOperation * | ||
306 | ANASTASIS_policy_lookup_version ( | ||
307 | struct GNUNET_CURL_Context *ctx, | ||
308 | const char *backend_url, | ||
309 | const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub, | ||
310 | ANASTASIS_PolicyLookupCallback cb, | ||
311 | void *cb_cls, | ||
312 | unsigned int version) | ||
313 | { | ||
314 | struct ANASTASIS_PolicyLookupOperation *plo; | ||
315 | CURL *eh; | ||
316 | char *acc_pub_str; | ||
317 | char *path; | ||
318 | char version_s[14]; | ||
319 | |||
320 | GNUNET_assert (NULL != cb); | ||
321 | plo = GNUNET_new (struct ANASTASIS_PolicyLookupOperation); | ||
322 | plo->account_pub = *anastasis_pub; | ||
323 | acc_pub_str = GNUNET_STRINGS_data_to_string_alloc (anastasis_pub, | ||
324 | sizeof (*anastasis_pub)); | ||
325 | GNUNET_asprintf (&path, | ||
326 | "policy/%s", | ||
327 | acc_pub_str); | ||
328 | GNUNET_free (acc_pub_str); | ||
329 | GNUNET_snprintf (version_s, | ||
330 | sizeof (version_s), | ||
331 | "%u", | ||
332 | version); | ||
333 | plo->url = TALER_url_join (backend_url, | ||
334 | path, | ||
335 | "version", | ||
336 | version_s, | ||
337 | NULL); | ||
338 | GNUNET_free (path); | ||
339 | eh = ANASTASIS_curl_easy_get_ (plo->url); | ||
340 | GNUNET_assert (CURLE_OK == | ||
341 | curl_easy_setopt (eh, | ||
342 | CURLOPT_HEADERFUNCTION, | ||
343 | &handle_header)); | ||
344 | GNUNET_assert (CURLE_OK == | ||
345 | curl_easy_setopt (eh, | ||
346 | CURLOPT_HEADERDATA, | ||
347 | plo)); | ||
348 | plo->cb = cb; | ||
349 | plo->cb_cls = cb_cls; | ||
350 | plo->job = GNUNET_CURL_job_add_raw (ctx, | ||
351 | eh, | ||
352 | GNUNET_NO, | ||
353 | &handle_policy_lookup_finished, | ||
354 | plo); | ||
355 | return plo; | ||
356 | } | ||