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)
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 struct GNUNET_CREDENTIAL_Credential *cred)
279 struct VerifyHandle *handle = cls;
280 struct MHD_Response *resp;
281 struct GNUNET_JSONAPI_Document *json_document;
282 struct GNUNET_JSONAPI_Resource *json_resource;
285 json_t *result_array;
289 handle->verify_request = NULL;
291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
293 handle->response_code = MHD_HTTP_NOT_FOUND;
294 GNUNET_SCHEDULER_add_now (&do_error, handle);
297 json_document = GNUNET_JSONAPI_document_new ();
298 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
299 handle->issuer_attr);
300 cred_obj = credential_to_json (cred);
301 result_array = json_array ();
302 for (i = 0; i < d_count; i++)
304 attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
305 json_array_append (result_array, attr_obj);
306 json_decref (attr_obj);
308 GNUNET_JSONAPI_resource_add_attr (json_resource,
309 GNUNET_REST_JSONAPI_CREDENTIAL,
311 GNUNET_JSONAPI_resource_add_attr (json_resource,
312 GNUNET_REST_JSONAPI_CREDENTIAL_CHAIN,
314 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
315 GNUNET_JSONAPI_document_serialize (json_document, &result);
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 json_decref (result_array);
320 GNUNET_JSONAPI_document_delete (json_document);
321 resp = GNUNET_REST_create_response (result);
322 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
323 GNUNET_free (result);
324 cleanup_handle (handle);
329 verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
333 struct VerifyHandle *handle = cls;
334 struct GNUNET_HashCode key;
338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
340 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
341 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
345 if (NULL == handle->credential)
347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
348 "Connecting to CREDENTIAL failed\n");
349 GNUNET_SCHEDULER_add_now (&do_error, handle);
352 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
353 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
356 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
360 "Missing issuer attribute\n");
361 GNUNET_SCHEDULER_add_now (&do_error, handle);
364 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
366 entity_attr = GNUNET_strdup (tmp);
367 tmp = strtok(entity_attr, ".");
370 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
371 "Malformed issuer or attribute\n");
372 GNUNET_free (entity_attr);
373 GNUNET_SCHEDULER_add_now (&do_error, handle);
377 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
379 &handle->issuer_key))
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
382 "Malformed issuer key\n");
383 GNUNET_free (entity_attr);
384 GNUNET_SCHEDULER_add_now (&do_error, handle);
387 tmp = strtok (NULL, "."); //Issuer attribute
390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
391 "Malformed attribute\n");
392 GNUNET_free (entity_attr);
393 GNUNET_SCHEDULER_add_now (&do_error, handle);
396 handle->issuer_attr = GNUNET_strdup (tmp);
397 GNUNET_free (entity_attr);
399 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR,
400 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR),
403 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
407 "Missing subject or attribute\n");
408 GNUNET_free (entity_attr);
409 GNUNET_SCHEDULER_add_now (&do_error, handle);
412 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
414 entity_attr = GNUNET_strdup (tmp);
415 tmp = strtok(entity_attr, ".");
418 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
419 "Malformed subject\n");
420 GNUNET_free (entity_attr);
421 GNUNET_SCHEDULER_add_now (&do_error, handle);
425 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
427 &handle->subject_key)) {
428 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
429 "Malformed subject key\n");
430 GNUNET_free (entity_attr);
431 GNUNET_SCHEDULER_add_now (&do_error, handle);
434 tmp = strtok (NULL, ".");
437 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
438 "Malformed subject attribute\n");
439 GNUNET_free (entity_attr);
440 GNUNET_SCHEDULER_add_now (&do_error, handle);
443 handle->subject_attr = GNUNET_strdup (tmp);
444 GNUNET_free (entity_attr);
446 handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
449 &handle->subject_key,
450 handle->subject_attr,
451 &handle_verify_response,
457 * Handle rest request
459 * @param handle the lookup handle
462 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
466 struct MHD_Response *resp;
467 struct VerifyHandle *handle = cls;
469 //For GNS, independent of path return all options
470 resp = GNUNET_REST_create_response (NULL);
471 MHD_add_response_header (resp,
472 "Access-Control-Allow-Methods",
473 MHD_HTTP_METHOD_GET);
474 handle->proc (handle->proc_cls,
477 cleanup_handle (handle);
482 * Function processing the REST call
484 * @param method HTTP method
485 * @param url URL of the HTTP request
486 * @param data body of the HTTP request (optional)
487 * @param data_size length of the body
488 * @param proc callback function for the result
489 * @param proc_cls closure for callback function
490 * @return GNUNET_OK if request accepted
493 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
494 GNUNET_REST_ResultProcessor proc,
497 struct VerifyHandle *handle = GNUNET_new (struct VerifyHandle);
498 struct GNUNET_REST_RequestHandlerError err;
500 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
501 handle->proc_cls = proc_cls;
503 handle->rest_handle = conndata_handle;
505 static const struct GNUNET_REST_RequestHandler handlers[] = {
506 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL, &verify_cred_cont},
507 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
508 GNUNET_REST_HANDLER_END
511 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
516 handle->response_code = err.error_code;
517 GNUNET_SCHEDULER_add_now (&do_error, handle);
523 * Entry point for the plugin.
525 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
526 * @return NULL on error, otherwise the plugin context
529 libgnunet_plugin_rest_credential_init (void *cls)
531 static struct Plugin plugin;
533 struct GNUNET_REST_Plugin *api;
535 if (NULL != plugin.cfg)
536 return NULL; /* can only initialize once! */
537 memset (&plugin, 0, sizeof (struct Plugin));
539 api = GNUNET_new (struct GNUNET_REST_Plugin);
541 api->name = GNUNET_REST_API_NS_CREDENTIAL;
542 api->process_request = &rest_credential_process_request;
543 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
544 _("GNS REST API initialized\n"));
550 * Exit point from the plugin.
552 * @param cls the plugin context (as returned by "init")
553 * @return always NULL
556 libgnunet_plugin_rest_credential_done (void *cls)
558 struct GNUNET_REST_Plugin *api = cls;
559 struct Plugin *plugin = api->cls;
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 "GNS REST plugin is finished\n");
568 /* end of plugin_rest_gns.c */