anastasis_api_policy_lookup.c (9923B)
1 /* 2 This file is part of ANASTASIS 3 Copyright (C) 2014-2019 Anastasis SARL 4 5 ANASTASIS is free software; you can redistribute it and/or modify 6 it under the terms of the GNU 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 General Public License for more details. 14 15 You should have received a copy of the GNU 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 restclient/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 struct ANASTASIS_DownloadDetails dd = { 110 .http_status = response_code 111 }; 112 113 plo->job = NULL; 114 switch (response_code) 115 { 116 case 0: 117 /* Hard error */ 118 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 119 "Backend didn't even return from GET /policy\n"); 120 break; 121 case MHD_HTTP_OK: 122 { 123 struct ANASTASIS_UploadSignaturePS usp = { 124 .purpose.purpose = htonl (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD), 125 .purpose.size = htonl (sizeof (usp)), 126 }; 127 128 GNUNET_CRYPTO_hash (data, 129 data_size, 130 &usp.new_recovery_data_hash); 131 if (GNUNET_OK != 132 GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD, 133 &usp, 134 &plo->account_sig.eddsa_sig, 135 &plo->account_pub.pub)) 136 { 137 GNUNET_break_op (0); 138 dd.http_status = 0; 139 dd.ec = -1; // FIXME: needs new code in Gana! 140 break; 141 } 142 /* Success, call callback with all details! */ 143 dd.details.ok.sig = plo->account_sig; 144 dd.details.ok.curr_policy_hash = usp.new_recovery_data_hash; 145 dd.details.ok.policy = data; 146 dd.details.ok.policy_size = data_size; 147 dd.details.ok.version = plo->version; 148 plo->cb (plo->cb_cls, 149 &dd); 150 plo->cb = NULL; 151 ANASTASIS_policy_lookup_cancel (plo); 152 return; 153 } 154 case MHD_HTTP_BAD_REQUEST: 155 /* This should never happen, either us or the anastasis server is buggy 156 (or API version conflict); just pass JSON reply to the application */ 157 break; 158 case MHD_HTTP_NOT_FOUND: 159 /* Nothing really to verify */ 160 break; 161 case MHD_HTTP_INTERNAL_SERVER_ERROR: 162 /* Server had an internal issue; we should retry, but this API 163 leaves this to the application */ 164 break; 165 default: 166 /* unexpected response code */ 167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 168 "Unexpected response code %u\n", 169 (unsigned int) response_code); 170 GNUNET_break (0); 171 break; 172 } 173 plo->cb (plo->cb_cls, 174 &dd); 175 plo->cb = NULL; 176 ANASTASIS_policy_lookup_cancel (plo); 177 } 178 179 180 /** 181 * Handle HTTP header received by curl. 182 * 183 * @param buffer one line of HTTP header data 184 * @param size size of an item 185 * @param nitems number of items passed 186 * @param userdata our `struct ANASTASIS_PolicyLookupOperation *` 187 * @return `size * nitems` 188 */ 189 static size_t 190 handle_header (char *buffer, 191 size_t size, 192 size_t nitems, 193 void *userdata) 194 { 195 struct ANASTASIS_PolicyLookupOperation *plo = userdata; 196 size_t total = size * nitems; 197 char *ndup; 198 const char *hdr_type; 199 char *hdr_val; 200 char *sp; 201 202 ndup = GNUNET_strndup (buffer, 203 total); 204 hdr_type = strtok_r (ndup, 205 ":", 206 &sp); 207 if (NULL == hdr_type) 208 { 209 GNUNET_free (ndup); 210 return total; 211 } 212 hdr_val = strtok_r (NULL, 213 "\n\r", 214 &sp); 215 if (NULL == hdr_val) 216 { 217 GNUNET_free (ndup); 218 return total; 219 } 220 if (' ' == *hdr_val) 221 hdr_val++; 222 if (0 == strcasecmp (hdr_type, 223 ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE)) 224 { 225 if (GNUNET_OK != 226 GNUNET_STRINGS_string_to_data ( 227 hdr_val, 228 strlen (hdr_val), 229 &plo->account_sig, 230 sizeof (struct ANASTASIS_AccountSignatureP))) 231 { 232 GNUNET_break_op (0); 233 GNUNET_free (ndup); 234 return 0; 235 } 236 } 237 if (0 == strcasecmp (hdr_type, 238 ANASTASIS_HTTP_HEADER_POLICY_VERSION)) 239 { 240 char dummy; 241 242 if (1 != 243 sscanf (hdr_val, 244 "%u%c", 245 &plo->version, 246 &dummy)) 247 { 248 GNUNET_break_op (0); 249 GNUNET_free (ndup); 250 return 0; 251 } 252 } 253 GNUNET_free (ndup); 254 return total; 255 } 256 257 258 struct ANASTASIS_PolicyLookupOperation * 259 ANASTASIS_policy_lookup ( 260 struct GNUNET_CURL_Context *ctx, 261 const char *backend_url, 262 const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub, 263 ANASTASIS_PolicyLookupCallback cb, 264 void *cb_cls) 265 { 266 struct ANASTASIS_PolicyLookupOperation *plo; 267 CURL *eh; 268 char *acc_pub_str; 269 char *path; 270 271 GNUNET_assert (NULL != cb); 272 plo = GNUNET_new (struct ANASTASIS_PolicyLookupOperation); 273 plo->account_pub = *anastasis_pub; 274 acc_pub_str = GNUNET_STRINGS_data_to_string_alloc (anastasis_pub, 275 sizeof (*anastasis_pub)); 276 GNUNET_asprintf (&path, 277 "policy/%s", 278 acc_pub_str); 279 GNUNET_free (acc_pub_str); 280 plo->url = TALER_url_join (backend_url, 281 path, 282 NULL); 283 GNUNET_free (path); 284 eh = ANASTASIS_curl_easy_get_ (plo->url); 285 if (NULL == eh) 286 { 287 GNUNET_break (0); 288 GNUNET_free (plo->url); 289 GNUNET_free (plo); 290 return NULL; 291 } 292 GNUNET_assert (CURLE_OK == 293 curl_easy_setopt (eh, 294 CURLOPT_HEADERFUNCTION, 295 &handle_header)); 296 GNUNET_assert (CURLE_OK == 297 curl_easy_setopt (eh, 298 CURLOPT_HEADERDATA, 299 plo)); 300 plo->cb = cb; 301 plo->cb_cls = cb_cls; 302 plo->job = GNUNET_CURL_job_add_raw (ctx, 303 eh, 304 NULL, 305 &handle_policy_lookup_finished, 306 plo); 307 return plo; 308 } 309 310 311 struct ANASTASIS_PolicyLookupOperation * 312 ANASTASIS_policy_lookup_version ( 313 struct GNUNET_CURL_Context *ctx, 314 const char *backend_url, 315 const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub, 316 ANASTASIS_PolicyLookupCallback cb, 317 void *cb_cls, 318 unsigned int version) 319 { 320 struct ANASTASIS_PolicyLookupOperation *plo; 321 CURL *eh; 322 char *acc_pub_str; 323 char *path; 324 char version_s[14]; 325 326 GNUNET_assert (NULL != cb); 327 plo = GNUNET_new (struct ANASTASIS_PolicyLookupOperation); 328 plo->account_pub = *anastasis_pub; 329 acc_pub_str = GNUNET_STRINGS_data_to_string_alloc (anastasis_pub, 330 sizeof (*anastasis_pub)); 331 GNUNET_asprintf (&path, 332 "policy/%s", 333 acc_pub_str); 334 GNUNET_free (acc_pub_str); 335 GNUNET_snprintf (version_s, 336 sizeof (version_s), 337 "%u", 338 version); 339 plo->url = TALER_url_join (backend_url, 340 path, 341 "version", 342 version_s, 343 NULL); 344 GNUNET_free (path); 345 eh = ANASTASIS_curl_easy_get_ (plo->url); 346 GNUNET_assert (CURLE_OK == 347 curl_easy_setopt (eh, 348 CURLOPT_HEADERFUNCTION, 349 &handle_header)); 350 GNUNET_assert (CURLE_OK == 351 curl_easy_setopt (eh, 352 CURLOPT_HEADERDATA, 353 plo)); 354 plo->cb = cb; 355 plo->cb_cls = cb_cls; 356 plo->job = GNUNET_CURL_job_add_raw (ctx, 357 eh, 358 NULL, 359 &handle_policy_lookup_finished, 360 plo); 361 return plo; 362 }