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_AttributeRecordData *attr)
195 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&attr->subject_key);
197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198 "Subject in credential malformed\n");
201 attribute = (char*)&attr[1];
202 attr_obj = json_object ();
203 json_object_set_new (attr_obj, "subject", json_string (subject));
204 json_object_set_new (attr_obj, "attribute", json_string (attribute));
205 GNUNET_free (subject);
211 * @param cred the credential
212 * @return the resulting json, NULL if failed
215 credential_to_json (struct GNUNET_CREDENTIAL_CredentialRecordData *cred)
217 struct GNUNET_TIME_Absolute exp;
225 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
229 "Issuer in credential malformed\n");
232 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
236 "Subject in credential malformed\n");
237 GNUNET_free (issuer);
240 GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
241 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
243 attribute = (char*)&cred[1];
244 exp.abs_value_us = ntohs (cred->expiration);
245 exp_str = GNUNET_STRINGS_absolute_time_to_string (exp);
246 cred_obj = json_object ();
247 json_object_set_new (cred_obj, "issuer", json_string (issuer));
248 json_object_set_new (cred_obj, "subject", json_string (subject));
249 json_object_set_new (cred_obj, "attribute", json_string (attribute));
250 json_object_set_new (cred_obj, "signature", json_string (signature));
251 json_object_set_new (cred_obj, "expiration", json_string (exp_str));
252 GNUNET_free (issuer);
253 GNUNET_free (subject);
254 GNUNET_free (signature);
259 * Function called with the result of a Credential lookup.
261 * @param cls the 'const char *' name that was resolved
262 * @param cd_count number of records returned
263 * @param cd array of @a cd_count records with the results
266 handle_verify_response (void *cls,
267 struct GNUNET_CREDENTIAL_CredentialRecordData *cred,
268 uint32_t delegation_count,
269 struct GNUNET_CREDENTIAL_AttributeRecordData *deleg)
272 struct VerifyHandle *handle = cls;
273 struct MHD_Response *resp;
274 struct GNUNET_JSONAPI_Document *json_document;
275 struct GNUNET_JSONAPI_Resource *json_resource;
278 json_t *result_array;
282 handle->verify_request = NULL;
284 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
286 handle->response_code = MHD_HTTP_NOT_FOUND;
287 GNUNET_SCHEDULER_add_now (&do_error, handle);
290 json_document = GNUNET_JSONAPI_document_new ();
291 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
292 handle->issuer_attr);
293 cred_obj = credential_to_json (cred);
294 result_array = json_array ();
295 for (i = 0; i < delegation_count; i++)
297 attr_obj = attribute_delegation_to_json (&(deleg[i]));
298 json_array_append (result_array, attr_obj);
299 json_decref (attr_obj);
301 GNUNET_JSONAPI_resource_add_attr (json_resource,
302 GNUNET_REST_JSONAPI_CREDENTIAL,
304 GNUNET_JSONAPI_resource_add_attr (json_resource,
305 GNUNET_REST_JSONAPI_CREDENTIAL_CHAIN,
307 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
308 GNUNET_JSONAPI_document_serialize (json_document, &result);
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
312 json_decref (result_array);
313 GNUNET_JSONAPI_document_delete (json_document);
314 resp = GNUNET_REST_create_response (result);
315 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
316 GNUNET_free (result);
317 cleanup_handle (handle);
322 verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
326 struct VerifyHandle *handle = cls;
327 struct GNUNET_HashCode key;
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
334 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 if (NULL == handle->credential)
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341 "Connecting to CREDENTIAL failed\n");
342 GNUNET_SCHEDULER_add_now (&do_error, handle);
345 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
346 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
349 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353 "Missing issuer attribute\n");
354 GNUNET_SCHEDULER_add_now (&do_error, handle);
357 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
359 entity_attr = GNUNET_strdup (tmp);
360 tmp = strtok(entity_attr, ".");
363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364 "Malformed issuer or attribute\n");
365 GNUNET_free (entity_attr);
366 GNUNET_SCHEDULER_add_now (&do_error, handle);
370 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
372 &handle->issuer_key))
374 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
375 "Malformed issuer key\n");
376 GNUNET_free (entity_attr);
377 GNUNET_SCHEDULER_add_now (&do_error, handle);
380 tmp = strtok (NULL, "."); //Issuer attribute
383 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
384 "Malformed attribute\n");
385 GNUNET_free (entity_attr);
386 GNUNET_SCHEDULER_add_now (&do_error, handle);
389 handle->issuer_attr = GNUNET_strdup (tmp);
390 GNUNET_free (entity_attr);
392 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR,
393 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR),
396 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
400 "Missing subject or attribute\n");
401 GNUNET_free (entity_attr);
402 GNUNET_SCHEDULER_add_now (&do_error, handle);
405 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
407 entity_attr = GNUNET_strdup (tmp);
408 tmp = strtok(entity_attr, ".");
411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
412 "Malformed subject\n");
413 GNUNET_free (entity_attr);
414 GNUNET_SCHEDULER_add_now (&do_error, handle);
418 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
420 &handle->subject_key)) {
421 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
422 "Malformed subject key\n");
423 GNUNET_free (entity_attr);
424 GNUNET_SCHEDULER_add_now (&do_error, handle);
427 tmp = strtok (NULL, ".");
430 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
431 "Malformed subject attribute\n");
432 GNUNET_free (entity_attr);
433 GNUNET_SCHEDULER_add_now (&do_error, handle);
436 handle->subject_attr = GNUNET_strdup (tmp);
437 GNUNET_free (entity_attr);
439 handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
442 &handle->subject_key,
443 handle->subject_attr,
444 &handle_verify_response,
450 * Handle rest request
452 * @param handle the lookup handle
455 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
459 struct MHD_Response *resp;
460 struct VerifyHandle *handle = cls;
462 //For GNS, independent of path return all options
463 resp = GNUNET_REST_create_response (NULL);
464 MHD_add_response_header (resp,
465 "Access-Control-Allow-Methods",
466 MHD_HTTP_METHOD_GET);
467 handle->proc (handle->proc_cls,
470 cleanup_handle (handle);
475 * Function processing the REST call
477 * @param method HTTP method
478 * @param url URL of the HTTP request
479 * @param data body of the HTTP request (optional)
480 * @param data_size length of the body
481 * @param proc callback function for the result
482 * @param proc_cls closure for callback function
483 * @return GNUNET_OK if request accepted
486 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
487 GNUNET_REST_ResultProcessor proc,
490 struct VerifyHandle *handle = GNUNET_new (struct VerifyHandle);
491 struct GNUNET_REST_RequestHandlerError err;
493 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
494 handle->proc_cls = proc_cls;
496 handle->rest_handle = conndata_handle;
498 static const struct GNUNET_REST_RequestHandler handlers[] = {
499 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL, &verify_cred_cont},
500 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
501 GNUNET_REST_HANDLER_END
504 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
509 handle->response_code = err.error_code;
510 GNUNET_SCHEDULER_add_now (&do_error, handle);
516 * Entry point for the plugin.
518 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
519 * @return NULL on error, otherwise the plugin context
522 libgnunet_plugin_rest_credential_init (void *cls)
524 static struct Plugin plugin;
526 struct GNUNET_REST_Plugin *api;
528 if (NULL != plugin.cfg)
529 return NULL; /* can only initialize once! */
530 memset (&plugin, 0, sizeof (struct Plugin));
532 api = GNUNET_new (struct GNUNET_REST_Plugin);
534 api->name = GNUNET_REST_API_NS_CREDENTIAL;
535 api->process_request = &rest_credential_process_request;
536 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
537 _("GNS REST API initialized\n"));
543 * Exit point from the plugin.
545 * @param cls the plugin context (as returned by "init")
546 * @return always NULL
549 libgnunet_plugin_rest_credential_done (void *cls)
551 struct GNUNET_REST_Plugin *api = cls;
552 struct Plugin *plugin = api->cls;
556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557 "GNS REST plugin is finished\n");
561 /* end of plugin_rest_gns.c */