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