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_DELEGATIONS "delegations"
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)
195 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->issuer_key);
197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198 "Issuer in delegation malformed\n");
201 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->subject_key);
203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
204 "Subject in credential malformed\n");
205 GNUNET_free (issuer);
208 attr_obj = json_object ();
210 json_object_set_new (attr_obj, "subject", json_string (subject));
211 json_object_set_new (attr_obj, "issuer", json_string (issuer));
212 json_object_set_new (attr_obj, "issuer_attribute",
213 json_string (delegation_chain_entry->issuer_attribute));
215 if (0 < delegation_chain_entry->subject_attribute_len)
217 json_object_set_new (attr_obj, "subject_attribute",
218 json_string (delegation_chain_entry->subject_attribute));
220 GNUNET_free (subject);
226 * @param cred the credential
227 * @return the resulting json, NULL if failed
230 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
234 char attribute[cred->issuer_attribute_len + 1];
237 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
241 "Issuer in credential malformed\n");
244 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
247 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
248 "Subject in credential malformed\n");
249 GNUNET_free (issuer);
253 cred->issuer_attribute,
254 cred->issuer_attribute_len);
255 attribute[cred->issuer_attribute_len] = '\0';
256 cred_obj = json_object ();
257 json_object_set_new (cred_obj, "issuer", json_string (issuer));
258 json_object_set_new (cred_obj, "subject", json_string (subject));
259 json_object_set_new (cred_obj, "attribute", json_string (attribute));
260 GNUNET_free (issuer);
261 GNUNET_free (subject);
266 * Function called with the result of a Credential lookup.
268 * @param cls the 'const char *' name that was resolved
269 * @param cd_count number of records returned
270 * @param cd array of @a cd_count records with the results
273 handle_verify_response (void *cls,
274 unsigned int d_count,
275 struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
276 unsigned int c_count,
277 struct GNUNET_CREDENTIAL_Credential *cred)
280 struct VerifyHandle *handle = cls;
281 struct MHD_Response *resp;
282 struct GNUNET_JSONAPI_Document *json_document;
283 struct GNUNET_JSONAPI_Resource *json_resource;
291 handle->verify_request = NULL;
293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
295 handle->response_code = MHD_HTTP_NOT_FOUND;
296 GNUNET_SCHEDULER_add_now (&do_error, handle);
299 json_document = GNUNET_JSONAPI_document_new ();
300 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
301 handle->issuer_attr);
302 cred_obj = credential_to_json (cred);
303 attr_array = json_array ();
304 for (i = 0; i < d_count; i++)
306 attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
307 json_array_append (attr_array, attr_obj);
308 json_decref (attr_obj);
310 cred_array = json_array ();
311 for (i=0;i<c_count;i++)
313 cred_obj = credential_to_json (&cred[i]);
314 json_array_append (cred_array, cred_obj);
315 json_decref (cred_obj);
317 GNUNET_JSONAPI_resource_add_attr (json_resource,
318 GNUNET_REST_JSONAPI_CREDENTIAL,
320 GNUNET_JSONAPI_resource_add_attr (json_resource,
321 GNUNET_REST_JSONAPI_DELEGATIONS,
323 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
324 GNUNET_JSONAPI_document_serialize (json_document, &result);
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
328 json_decref (attr_array);
329 json_decref (cred_array);
330 GNUNET_JSONAPI_document_delete (json_document);
331 resp = GNUNET_REST_create_response (result);
332 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
333 GNUNET_free (result);
334 cleanup_handle (handle);
339 verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
343 struct VerifyHandle *handle = cls;
344 struct GNUNET_HashCode key;
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
350 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
351 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 if (NULL == handle->credential)
357 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
358 "Connecting to CREDENTIAL failed\n");
359 GNUNET_SCHEDULER_add_now (&do_error, handle);
362 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
363 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
366 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 "Missing issuer attribute\n");
371 GNUNET_SCHEDULER_add_now (&do_error, handle);
374 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
376 entity_attr = GNUNET_strdup (tmp);
377 tmp = strtok(entity_attr, ".");
380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
381 "Malformed issuer or attribute\n");
382 GNUNET_free (entity_attr);
383 GNUNET_SCHEDULER_add_now (&do_error, handle);
387 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
389 &handle->issuer_key))
391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392 "Malformed issuer key\n");
393 GNUNET_free (entity_attr);
394 GNUNET_SCHEDULER_add_now (&do_error, handle);
397 tmp = strtok (NULL, "."); //Issuer attribute
400 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
401 "Malformed attribute\n");
402 GNUNET_free (entity_attr);
403 GNUNET_SCHEDULER_add_now (&do_error, handle);
406 handle->issuer_attr = GNUNET_strdup (tmp);
407 GNUNET_free (entity_attr);
409 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR,
410 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR),
413 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 "Missing subject or attribute\n");
418 GNUNET_free (entity_attr);
419 GNUNET_SCHEDULER_add_now (&do_error, handle);
422 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
424 entity_attr = GNUNET_strdup (tmp);
425 tmp = strtok(entity_attr, ".");
428 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
429 "Malformed subject\n");
430 GNUNET_free (entity_attr);
431 GNUNET_SCHEDULER_add_now (&do_error, handle);
435 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
437 &handle->subject_key)) {
438 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
439 "Malformed subject key\n");
440 GNUNET_free (entity_attr);
441 GNUNET_SCHEDULER_add_now (&do_error, handle);
444 tmp = strtok (NULL, ".");
447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
448 "Malformed subject attribute\n");
449 GNUNET_free (entity_attr);
450 GNUNET_SCHEDULER_add_now (&do_error, handle);
453 handle->subject_attr = GNUNET_strdup (tmp);
454 GNUNET_free (entity_attr);
456 handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
459 &handle->subject_key,
460 handle->subject_attr,
461 &handle_verify_response,
467 * Handle rest request
469 * @param handle the lookup handle
472 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
476 struct MHD_Response *resp;
477 struct VerifyHandle *handle = cls;
479 //For GNS, independent of path return all options
480 resp = GNUNET_REST_create_response (NULL);
481 MHD_add_response_header (resp,
482 "Access-Control-Allow-Methods",
483 MHD_HTTP_METHOD_GET);
484 handle->proc (handle->proc_cls,
487 cleanup_handle (handle);
492 * Function processing the REST call
494 * @param method HTTP method
495 * @param url URL of the HTTP request
496 * @param data body of the HTTP request (optional)
497 * @param data_size length of the body
498 * @param proc callback function for the result
499 * @param proc_cls closure for callback function
500 * @return GNUNET_OK if request accepted
503 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
504 GNUNET_REST_ResultProcessor proc,
507 struct VerifyHandle *handle = GNUNET_new (struct VerifyHandle);
508 struct GNUNET_REST_RequestHandlerError err;
510 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
511 handle->proc_cls = proc_cls;
513 handle->rest_handle = conndata_handle;
515 static const struct GNUNET_REST_RequestHandler handlers[] = {
516 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL, &verify_cred_cont},
517 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
518 GNUNET_REST_HANDLER_END
521 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
526 handle->response_code = err.error_code;
527 GNUNET_SCHEDULER_add_now (&do_error, handle);
533 * Entry point for the plugin.
535 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
536 * @return NULL on error, otherwise the plugin context
539 libgnunet_plugin_rest_credential_init (void *cls)
541 static struct Plugin plugin;
543 struct GNUNET_REST_Plugin *api;
545 if (NULL != plugin.cfg)
546 return NULL; /* can only initialize once! */
547 memset (&plugin, 0, sizeof (struct Plugin));
549 api = GNUNET_new (struct GNUNET_REST_Plugin);
551 api->name = GNUNET_REST_API_NS_CREDENTIAL;
552 api->process_request = &rest_credential_process_request;
553 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
554 _("GNS REST API initialized\n"));
560 * Exit point from the plugin.
562 * @param cls the plugin context (as returned by "init")
563 * @return always NULL
566 libgnunet_plugin_rest_credential_done (void *cls)
568 struct GNUNET_REST_Plugin *api = cls;
569 struct Plugin *plugin = api->cls;
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "GNS REST plugin is finished\n");
578 /* end of plugin_rest_gns.c */