-fix rest issue
[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  * Credential to JSON
249  * @param cred the credential
250  * @return the resulting json, NULL if failed
251  */
252 static json_t*
253 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
254 {
255   char *issuer;
256   char *subject;
257   char attribute[cred->issuer_attribute_len + 1];
258   json_t *cred_obj;
259
260   issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
261   if (NULL == issuer)
262   {
263     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
264                 "Issuer in credential malformed\n");
265     return NULL;
266   }  
267   subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
268   if (NULL == subject)
269   {
270     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
271                 "Subject in credential malformed\n");
272     GNUNET_free (issuer);
273     return NULL;
274   }
275   memcpy (attribute,
276           cred->issuer_attribute,
277           cred->issuer_attribute_len);
278   attribute[cred->issuer_attribute_len] = '\0';
279   cred_obj = json_object ();
280   json_object_set_new (cred_obj, "issuer", json_string (issuer));
281   json_object_set_new (cred_obj, "subject", json_string (subject));
282   json_object_set_new (cred_obj, "attribute", json_string (attribute));
283   GNUNET_free (issuer);
284   GNUNET_free (subject);
285   return cred_obj;
286 }
287
288 /**
289  * Function called with the result of a Credential lookup.
290  *
291  * @param cls the 'const char *' name that was resolved
292  * @param cd_count number of records returned
293  * @param cd array of @a cd_count records with the results
294  */
295 static void
296 handle_verify_response (void *cls,
297                         unsigned int d_count,
298                         struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
299                         unsigned int c_count,
300                         struct GNUNET_CREDENTIAL_Credential *cred)
301 {
302
303   struct RequestHandle *handle = cls;
304   struct MHD_Response *resp;
305   struct GNUNET_JSONAPI_Document *json_document;
306   struct GNUNET_JSONAPI_Resource *json_resource;
307   json_t *cred_obj;
308   json_t *attr_obj;
309   json_t *cred_array;
310   json_t *attr_array;
311   char *result;
312   char *issuer;
313   char *id;
314   uint32_t i;
315
316   handle->verify_request = NULL;
317   if (NULL == cred) {
318     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319                 "Verify failed.\n");
320     handle->response_code = MHD_HTTP_NOT_FOUND;
321     GNUNET_SCHEDULER_add_now (&do_error, handle);
322     return;
323   }
324   issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
325   if (NULL == issuer)
326   {
327     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328                 "Issuer in delegation malformed\n");
329     return;
330   }
331   GNUNET_asprintf (&id,
332                    "%s.%s",
333                    issuer,
334                    handle->issuer_attr);
335   GNUNET_free (issuer);
336   json_document = GNUNET_JSONAPI_document_new ();
337   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
338                                                id);
339   GNUNET_free (id);
340   attr_array = json_array ();
341   for (i = 0; i < d_count; i++)
342   {
343     attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
344     json_array_append_new (attr_array, attr_obj);
345   }
346   cred_array = json_array ();
347   for (i=0;i<c_count;i++)
348   {
349     cred_obj = credential_to_json (&cred[i]);
350     json_array_append_new (cred_array, cred_obj);
351   }
352   GNUNET_JSONAPI_resource_add_attr (json_resource,
353                                     GNUNET_REST_JSONAPI_CREDENTIAL,
354                                     cred_array);
355   GNUNET_JSONAPI_resource_add_attr (json_resource,
356                                     GNUNET_REST_JSONAPI_DELEGATIONS,
357                                     attr_array);
358   GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
359   GNUNET_JSONAPI_document_serialize (json_document, &result);
360   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
361               "Result %s\n",
362               result);
363   json_decref (attr_array);
364   json_decref (cred_array);
365   GNUNET_JSONAPI_document_delete (json_document);
366   resp = GNUNET_REST_create_response (result);
367   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
368   GNUNET_free (result);
369   cleanup_handle (handle);
370 }
371
372
373 static void
374 verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
375                   const char* url,
376                   void *cls)
377 {
378   struct RequestHandle *handle = cls;
379   struct GNUNET_HashCode key;
380   char *tmp;
381   char *entity_attr;
382
383   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384               "Connecting...\n");
385   handle->credential = GNUNET_CREDENTIAL_connect (cfg);
386   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
387                                                        &do_error, handle);
388   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
389               "Connected\n");
390   if (NULL == handle->credential)
391   {
392     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393                 "Connecting to CREDENTIAL failed\n");
394     GNUNET_SCHEDULER_add_now (&do_error, handle);
395     return;
396   }
397   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
398                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
399                       &key);
400   if ( GNUNET_NO ==
401        GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
402                                                &key) )
403   {
404     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
405                 "Missing issuer attribute\n");
406     GNUNET_SCHEDULER_add_now (&do_error, handle); 
407     return;
408   }
409   tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
410                                            &key);
411   entity_attr = GNUNET_strdup (tmp);
412   tmp = strtok(entity_attr, ".");
413   if (NULL == tmp)
414   {
415     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
416                 "Malformed issuer or attribute\n");
417     GNUNET_free (entity_attr);
418     GNUNET_SCHEDULER_add_now (&do_error, handle);
419     return;
420   }
421   if (GNUNET_OK != 
422       GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
423                                                   strlen (tmp),
424                                                   &handle->issuer_key))
425   {
426     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427                 "Malformed issuer key\n");
428     GNUNET_free (entity_attr);
429     GNUNET_SCHEDULER_add_now (&do_error, handle);
430     return;
431   }
432   tmp = strtok (NULL, "."); //Issuer attribute
433   if (NULL == tmp)
434   {
435     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
436                 "Malformed attribute\n");
437     GNUNET_free (entity_attr);
438     GNUNET_SCHEDULER_add_now (&do_error, handle);
439     return;
440   }
441   handle->issuer_attr = GNUNET_strdup (tmp);
442   GNUNET_free (entity_attr);
443
444   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR,
445                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR),
446                       &key);
447   if ( GNUNET_NO ==
448        GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
449                                                &key) )
450   {
451     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
452                 "Missing subject or attribute\n");
453     GNUNET_free (entity_attr);
454     GNUNET_SCHEDULER_add_now (&do_error, handle);
455     return;
456   }
457   tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
458                                            &key);
459   entity_attr = GNUNET_strdup (tmp);
460   tmp = strtok(entity_attr, ".");
461   if (NULL == tmp)
462   {
463     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
464                 "Malformed subject\n");
465     GNUNET_free (entity_attr);
466     GNUNET_SCHEDULER_add_now (&do_error, handle); 
467     return;
468   }
469   if (GNUNET_OK !=
470       GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
471                                                   strlen (tmp),
472                                                   &handle->subject_key)) {
473     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
474                 "Malformed subject key\n");
475     GNUNET_free (entity_attr);
476     GNUNET_SCHEDULER_add_now (&do_error, handle);
477     return;
478   }
479   tmp = strtok (NULL, ".");
480   if (NULL == tmp)
481   {
482     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
483                 "Malformed subject attribute\n");
484     GNUNET_free (entity_attr);
485     GNUNET_SCHEDULER_add_now (&do_error, handle); 
486     return;
487   }
488   handle->subject_attr = GNUNET_strdup (tmp);
489   GNUNET_free (entity_attr);
490
491   handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
492                                                      &handle->issuer_key,
493                                                      handle->issuer_attr,
494                                                      &handle->subject_key,
495                                                      handle->subject_attr,
496                                                      &handle_verify_response,
497                                                      handle);
498
499 }
500
501 void
502 send_cred_response (struct RequestHandle *handle,
503                     struct GNUNET_CREDENTIAL_Credential *cred)
504 {
505   struct MHD_Response *resp;
506   struct GNUNET_JSONAPI_Document *json_document;
507   struct GNUNET_JSONAPI_Resource *json_resource;
508   json_t *cred_obj;
509   char *result;
510   char *issuer;
511   char *subject;
512   char *signature;
513   char *id;
514
515   GNUNET_assert (NULL != cred);
516   issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
517   if (NULL == issuer)
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
520                 "Subject malformed\n");
521     return;
522   }
523   GNUNET_asprintf (&id,
524                    "%s.%s",
525                    issuer,
526                    (char*)&cred[1]);
527   subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
528   if (NULL == subject)
529   {
530     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
531                 "Subject malformed\n");
532     return;
533   }
534   GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
535                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
536                                 &signature);
537   json_document = GNUNET_JSONAPI_document_new ();
538   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
539                                                id);
540   GNUNET_free (id);
541   cred_obj = json_object();
542   json_object_set_new (cred_obj, "issuer", json_string (issuer));
543   json_object_set_new (cred_obj, "subject", json_string (subject));
544   json_object_set_new (cred_obj, "expiration", json_integer( cred->expiration.abs_value_us));
545   json_object_set_new (cred_obj, "signature", json_string (signature));
546   GNUNET_JSONAPI_resource_add_attr (json_resource,
547                                     GNUNET_REST_JSONAPI_CREDENTIAL,
548                                     cred_obj);
549   GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
550   GNUNET_JSONAPI_document_serialize (json_document, &result);
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552               "Result %s\n",
553               result);
554   json_decref (cred_obj);
555   GNUNET_JSONAPI_document_delete (json_document);
556   resp = GNUNET_REST_create_response (result);
557   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
558   GNUNET_free (result);
559   GNUNET_free (signature);
560   GNUNET_free (issuer);
561   GNUNET_free (subject);
562   cleanup_handle (handle);
563 }
564
565 void
566 get_cred_issuer_cb (void *cls,
567                     struct GNUNET_IDENTITY_Ego *ego,
568                     void **ctx,
569                     const char *name)
570 {
571   struct RequestHandle *handle = cls;
572   struct GNUNET_TIME_Absolute etime_abs;
573   struct GNUNET_TIME_Relative etime_rel;
574   const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer_key;
575   struct GNUNET_HashCode key;
576   struct GNUNET_CREDENTIAL_Credential *cred;
577   char* expiration_str;
578   char* tmp;
579
580   handle->id_op = NULL;
581
582   if (NULL == name)
583   {
584     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
585                 "Issuer not configured!\n");
586     GNUNET_SCHEDULER_add_now (&do_error, handle);
587     return;
588   }
589
590   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591               "Connecting to credential service...\n");
592   handle->credential = GNUNET_CREDENTIAL_connect (cfg);
593   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594               "Connected\n");
595   if (NULL == handle->credential)
596   {
597     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
598                 "Connecting to CREDENTIAL failed\n");
599     GNUNET_SCHEDULER_add_now (&do_error, handle);
600     return;
601   }
602   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION,
603                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION),
604                       &key);
605   if ( GNUNET_NO ==
606        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
607                                                &key) )
608   {
609     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
610                 "Missing expiration\n");
611     GNUNET_SCHEDULER_add_now (&do_error, handle); 
612     return;
613   }
614   expiration_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
615                                                       &key);
616   if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration_str,
617                                                           &etime_rel))
618   {
619     etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
620   } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration_str,
621                                                                  &etime_abs))
622   {
623     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
624                 "Malformed expiration: %s\n", expiration_str);
625     GNUNET_SCHEDULER_add_now (&do_error, handle); 
626     return;
627   }
628   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
629                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
630                       &key);
631   if ( GNUNET_NO ==
632        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
633                                                &key) )
634   {
635     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
636                 "Missing issuer attribute\n");
637     GNUNET_SCHEDULER_add_now (&do_error, handle); 
638     return;
639   }
640   handle->issuer_attr = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get 
641                                       (handle->rest_handle->url_param_map,
642                                        &key));
643   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
644                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
645                       &key);
646   if ( GNUNET_NO ==
647        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
648                                                &key) )
649   {
650     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
651                 "Missing subject\n");
652     GNUNET_SCHEDULER_add_now (&do_error, handle);
653     return;
654   }
655   tmp = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
656                                            &key);
657   if (NULL == tmp)
658   {
659     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
660                 "Malformed subject\n");
661     GNUNET_SCHEDULER_add_now (&do_error, handle); 
662     return;
663   }
664   if (GNUNET_OK !=
665       GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
666                                                   strlen (tmp),
667                                                   &handle->subject_key)) {
668     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
669                 "Malformed subject key\n");
670     GNUNET_SCHEDULER_add_now (&do_error, handle);
671     return;
672   }
673   issuer_key = GNUNET_IDENTITY_ego_get_private_key (ego);
674   cred = GNUNET_CREDENTIAL_credential_issue (issuer_key,
675                                              &handle->subject_key,
676                                              handle->issuer_attr,
677                                              &etime_abs);
678   if (NULL == cred)
679   {
680     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
681                 "Failed to create credential\n");
682     GNUNET_SCHEDULER_add_now (&do_error, handle);
683     return;
684   }
685   send_cred_response (handle, cred);
686 }
687
688
689 static void
690 issue_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
691                  const char* url,
692                  void *cls)
693 {
694   struct RequestHandle *handle = cls;
695
696   handle->identity = GNUNET_IDENTITY_connect (cfg,
697                                               NULL,
698                                               NULL);
699   handle->id_op = GNUNET_IDENTITY_get(handle->identity,
700                                       "credential-issuer",
701                                       &get_cred_issuer_cb,
702                                       handle);
703   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
704                                                        &do_error,
705                                                        handle);
706 }
707
708 /**
709  * Handle rest request
710  *
711  * @param handle the lookup handle
712  */
713 static void
714 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
715               const char* url,
716               void *cls)
717 {
718   struct MHD_Response *resp;
719   struct RequestHandle *handle = cls;
720
721   //For GNS, independent of path return all options
722   resp = GNUNET_REST_create_response (NULL);
723   MHD_add_response_header (resp,
724                            "Access-Control-Allow-Methods",
725                            MHD_HTTP_METHOD_GET);
726   handle->proc (handle->proc_cls,
727                 resp,
728                 MHD_HTTP_OK);
729   cleanup_handle (handle);
730 }
731
732
733 /**
734  * Function processing the REST call
735  *
736  * @param method HTTP method
737  * @param url URL of the HTTP request
738  * @param data body of the HTTP request (optional)
739  * @param data_size length of the body
740  * @param proc callback function for the result
741  * @param proc_cls closure for callback function
742  * @return GNUNET_OK if request accepted
743  */
744 static void
745 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
746                                 GNUNET_REST_ResultProcessor proc,
747                                 void *proc_cls)
748 {
749   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
750   struct GNUNET_REST_RequestHandlerError err;
751
752   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
753   handle->proc_cls = proc_cls;
754   handle->proc = proc;
755   handle->rest_handle = conndata_handle;
756
757   static const struct GNUNET_REST_RequestHandler handlers[] = {
758     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont},
759     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE, &issue_cred_cont},
760     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
761     GNUNET_REST_HANDLER_END
762   };
763
764   if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
765                                                   handlers,
766                                                   &err,
767                                                   handle))
768   {
769     handle->response_code = err.error_code;
770     GNUNET_SCHEDULER_add_now (&do_error, handle);
771   }
772 }
773
774
775 /**
776  * Entry point for the plugin.
777  *
778  * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
779  * @return NULL on error, otherwise the plugin context
780  */
781 void *
782 libgnunet_plugin_rest_credential_init (void *cls)
783 {
784   static struct Plugin plugin;
785   cfg = cls;
786   struct GNUNET_REST_Plugin *api;
787
788   if (NULL != plugin.cfg)
789     return NULL;                /* can only initialize once! */
790   memset (&plugin, 0, sizeof (struct Plugin));
791   plugin.cfg = cfg;
792   api = GNUNET_new (struct GNUNET_REST_Plugin);
793   api->cls = &plugin;
794   api->name = GNUNET_REST_API_NS_CREDENTIAL;
795   api->process_request = &rest_credential_process_request;
796   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
797               _("GNS REST API initialized\n"));
798   return api;
799 }
800
801
802 /**
803  * Exit point from the plugin.
804  *
805  * @param cls the plugin context (as returned by "init")
806  * @return always NULL
807  */
808 void *
809 libgnunet_plugin_rest_credential_done (void *cls)
810 {
811   struct GNUNET_REST_Plugin *api = cls;
812   struct Plugin *plugin = api->cls;
813
814   plugin->cfg = NULL;
815   GNUNET_free (api);
816   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
817               "GNS REST plugin is finished\n");
818   return NULL;
819 }
820
821 /* end of plugin_rest_gns.c */