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