aboutsummaryrefslogtreecommitdiff
path: root/src/credential/plugin_rest_credential.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/credential/plugin_rest_credential.c')
-rw-r--r--src/credential/plugin_rest_credential.c1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/src/credential/plugin_rest_credential.c b/src/credential/plugin_rest_credential.c
new file mode 100644
index 000000000..480658822
--- /dev/null
+++ b/src/credential/plugin_rest_credential.c
@@ -0,0 +1,1146 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2016 GNUnet e.V.
4
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.
9
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.
14
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.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file credential/plugin_rest_credential.c
23 * @brief GNUnet CREDENTIAL REST plugin
24 *
25 */
26
27#include "platform.h"
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>
36#include <jansson.h>
37
38#define GNUNET_REST_API_NS_CREDENTIAL "/credential"
39
40#define GNUNET_REST_API_NS_CREDENTIAL_ISSUE "/credential/issue"
41
42#define GNUNET_REST_API_NS_CREDENTIAL_VERIFY "/credential/verify"
43
44#define GNUNET_REST_API_NS_CREDENTIAL_COLLECT "/credential/collect"
45
46#define GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION "expiration"
47
48#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY "subject_key"
49
50#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO "subject"
51
52#define GNUNET_REST_JSONAPI_CREDENTIAL "credential"
53
54#define GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO "credential"
55
56#define GNUNET_REST_JSONAPI_DELEGATIONS "delegations"
57
58#define GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR "attribute"
59
60#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR "credential"
61
62/**
63 * @brief struct returned by the initialization function of the plugin
64 */
65struct Plugin
66{
67 const struct GNUNET_CONFIGURATION_Handle *cfg;
68};
69
70const struct GNUNET_CONFIGURATION_Handle *cfg;
71
72struct RequestHandle
73{
74 /**
75 * Handle to Credential service.
76 */
77 struct GNUNET_CREDENTIAL_Handle *credential;
78
79 /**
80 * Handle to lookup request
81 */
82 struct GNUNET_CREDENTIAL_Request *verify_request;
83
84 /**
85 * Handle to issue request
86 */
87 struct GNUNET_CREDENTIAL_Request *issue_request;
88
89 /**
90 * Handle to identity
91 */
92 struct GNUNET_IDENTITY_Handle *identity;
93
94 /**
95 * Handle to identity operation
96 */
97 struct GNUNET_IDENTITY_Operation *id_op;
98
99 /**
100 * Handle to ego lookup
101 */
102 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
103
104 /**
105 * Handle to rest request
106 */
107 struct GNUNET_REST_RequestHandle *rest_handle;
108
109 /**
110 * ID of a task associated with the resolution process.
111 */
112 struct GNUNET_SCHEDULER_Task * timeout_task;
113
114 /**
115 * The root of the received JSON or NULL
116 */
117 json_t *json_root;
118
119 /**
120 * The plugin result processor
121 */
122 GNUNET_REST_ResultProcessor proc;
123
124 /**
125 * The closure of the result processor
126 */
127 void *proc_cls;
128
129 /**
130 * The issuer attribute to verify
131 */
132 char *issuer_attr;
133
134 /**
135 * The subject attribute
136 */
137 char *subject_attr;
138
139 /**
140 * The public key of the issuer
141 */
142 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
143
144 /**
145 * The public key of the subject
146 */
147 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
148
149 /**
150 * HTTP response code
151 */
152 int response_code;
153
154 /**
155 * Timeout
156 */
157 struct GNUNET_TIME_Relative timeout;
158
159};
160
161
162/**
163 * Cleanup lookup handle.
164 *
165 * @param handle Handle to clean up
166 */
167static void
168cleanup_handle (struct RequestHandle *handle)
169{
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171 "Cleaning up\n");
172 if (NULL != handle->json_root)
173 json_decref (handle->json_root);
174
175 if (NULL != handle->issuer_attr)
176 GNUNET_free (handle->issuer_attr);
177 if (NULL != handle->subject_attr)
178 GNUNET_free (handle->subject_attr);
179 if (NULL != handle->verify_request)
180 GNUNET_CREDENTIAL_request_cancel (handle->verify_request);
181 if (NULL != handle->credential)
182 GNUNET_CREDENTIAL_disconnect (handle->credential);
183 if (NULL != handle->id_op)
184 GNUNET_IDENTITY_cancel (handle->id_op);
185 if (NULL != handle->ego_lookup)
186 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
187 if (NULL != handle->identity)
188 GNUNET_IDENTITY_disconnect (handle->identity);
189 if (NULL != handle->timeout_task)
190 {
191 GNUNET_SCHEDULER_cancel (handle->timeout_task);
192 }
193 GNUNET_free (handle);
194}
195
196
197static void
198do_error (void *cls)
199{
200 struct RequestHandle *handle = cls;
201 struct MHD_Response *resp;
202
203 resp = GNUNET_REST_create_response (NULL);
204 handle->proc (handle->proc_cls, resp, handle->response_code);
205 cleanup_handle (handle);
206}
207
208/**
209 * Attribute delegation to JSON
210 *
211 * @param delegation_chain_entry the DSE
212 * @return JSON, NULL if failed
213 */
214static json_t*
215attribute_delegation_to_json (struct GNUNET_CREDENTIAL_Delegation *delegation_chain_entry)
216{
217 char *subject;
218 char *issuer;
219 json_t *attr_obj;
220
221 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->issuer_key);
222 if (NULL == issuer)
223 {
224 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225 "Issuer in delegation malformed\n");
226 return NULL;
227 }
228 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->subject_key);
229 if (NULL == subject)
230 {
231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
232 "Subject in credential malformed\n");
233 GNUNET_free (issuer);
234 return NULL;
235 }
236 attr_obj = json_object ();
237
238 json_object_set_new (attr_obj, "issuer", json_string (issuer));
239 json_object_set_new (attr_obj, "issuer_attribute",
240 json_string (delegation_chain_entry->issuer_attribute));
241
242 json_object_set_new (attr_obj, "subject", json_string (subject));
243 if (0 < delegation_chain_entry->subject_attribute_len)
244 {
245 json_object_set_new (attr_obj, "subject_attribute",
246 json_string (delegation_chain_entry->subject_attribute));
247 }
248 GNUNET_free (issuer);
249 GNUNET_free (subject);
250 return attr_obj;
251}
252
253/**
254 * JSONAPI resource to Credential
255 *
256 * @param res the JSONAPI resource
257 * @return the resulting credential, NULL if failed
258 */
259static struct GNUNET_CREDENTIAL_Credential*
260json_to_credential (json_t *res)
261{
262 struct GNUNET_CREDENTIAL_Credential *cred;
263 json_t *tmp;
264 const char *attribute;
265 const char *signature;
266 char *sig;
267
268 tmp = json_object_get (res, "attribute");
269 if (0 == json_is_string (tmp))
270 {
271 return NULL;
272 }
273 attribute = json_string_value (tmp);
274 cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential)
275 + strlen (attribute));
276 cred->issuer_attribute = attribute;
277 cred->issuer_attribute_len = strlen (attribute);
278 tmp = json_object_get (res, "issuer");
279 if (0 == json_is_string (tmp))
280 {
281 GNUNET_free (cred);
282 return NULL;
283 }
284
285 GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value(tmp),
286 strlen (json_string_value(tmp)),
287 &cred->issuer_key);
288 tmp = json_object_get (res, "subject");
289 if (0 == json_is_string (tmp))
290 {
291 GNUNET_free (cred);
292 return NULL;
293 }
294 GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value(tmp),
295 strlen (json_string_value(tmp)),
296 &cred->subject_key);
297
298 tmp = json_object_get (res, "signature");
299 if (0 == json_is_string (tmp))
300 {
301 GNUNET_free (cred);
302 return NULL;
303 }
304 signature = json_string_value (tmp);
305 GNUNET_STRINGS_base64_decode (signature,
306 strlen (signature),
307 (char**)&sig);
308 GNUNET_memcpy (&cred->signature,
309 sig,
310 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
311 GNUNET_free (sig);
312
313 tmp = json_object_get (res, "expiration");
314 if (0 == json_is_integer (tmp))
315 {
316 GNUNET_free (cred);
317 return NULL;
318 }
319 cred->expiration.abs_value_us = json_integer_value (tmp);
320 return cred;
321}
322
323
324/**
325 * Credential to JSON
326 *
327 * @param cred the credential
328 * @return the resulting json, NULL if failed
329 */
330static json_t*
331credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
332{
333 char *issuer;
334 char *subject;
335 char *signature;
336 char attribute[cred->issuer_attribute_len + 1];
337 json_t *cred_obj;
338
339 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
340 if (NULL == issuer)
341 {
342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
343 "Issuer in credential malformed\n");
344 return NULL;
345 }
346 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
347 if (NULL == subject)
348 {
349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350 "Subject in credential malformed\n");
351 GNUNET_free (issuer);
352 return NULL;
353 }
354 GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
355 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
356 &signature);
357 memcpy (attribute,
358 cred->issuer_attribute,
359 cred->issuer_attribute_len);
360 attribute[cred->issuer_attribute_len] = '\0';
361 cred_obj = json_object ();
362 json_object_set_new (cred_obj, "issuer", json_string (issuer));
363 json_object_set_new (cred_obj, "subject", json_string (subject));
364 json_object_set_new (cred_obj, "attribute", json_string (attribute));
365 json_object_set_new (cred_obj, "signature", json_string (signature));
366 json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us));
367 GNUNET_free (issuer);
368 GNUNET_free (subject);
369 GNUNET_free (signature);
370 return cred_obj;
371}
372
373static void
374handle_collect_response (void *cls,
375 unsigned int d_count,
376 struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
377 unsigned int c_count,
378 struct GNUNET_CREDENTIAL_Credential *cred)
379{
380 struct RequestHandle *handle = cls;
381 struct MHD_Response *resp;
382 struct GNUNET_JSONAPI_Document *json_document;
383 struct GNUNET_JSONAPI_Resource *json_resource;
384 json_t *cred_obj;
385 json_t *cred_array;
386 char *result;
387 char *issuer;
388 char *id;
389 uint32_t i;
390
391 handle->verify_request = NULL;
392 if (NULL == cred) {
393 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
394 "Verify failed.\n");
395 handle->response_code = MHD_HTTP_NOT_FOUND;
396 GNUNET_SCHEDULER_add_now (&do_error, handle);
397 return;
398 }
399 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
400 if (NULL == issuer)
401 {
402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
403 "Issuer in delegation malformed\n");
404 return;
405 }
406 GNUNET_asprintf (&id,
407 "%s.%s",
408 issuer,
409 handle->issuer_attr);
410 GNUNET_free (issuer);
411 json_document = GNUNET_JSONAPI_document_new ();
412 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
413 id);
414 GNUNET_free (id);
415 cred_array = json_array ();
416 for (i=0;i<c_count;i++)
417 {
418 cred_obj = credential_to_json (&cred[i]);
419 json_array_append_new (cred_array, cred_obj);
420 }
421 GNUNET_JSONAPI_resource_add_attr (json_resource,
422 GNUNET_REST_JSONAPI_CREDENTIAL,
423 cred_array);
424 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
425 GNUNET_JSONAPI_document_serialize (json_document, &result);
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Result %s\n",
428 result);
429 json_decref (cred_array);
430 GNUNET_JSONAPI_document_delete (json_document);
431 resp = GNUNET_REST_create_response (result);
432 GNUNET_free(result);
433 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
434 cleanup_handle (handle);
435}
436
437static void
438subject_ego_lookup (void *cls,
439 const struct GNUNET_IDENTITY_Ego *ego)
440{
441 struct RequestHandle *handle = cls;
442 const struct GNUNET_CRYPTO_EcdsaPrivateKey *sub_key;
443 handle->ego_lookup = NULL;
444
445 if (NULL == ego)
446 {
447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
448 "Subject not found\n");
449 GNUNET_SCHEDULER_add_now (&do_error, handle);
450 return;
451 }
452 sub_key = GNUNET_IDENTITY_ego_get_private_key (ego);
453 handle->verify_request = GNUNET_CREDENTIAL_collect (handle->credential,
454 &handle->issuer_key,
455 handle->issuer_attr,
456 sub_key,
457 &handle_collect_response,
458 handle);
459}
460
461
462
463static void
464handle_verify_response (void *cls,
465 unsigned int d_count,
466 struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
467 unsigned int c_count,
468 struct GNUNET_CREDENTIAL_Credential *cred)
469{
470
471 struct RequestHandle *handle = cls;
472 struct MHD_Response *resp;
473 struct GNUNET_JSONAPI_Document *json_document;
474 struct GNUNET_JSONAPI_Resource *json_resource;
475 json_t *cred_obj;
476 json_t *attr_obj;
477 json_t *cred_array;
478 json_t *attr_array;
479 char *result;
480 char *issuer;
481 char *id;
482 uint32_t i;
483
484 handle->verify_request = NULL;
485 if (NULL == cred) {
486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
487 "Verify failed.\n");
488 handle->response_code = MHD_HTTP_NOT_FOUND;
489 GNUNET_SCHEDULER_add_now (&do_error, handle);
490 return;
491 }
492 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
493 if (NULL == issuer)
494 {
495 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
496 "Issuer in delegation malformed\n");
497 return;
498 }
499 GNUNET_asprintf (&id,
500 "%s.%s",
501 issuer,
502 handle->issuer_attr);
503 GNUNET_free (issuer);
504 json_document = GNUNET_JSONAPI_document_new ();
505 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
506 id);
507 GNUNET_free (id);
508 attr_array = json_array ();
509 for (i = 0; i < d_count; i++)
510 {
511 attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
512 json_array_append_new (attr_array, attr_obj);
513 }
514 cred_array = json_array ();
515 for (i=0;i<c_count;i++)
516 {
517 cred_obj = credential_to_json (&cred[i]);
518 json_array_append_new (cred_array, cred_obj);
519 }
520 GNUNET_JSONAPI_resource_add_attr (json_resource,
521 GNUNET_REST_JSONAPI_CREDENTIAL,
522 cred_array);
523 GNUNET_JSONAPI_resource_add_attr (json_resource,
524 GNUNET_REST_JSONAPI_DELEGATIONS,
525 attr_array);
526 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
527 GNUNET_JSONAPI_document_serialize (json_document, &result);
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Result %s\n",
530 result);
531 json_decref (attr_array);
532 json_decref (cred_array);
533 GNUNET_JSONAPI_document_delete (json_document);
534 resp = GNUNET_REST_create_response (result);
535 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
536 GNUNET_free (result);
537 cleanup_handle (handle);
538}
539
540static void
541collect_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
542 const char* url,
543 void *cls)
544{
545 struct RequestHandle *handle = cls;
546 struct GNUNET_HashCode key;
547 char *tmp;
548 char *entity_attr;
549
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Connecting...\n");
552 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
553 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
554 &do_error, handle);
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "Connected\n");
557 if (NULL == handle->credential)
558 {
559 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
560 "Connecting to CREDENTIAL failed\n");
561 GNUNET_SCHEDULER_add_now (&do_error, handle);
562 return;
563 }
564 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
565 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
566 &key);
567 if ( GNUNET_NO ==
568 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
569 &key) )
570 {
571 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
572 "Missing issuer attribute\n");
573 GNUNET_SCHEDULER_add_now (&do_error, handle);
574 return;
575 }
576 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
577 &key);
578 entity_attr = GNUNET_strdup (tmp);
579 tmp = strtok(entity_attr, ".");
580 if (NULL == tmp)
581 {
582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583 "Malformed issuer or attribute\n");
584 GNUNET_free (entity_attr);
585 GNUNET_SCHEDULER_add_now (&do_error, handle);
586 return;
587 }
588 if (GNUNET_OK !=
589 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
590 strlen (tmp),
591 &handle->issuer_key))
592 {
593 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
594 "Malformed issuer key\n");
595 GNUNET_free (entity_attr);
596 GNUNET_SCHEDULER_add_now (&do_error, handle);
597 return;
598 }
599 tmp = strtok (NULL, "."); //Issuer attribute
600 if (NULL == tmp)
601 {
602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603 "Malformed attribute\n");
604 GNUNET_free (entity_attr);
605 GNUNET_SCHEDULER_add_now (&do_error, handle);
606 return;
607 }
608 handle->issuer_attr = GNUNET_strdup (tmp);
609 GNUNET_free (entity_attr);
610
611 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO,
612 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO),
613 &key);
614 if ( GNUNET_NO ==
615 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
616 &key) )
617 {
618 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
619 "Missing subject\n");
620 GNUNET_free (entity_attr);
621 GNUNET_SCHEDULER_add_now (&do_error, handle);
622 return;
623 }
624 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
625 &key);
626 if (NULL == tmp)
627 {
628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
629 "Malformed subject\n");
630 GNUNET_free (entity_attr);
631 GNUNET_SCHEDULER_add_now (&do_error, handle);
632 return;
633 }
634 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
635 tmp,
636 &subject_ego_lookup,
637 handle);
638}
639
640
641
642static void
643verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
644 const char* url,
645 void *cls)
646{
647 struct RequestHandle *handle = cls;
648 struct GNUNET_HashCode key;
649 struct GNUNET_JSONAPI_Document *json_obj;
650 struct GNUNET_JSONAPI_Resource *res;
651 struct GNUNET_CREDENTIAL_Credential *cred;
652 char *tmp;
653 char *entity_attr;
654 int i;
655 uint32_t credential_count;
656 uint32_t resource_count;
657 json_t *cred_json;
658 json_t *data_js;
659 json_error_t err;
660
661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
662 "Connecting...\n");
663 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
664 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
665 &do_error, handle);
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
667 "Connected\n");
668 if (NULL == handle->credential)
669 {
670 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
671 "Connecting to CREDENTIAL failed\n");
672 GNUNET_SCHEDULER_add_now (&do_error, handle);
673 return;
674 }
675 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
676 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
677 &key);
678 if ( GNUNET_NO ==
679 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
680 &key) )
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
683 "Missing issuer attribute\n");
684 GNUNET_SCHEDULER_add_now (&do_error, handle);
685 return;
686 }
687 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
688 &key);
689 entity_attr = GNUNET_strdup (tmp);
690 tmp = strtok(entity_attr, ".");
691 if (NULL == tmp)
692 {
693 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
694 "Malformed issuer or attribute\n");
695 GNUNET_free (entity_attr);
696 GNUNET_SCHEDULER_add_now (&do_error, handle);
697 return;
698 }
699 if (GNUNET_OK !=
700 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
701 strlen (tmp),
702 &handle->issuer_key))
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
705 "Malformed issuer key\n");
706 GNUNET_free (entity_attr);
707 GNUNET_SCHEDULER_add_now (&do_error, handle);
708 return;
709 }
710 tmp = strtok (NULL, "."); //Issuer attribute
711 if (NULL == tmp)
712 {
713 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
714 "Malformed attribute\n");
715 GNUNET_free (entity_attr);
716 GNUNET_SCHEDULER_add_now (&do_error, handle);
717 return;
718 }
719 handle->issuer_attr = GNUNET_strdup (tmp);
720 GNUNET_free (entity_attr);
721
722 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
723 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
724 &key);
725 if ( GNUNET_NO ==
726 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
727 &key) )
728 {
729 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
730 "Missing subject key\n");
731 GNUNET_free (entity_attr);
732 GNUNET_SCHEDULER_add_now (&do_error, handle);
733 return;
734 }
735 tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
736 &key);
737 if (NULL == tmp)
738 {
739 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
740 "Malformed subject\n");
741 GNUNET_free (entity_attr);
742 GNUNET_SCHEDULER_add_now (&do_error, handle);
743 return;
744 }
745 if (GNUNET_OK !=
746 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
747 strlen (tmp),
748 &handle->subject_key)) {
749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
750 "Malformed subject key\n");
751 GNUNET_free (entity_attr);
752 GNUNET_SCHEDULER_add_now (&do_error, handle);
753 return;
754 }
755
756 if (0 >= handle->rest_handle->data_size)
757 {
758 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
759 "Missing credentials\n");
760 GNUNET_SCHEDULER_add_now (&do_error, handle);
761 return;
762 }
763
764 struct GNUNET_JSON_Specification docspec[] = {
765 GNUNET_JSON_spec_jsonapi_document (&json_obj),
766 GNUNET_JSON_spec_end()
767 };
768 char term_data[handle->rest_handle->data_size+1];
769 term_data[handle->rest_handle->data_size] = '\0';
770 credential_count = 0;
771 GNUNET_memcpy (term_data,
772 handle->rest_handle->data,
773 handle->rest_handle->data_size);
774 data_js = json_loads (term_data,
775 JSON_DECODE_ANY,
776 &err);
777 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (data_js, docspec,
778 NULL, NULL));
779 json_decref (data_js);
780 if (NULL == json_obj)
781 {
782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
783 "Unable to parse JSONAPI Object from %s\n",
784 term_data);
785 GNUNET_SCHEDULER_add_now (&do_error, handle);
786 return;
787 }
788
789 resource_count = GNUNET_JSONAPI_document_resource_count(json_obj);
790 GNUNET_assert (1 == resource_count);
791 res = (GNUNET_JSONAPI_document_get_resource(json_obj, 0));
792 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type(res,
793 GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO))
794 {
795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
796 "Resource not a credential!\n");
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798 "Unable to parse JSONAPI Object from %s\n",
799 term_data);
800 GNUNET_JSONAPI_document_delete (json_obj);
801 GNUNET_SCHEDULER_add_now (&do_error, handle);
802 return;
803 }
804 cred_json = GNUNET_JSONAPI_resource_read_attr (res,
805 GNUNET_REST_JSONAPI_CREDENTIAL);
806
807 GNUNET_assert (json_is_array (cred_json));
808
809 credential_count = json_array_size(cred_json);
810
811 struct GNUNET_CREDENTIAL_Credential credentials[credential_count];
812 for (i=0;i<credential_count;i++)
813 {
814 cred = json_to_credential (json_array_get (cred_json, i));
815 if (NULL == cred)
816 {
817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
818 "Unable to parse credential!\n");
819 continue;
820 }
821 GNUNET_memcpy (&credentials[i],
822 cred,
823 sizeof (struct GNUNET_CREDENTIAL_Credential));
824 credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
825 GNUNET_free (cred);
826 }
827 GNUNET_JSONAPI_document_delete(json_obj);
828 handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
829 &handle->issuer_key,
830 handle->issuer_attr,
831 &handle->subject_key,
832 credential_count,
833 credentials,
834 &handle_verify_response,
835 handle);
836 for (i=0;i<credential_count;i++)
837 GNUNET_free ((char*)credentials[i].issuer_attribute);
838
839}
840
841void
842send_cred_response (struct RequestHandle *handle,
843 struct GNUNET_CREDENTIAL_Credential *cred)
844{
845 struct MHD_Response *resp;
846 struct GNUNET_JSONAPI_Document *json_document;
847 struct GNUNET_JSONAPI_Resource *json_resource;
848 json_t *cred_obj;
849 char *result;
850 char *issuer;
851 char *subject;
852 char *signature;
853 char *id;
854
855 GNUNET_assert (NULL != cred);
856 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
857 if (NULL == issuer)
858 {
859 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
860 "Subject malformed\n");
861 return;
862 }
863 GNUNET_asprintf (&id,
864 "%s.%s",
865 issuer,
866 (char*)&cred[1]);
867 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
868 if (NULL == subject)
869 {
870 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
871 "Subject malformed\n");
872 return;
873 }
874 GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
875 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
876 &signature);
877 json_document = GNUNET_JSONAPI_document_new ();
878 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
879 id);
880 GNUNET_free (id);
881 cred_obj = json_object();
882 json_object_set_new (cred_obj, "issuer", json_string (issuer));
883 json_object_set_new (cred_obj, "subject", json_string (subject));
884 json_object_set_new (cred_obj, "expiration", json_integer( cred->expiration.abs_value_us));
885 json_object_set_new (cred_obj, "signature", json_string (signature));
886 GNUNET_JSONAPI_resource_add_attr (json_resource,
887 GNUNET_REST_JSONAPI_CREDENTIAL,
888 cred_obj);
889 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
890 GNUNET_JSONAPI_document_serialize (json_document, &result);
891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
892 "Result %s\n",
893 result);
894 json_decref (cred_obj);
895 GNUNET_JSONAPI_document_delete (json_document);
896 resp = GNUNET_REST_create_response (result);
897 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
898 GNUNET_free (result);
899 GNUNET_free (signature);
900 GNUNET_free (issuer);
901 GNUNET_free (subject);
902 cleanup_handle (handle);
903}
904
905void
906get_cred_issuer_cb (void *cls,
907 struct GNUNET_IDENTITY_Ego *ego,
908 void **ctx,
909 const char *name)
910{
911 struct RequestHandle *handle = cls;
912 struct GNUNET_TIME_Absolute etime_abs;
913 struct GNUNET_TIME_Relative etime_rel;
914 const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer_key;
915 struct GNUNET_HashCode key;
916 struct GNUNET_CREDENTIAL_Credential *cred;
917 char* expiration_str;
918 char* tmp;
919
920 handle->id_op = NULL;
921
922 if (NULL == name)
923 {
924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
925 "Issuer not configured!\n");
926 GNUNET_SCHEDULER_add_now (&do_error, handle);
927 return;
928 }
929
930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
931 "Connecting to credential service...\n");
932 handle->credential = GNUNET_CREDENTIAL_connect (cfg);
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
934 "Connected\n");
935 if (NULL == handle->credential)
936 {
937 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
938 "Connecting to CREDENTIAL failed\n");
939 GNUNET_SCHEDULER_add_now (&do_error, handle);
940 return;
941 }
942 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION,
943 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION),
944 &key);
945 if ( GNUNET_NO ==
946 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
947 &key) )
948 {
949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
950 "Missing expiration\n");
951 GNUNET_SCHEDULER_add_now (&do_error, handle);
952 return;
953 }
954 expiration_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
955 &key);
956 if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration_str,
957 &etime_rel))
958 {
959 etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
960 } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration_str,
961 &etime_abs))
962 {
963 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
964 "Malformed expiration: %s\n", expiration_str);
965 GNUNET_SCHEDULER_add_now (&do_error, handle);
966 return;
967 }
968 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
969 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
970 &key);
971 if ( GNUNET_NO ==
972 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
973 &key) )
974 {
975 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
976 "Missing issuer attribute\n");
977 GNUNET_SCHEDULER_add_now (&do_error, handle);
978 return;
979 }
980 handle->issuer_attr = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get
981 (handle->rest_handle->url_param_map,
982 &key));
983 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
984 strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
985 &key);
986 if ( GNUNET_NO ==
987 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
988 &key) )
989 {
990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991 "Missing subject\n");
992 GNUNET_SCHEDULER_add_now (&do_error, handle);
993 return;
994 }
995 tmp = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
996 &key);
997 if (NULL == tmp)
998 {
999 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1000 "Malformed subject\n");
1001 GNUNET_SCHEDULER_add_now (&do_error, handle);
1002 return;
1003 }
1004 if (GNUNET_OK !=
1005 GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
1006 strlen (tmp),
1007 &handle->subject_key)) {
1008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1009 "Malformed subject key\n");
1010 GNUNET_SCHEDULER_add_now (&do_error, handle);
1011 return;
1012 }
1013 issuer_key = GNUNET_IDENTITY_ego_get_private_key (ego);
1014 cred = GNUNET_CREDENTIAL_credential_issue (issuer_key,
1015 &handle->subject_key,
1016 handle->issuer_attr,
1017 &etime_abs);
1018 if (NULL == cred)
1019 {
1020 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1021 "Failed to create credential\n");
1022 GNUNET_SCHEDULER_add_now (&do_error, handle);
1023 return;
1024 }
1025 send_cred_response (handle, cred);
1026}
1027
1028
1029static void
1030issue_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
1031 const char* url,
1032 void *cls)
1033{
1034 struct RequestHandle *handle = cls;
1035
1036 handle->identity = GNUNET_IDENTITY_connect (cfg,
1037 NULL,
1038 NULL);
1039 handle->id_op = GNUNET_IDENTITY_get(handle->identity,
1040 "credential-issuer",
1041 &get_cred_issuer_cb,
1042 handle);
1043 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1044 &do_error,
1045 handle);
1046}
1047
1048static void
1049options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1050 const char* url,
1051 void *cls)
1052{
1053 struct MHD_Response *resp;
1054 struct RequestHandle *handle = cls;
1055
1056 //For GNS, independent of path return all options
1057 resp = GNUNET_REST_create_response (NULL);
1058 MHD_add_response_header (resp,
1059 "Access-Control-Allow-Methods",
1060 MHD_HTTP_METHOD_GET);
1061 handle->proc (handle->proc_cls,
1062 resp,
1063 MHD_HTTP_OK);
1064 cleanup_handle (handle);
1065}
1066
1067
1068static void
1069rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
1070 GNUNET_REST_ResultProcessor proc,
1071 void *proc_cls)
1072{
1073 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1074 struct GNUNET_REST_RequestHandlerError err;
1075
1076 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1077 handle->proc_cls = proc_cls;
1078 handle->proc = proc;
1079 handle->rest_handle = conndata_handle;
1080
1081 static const struct GNUNET_REST_RequestHandler handlers[] = {
1082 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont},
1083 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_COLLECT, &collect_cred_cont},
1084 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE, &issue_cred_cont},
1085 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
1086 GNUNET_REST_HANDLER_END
1087 };
1088
1089 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
1090 handlers,
1091 &err,
1092 handle))
1093 {
1094 handle->response_code = err.error_code;
1095 GNUNET_SCHEDULER_add_now (&do_error, handle);
1096 }
1097}
1098
1099
1100/**
1101 * Entry point for the plugin.
1102 *
1103 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
1104 * @return NULL on error, otherwise the plugin context
1105 */
1106void *
1107libgnunet_plugin_rest_credential_init (void *cls)
1108{
1109 static struct Plugin plugin;
1110 cfg = cls;
1111 struct GNUNET_REST_Plugin *api;
1112
1113 if (NULL != plugin.cfg)
1114 return NULL; /* can only initialize once! */
1115 memset (&plugin, 0, sizeof (struct Plugin));
1116 plugin.cfg = cfg;
1117 api = GNUNET_new (struct GNUNET_REST_Plugin);
1118 api->cls = &plugin;
1119 api->name = GNUNET_REST_API_NS_CREDENTIAL;
1120 api->process_request = &rest_credential_process_request;
1121 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1122 _("GNS REST API initialized\n"));
1123 return api;
1124}
1125
1126
1127/**
1128 * Exit point from the plugin.
1129 *
1130 * @param cls the plugin context (as returned by "init")
1131 * @return always NULL
1132 */
1133void *
1134libgnunet_plugin_rest_credential_done (void *cls)
1135{
1136 struct GNUNET_REST_Plugin *api = cls;
1137 struct Plugin *plugin = api->cls;
1138
1139 plugin->cfg = NULL;
1140 GNUNET_free (api);
1141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1142 "GNS REST plugin is finished\n");
1143 return NULL;
1144}
1145
1146/* end of plugin_rest_gns.c */