-cleanup doc; fixes
[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 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  */
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 static void
198 do_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  */
214 static json_t*
215 attribute_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  */
259 static struct GNUNET_CREDENTIAL_Credential*
260 json_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  */
330 static json_t*
331 credential_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
373 static void
374 handle_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
437 static void
438 subject_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
463 static void
464 handle_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
540 static void
541 collect_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
642 static void
643 verify_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
841 void
842 send_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
905 void
906 get_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
1029 static void
1030 issue_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
1048 static void
1049 options_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
1068 static void
1069 rest_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  */
1106 void *
1107 libgnunet_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  */
1133 void *
1134 libgnunet_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 */