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);
198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
199 "Issuer in delegation malformed\n");
202 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 ();
212 json_object_set_new (attr_obj, "issuer", json_string (issuer));
213 json_object_set_new (attr_obj, "issuer_attribute",
214 json_string (delegation_chain_entry->issuer_attribute));
216 json_object_set_new (attr_obj, "subject", json_string (subject));
217 if (0 < delegation_chain_entry->subject_attribute_len)
219 json_object_set_new (attr_obj, "subject_attribute",
220 json_string (delegation_chain_entry->subject_attribute));
222 GNUNET_free (issuer);
223 GNUNET_free (subject);
229 * @param cred the credential
230 * @return the resulting json, NULL if failed
233 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
237 char attribute[cred->issuer_attribute_len + 1];
240 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
243 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
244 "Issuer in credential malformed\n");
247 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 "Subject in credential malformed\n");
252 GNUNET_free (issuer);
256 cred->issuer_attribute,
257 cred->issuer_attribute_len);
258 attribute[cred->issuer_attribute_len] = '\0';
259 cred_obj = json_object ();
260 json_object_set_new (cred_obj, "issuer", json_string (issuer));
261 json_object_set_new (cred_obj, "subject", json_string (subject));
262 json_object_set_new (cred_obj, "attribute", json_string (attribute));
263 GNUNET_free (issuer);
264 GNUNET_free (subject);
269 * Function called with the result of a Credential lookup.
271 * @param cls the 'const char *' name that was resolved
272 * @param cd_count number of records returned
273 * @param cd array of @a cd_count records with the results
276 handle_verify_response (void *cls,
277 unsigned int d_count,
278 struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
279 unsigned int c_count,
280 struct GNUNET_CREDENTIAL_Credential *cred)
283 struct VerifyHandle *handle = cls;
284 struct MHD_Response *resp;
285 struct GNUNET_JSONAPI_Document *json_document;
286 struct GNUNET_JSONAPI_Resource *json_resource;
296 handle->verify_request = NULL;
298 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
300 handle->response_code = MHD_HTTP_NOT_FOUND;
301 GNUNET_SCHEDULER_add_now (&do_error, handle);
304 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
308 "Issuer in delegation malformed\n");
311 GNUNET_asprintf (&id,
314 handle->issuer_attr);
315 GNUNET_free (issuer);
316 json_document = GNUNET_JSONAPI_document_new ();
317 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
320 attr_array = json_array ();
321 for (i = 0; i < d_count; i++)
323 attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
324 json_array_append_new (attr_array, attr_obj);
326 cred_array = json_array ();
327 for (i=0;i<c_count;i++)
329 cred_obj = credential_to_json (&cred[i]);
330 json_array_append_new (cred_array, cred_obj);
332 GNUNET_JSONAPI_resource_add_attr (json_resource,
333 GNUNET_REST_JSONAPI_CREDENTIAL,
335 GNUNET_JSONAPI_resource_add_attr (json_resource,
336 GNUNET_REST_JSONAPI_DELEGATIONS,
338 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
339 GNUNET_JSONAPI_document_serialize (json_document, &result);
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 json_decref (attr_array);
344 json_decref (cred_array);
345 GNUNET_JSONAPI_document_delete (json_document);
346 resp = GNUNET_REST_create_response (result);
347 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
348 GNUNET_free (result);
349 cleanup_handle (handle);
354 verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
358 struct VerifyHandle *handle = cls;
359 struct GNUNET_HashCode key;
363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
366 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 if (NULL == handle->credential)
372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373 "Connecting to CREDENTIAL failed\n");
374 GNUNET_SCHEDULER_add_now (&do_error, handle);
377 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
378 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
381 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Missing issuer attribute\n");
386 GNUNET_SCHEDULER_add_now (&do_error, handle);
389 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
391 entity_attr = GNUNET_strdup (tmp);
392 tmp = strtok(entity_attr, ".");
395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
396 "Malformed issuer or attribute\n");
397 GNUNET_free (entity_attr);
398 GNUNET_SCHEDULER_add_now (&do_error, handle);
402 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
404 &handle->issuer_key))
406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
407 "Malformed issuer key\n");
408 GNUNET_free (entity_attr);
409 GNUNET_SCHEDULER_add_now (&do_error, handle);
412 tmp = strtok (NULL, "."); //Issuer attribute
415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
416 "Malformed attribute\n");
417 GNUNET_free (entity_attr);
418 GNUNET_SCHEDULER_add_now (&do_error, handle);
421 handle->issuer_attr = GNUNET_strdup (tmp);
422 GNUNET_free (entity_attr);
424 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR,
425 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR),
428 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
431 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432 "Missing subject or attribute\n");
433 GNUNET_free (entity_attr);
434 GNUNET_SCHEDULER_add_now (&do_error, handle);
437 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
439 entity_attr = GNUNET_strdup (tmp);
440 tmp = strtok(entity_attr, ".");
443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444 "Malformed subject\n");
445 GNUNET_free (entity_attr);
446 GNUNET_SCHEDULER_add_now (&do_error, handle);
450 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
452 &handle->subject_key)) {
453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
454 "Malformed subject key\n");
455 GNUNET_free (entity_attr);
456 GNUNET_SCHEDULER_add_now (&do_error, handle);
459 tmp = strtok (NULL, ".");
462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
463 "Malformed subject attribute\n");
464 GNUNET_free (entity_attr);
465 GNUNET_SCHEDULER_add_now (&do_error, handle);
468 handle->subject_attr = GNUNET_strdup (tmp);
469 GNUNET_free (entity_attr);
471 handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
474 &handle->subject_key,
475 handle->subject_attr,
476 &handle_verify_response,
482 * Handle rest request
484 * @param handle the lookup handle
487 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
491 struct MHD_Response *resp;
492 struct VerifyHandle *handle = cls;
494 //For GNS, independent of path return all options
495 resp = GNUNET_REST_create_response (NULL);
496 MHD_add_response_header (resp,
497 "Access-Control-Allow-Methods",
498 MHD_HTTP_METHOD_GET);
499 handle->proc (handle->proc_cls,
502 cleanup_handle (handle);
507 * Function processing the REST call
509 * @param method HTTP method
510 * @param url URL of the HTTP request
511 * @param data body of the HTTP request (optional)
512 * @param data_size length of the body
513 * @param proc callback function for the result
514 * @param proc_cls closure for callback function
515 * @return GNUNET_OK if request accepted
518 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
519 GNUNET_REST_ResultProcessor proc,
522 struct VerifyHandle *handle = GNUNET_new (struct VerifyHandle);
523 struct GNUNET_REST_RequestHandlerError err;
525 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
526 handle->proc_cls = proc_cls;
528 handle->rest_handle = conndata_handle;
530 static const struct GNUNET_REST_RequestHandler handlers[] = {
531 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL, &verify_cred_cont},
532 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
533 GNUNET_REST_HANDLER_END
536 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
541 handle->response_code = err.error_code;
542 GNUNET_SCHEDULER_add_now (&do_error, handle);
548 * Entry point for the plugin.
550 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
551 * @return NULL on error, otherwise the plugin context
554 libgnunet_plugin_rest_credential_init (void *cls)
556 static struct Plugin plugin;
558 struct GNUNET_REST_Plugin *api;
560 if (NULL != plugin.cfg)
561 return NULL; /* can only initialize once! */
562 memset (&plugin, 0, sizeof (struct Plugin));
564 api = GNUNET_new (struct GNUNET_REST_Plugin);
566 api->name = GNUNET_REST_API_NS_CREDENTIAL;
567 api->process_request = &rest_credential_process_request;
568 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
569 _("GNS REST API initialized\n"));
575 * Exit point from the plugin.
577 * @param cls the plugin context (as returned by "init")
578 * @return always NULL
581 libgnunet_plugin_rest_credential_done (void *cls)
583 struct GNUNET_REST_Plugin *api = cls;
584 struct Plugin *plugin = api->cls;
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589 "GNS REST plugin is finished\n");
593 /* end of plugin_rest_gns.c */