2 This file is part of GNUnet.
3 Copyright (C) 2012-2016 GNUnet e.V.
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.
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.
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.
21 * @author Martin Schanzenbach
22 * @file gns/plugin_rest_credential.c
23 * @brief GNUnet CREDENTIAL REST plugin
28 #include "gnunet_rest_plugin.h"
29 #include <gnunet_identity_service.h>
30 #include <gnunet_gnsrecord_lib.h>
31 #include <gnunet_namestore_service.h>
32 #include <gnunet_credential_service.h>
33 #include <gnunet_rest_lib.h>
34 #include <gnunet_jsonapi_lib.h>
35 #include <gnunet_jsonapi_util.h>
38 #define GNUNET_REST_API_NS_CREDENTIAL "/credential"
40 #define GNUNET_REST_JSONAPI_CREDENTIAL "credential"
42 #define GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO "credential"
44 #define GNUNET_REST_JSONAPI_CREDENTIAL_CHAIN "chain"
46 #define GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR "attribute"
48 #define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR "credential"
51 * @brief struct returned by the initialization function of the plugin
55 const struct GNUNET_CONFIGURATION_Handle *cfg;
58 const struct GNUNET_CONFIGURATION_Handle *cfg;
63 * Handle to Credential service.
65 struct GNUNET_CREDENTIAL_Handle *credential;
68 * Handle to lookup request
70 struct GNUNET_CREDENTIAL_Request *verify_request;
73 * Handle to rest request
75 struct GNUNET_REST_RequestHandle *rest_handle;
78 * ID of a task associated with the resolution process.
80 struct GNUNET_SCHEDULER_Task * timeout_task;
83 * The root of the received JSON or NULL
88 * The plugin result processor
90 GNUNET_REST_ResultProcessor proc;
93 * The closure of the result processor
98 * The issuer attribute to verify
103 * The subject attribute
108 * The public key of the issuer
110 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
113 * The public key of the subject
115 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
125 struct GNUNET_TIME_Relative timeout;
131 * Cleanup lookup handle.
133 * @param handle Handle to clean up
136 cleanup_handle (struct VerifyHandle *handle)
138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
140 if (NULL != handle->json_root)
141 json_decref (handle->json_root);
143 if (NULL != handle->issuer_attr)
144 GNUNET_free (handle->issuer_attr);
145 if (NULL != handle->subject_attr)
146 GNUNET_free (handle->subject_attr);
147 if (NULL != handle->verify_request)
149 GNUNET_CREDENTIAL_verify_cancel (handle->verify_request);
150 handle->verify_request = NULL;
152 if (NULL != handle->credential)
154 GNUNET_CREDENTIAL_disconnect (handle->credential);
155 handle->credential = NULL;
158 if (NULL != handle->timeout_task)
160 GNUNET_SCHEDULER_cancel (handle->timeout_task);
162 GNUNET_free (handle);
167 * Task run on shutdown. Cleans up everything.
170 * @param tc scheduler context
175 struct VerifyHandle *handle = cls;
176 struct MHD_Response *resp;
178 resp = GNUNET_REST_create_response (NULL);
179 handle->proc (handle->proc_cls, resp, handle->response_code);
180 cleanup_handle (handle);
184 * Attribute delegation to JSON
185 * @param attr the attribute
186 * @return JSON, NULL if failed
189 attribute_delegation_to_json (struct GNUNET_CREDENTIAL_Delegation *delegation_chain_entry)
193 char iss_attribute[delegation_chain_entry->issuer_attribute_len];
194 char sub_attribute[delegation_chain_entry->subject_attribute_len];
197 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->issuer_key);
199 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
200 "Issuer in delegation malformed\n");
203 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->subject_key);
205 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
206 "Subject in credential malformed\n");
207 GNUNET_free (issuer);
210 attr_obj = json_object ();
211 memcpy (iss_attribute,
212 delegation_chain_entry->issuer_attribute,
213 delegation_chain_entry->issuer_attribute_len);
214 iss_attribute[delegation_chain_entry->issuer_attribute_len] = '\0';
216 json_object_set_new (attr_obj, "subject", json_string (subject));
217 json_object_set_new (attr_obj, "issuer", json_string (issuer));
218 json_object_set_new (attr_obj, "issuer_attribute", json_string (iss_attribute));
220 if (0 < delegation_chain_entry->subject_attribute_len)
222 memcpy (sub_attribute,
223 delegation_chain_entry->subject_attribute,
224 delegation_chain_entry->subject_attribute_len);
225 sub_attribute[delegation_chain_entry->subject_attribute_len] = '\0';
226 json_object_set_new (attr_obj, "subject_attribute", json_string (sub_attribute));
228 GNUNET_free (subject);
234 * @param cred the credential
235 * @return the resulting json, NULL if failed
238 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
242 char attribute[cred->issuer_attribute_len + 1];
245 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249 "Issuer in credential malformed\n");
252 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
256 "Subject in credential malformed\n");
257 GNUNET_free (issuer);
261 cred->issuer_attribute,
262 cred->issuer_attribute_len);
263 attribute[cred->issuer_attribute_len] = '\0';
264 cred_obj = json_object ();
265 json_object_set_new (cred_obj, "issuer", json_string (issuer));
266 json_object_set_new (cred_obj, "subject", json_string (subject));
267 json_object_set_new (cred_obj, "attribute", json_string (attribute));
268 GNUNET_free (issuer);
269 GNUNET_free (subject);
274 * Function called with the result of a Credential lookup.
276 * @param cls the 'const char *' name that was resolved
277 * @param cd_count number of records returned
278 * @param cd array of @a cd_count records with the results
281 handle_verify_response (void *cls,
282 unsigned int d_count,
283 struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
284 struct GNUNET_CREDENTIAL_Credential *cred)
287 struct VerifyHandle *handle = cls;
288 struct MHD_Response *resp;
289 struct GNUNET_JSONAPI_Document *json_document;
290 struct GNUNET_JSONAPI_Resource *json_resource;
293 json_t *result_array;
297 handle->verify_request = NULL;
299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
301 handle->response_code = MHD_HTTP_NOT_FOUND;
302 GNUNET_SCHEDULER_add_now (&do_error, handle);
305 json_document = GNUNET_JSONAPI_document_new ();
306 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
307 handle->issuer_attr);
308 cred_obj = credential_to_json (cred);
309 result_array = json_array ();
310 for (i = 0; i < d_count; i++)
312 attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
313 json_array_append (result_array, attr_obj);
314 json_decref (attr_obj);
316 GNUNET_JSONAPI_resource_add_attr (json_resource,
317 GNUNET_REST_JSONAPI_CREDENTIAL,
319 GNUNET_JSONAPI_resource_add_attr (json_resource,
320 GNUNET_REST_JSONAPI_CREDENTIAL_CHAIN,
322 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
323 GNUNET_JSONAPI_document_serialize (json_document, &result);
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
327 json_decref (result_array);
328 GNUNET_JSONAPI_document_delete (json_document);
329 resp = GNUNET_REST_create_response (result);
330 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
331 GNUNET_free (result);
332 cleanup_handle (handle);
337 verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
341 struct VerifyHandle *handle = cls;
342 struct GNUNET_HashCode key;
346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
348 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
349 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 if (NULL == handle->credential)
355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
356 "Connecting to CREDENTIAL failed\n");
357 GNUNET_SCHEDULER_add_now (&do_error, handle);
360 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
361 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
364 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
368 "Missing issuer attribute\n");
369 GNUNET_SCHEDULER_add_now (&do_error, handle);
372 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
374 entity_attr = GNUNET_strdup (tmp);
375 tmp = strtok(entity_attr, ".");
378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
379 "Malformed issuer or attribute\n");
380 GNUNET_free (entity_attr);
381 GNUNET_SCHEDULER_add_now (&do_error, handle);
385 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
387 &handle->issuer_key))
389 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
390 "Malformed issuer key\n");
391 GNUNET_free (entity_attr);
392 GNUNET_SCHEDULER_add_now (&do_error, handle);
395 tmp = strtok (NULL, "."); //Issuer attribute
398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
399 "Malformed attribute\n");
400 GNUNET_free (entity_attr);
401 GNUNET_SCHEDULER_add_now (&do_error, handle);
404 handle->issuer_attr = GNUNET_strdup (tmp);
405 GNUNET_free (entity_attr);
407 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR,
408 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR),
411 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
414 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
415 "Missing subject or attribute\n");
416 GNUNET_free (entity_attr);
417 GNUNET_SCHEDULER_add_now (&do_error, handle);
420 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
422 entity_attr = GNUNET_strdup (tmp);
423 tmp = strtok(entity_attr, ".");
426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427 "Malformed subject\n");
428 GNUNET_free (entity_attr);
429 GNUNET_SCHEDULER_add_now (&do_error, handle);
433 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
435 &handle->subject_key)) {
436 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
437 "Malformed subject key\n");
438 GNUNET_free (entity_attr);
439 GNUNET_SCHEDULER_add_now (&do_error, handle);
442 tmp = strtok (NULL, ".");
445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
446 "Malformed subject attribute\n");
447 GNUNET_free (entity_attr);
448 GNUNET_SCHEDULER_add_now (&do_error, handle);
451 handle->subject_attr = GNUNET_strdup (tmp);
452 GNUNET_free (entity_attr);
454 handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
457 &handle->subject_key,
458 handle->subject_attr,
459 &handle_verify_response,
465 * Handle rest request
467 * @param handle the lookup handle
470 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
474 struct MHD_Response *resp;
475 struct VerifyHandle *handle = cls;
477 //For GNS, independent of path return all options
478 resp = GNUNET_REST_create_response (NULL);
479 MHD_add_response_header (resp,
480 "Access-Control-Allow-Methods",
481 MHD_HTTP_METHOD_GET);
482 handle->proc (handle->proc_cls,
485 cleanup_handle (handle);
490 * Function processing the REST call
492 * @param method HTTP method
493 * @param url URL of the HTTP request
494 * @param data body of the HTTP request (optional)
495 * @param data_size length of the body
496 * @param proc callback function for the result
497 * @param proc_cls closure for callback function
498 * @return GNUNET_OK if request accepted
501 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
502 GNUNET_REST_ResultProcessor proc,
505 struct VerifyHandle *handle = GNUNET_new (struct VerifyHandle);
506 struct GNUNET_REST_RequestHandlerError err;
508 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
509 handle->proc_cls = proc_cls;
511 handle->rest_handle = conndata_handle;
513 static const struct GNUNET_REST_RequestHandler handlers[] = {
514 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL, &verify_cred_cont},
515 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
516 GNUNET_REST_HANDLER_END
519 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
524 handle->response_code = err.error_code;
525 GNUNET_SCHEDULER_add_now (&do_error, handle);
531 * Entry point for the plugin.
533 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
534 * @return NULL on error, otherwise the plugin context
537 libgnunet_plugin_rest_credential_init (void *cls)
539 static struct Plugin plugin;
541 struct GNUNET_REST_Plugin *api;
543 if (NULL != plugin.cfg)
544 return NULL; /* can only initialize once! */
545 memset (&plugin, 0, sizeof (struct Plugin));
547 api = GNUNET_new (struct GNUNET_REST_Plugin);
549 api->name = GNUNET_REST_API_NS_CREDENTIAL;
550 api->process_request = &rest_credential_process_request;
551 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
552 _("GNS REST API initialized\n"));
558 * Exit point from the plugin.
560 * @param cls the plugin context (as returned by "init")
561 * @return always NULL
564 libgnunet_plugin_rest_credential_done (void *cls)
566 struct GNUNET_REST_Plugin *api = cls;
567 struct Plugin *plugin = api->cls;
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
572 "GNS REST plugin is finished\n");
576 /* end of plugin_rest_gns.c */