-change api
[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                                                      0,
496                                                      NULL,//TODOhandle->subject_attr,
497                                                      &handle_verify_response,
498                                                      handle);
499
500 }
501
502 void
503 send_cred_response (struct RequestHandle *handle,
504                     struct GNUNET_CREDENTIAL_Credential *cred)
505 {
506   struct MHD_Response *resp;
507   struct GNUNET_JSONAPI_Document *json_document;
508   struct GNUNET_JSONAPI_Resource *json_resource;
509   json_t *cred_obj;
510   char *result;
511   char *issuer;
512   char *subject;
513   char *signature;
514   char *id;
515
516   GNUNET_assert (NULL != cred);
517   issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
518   if (NULL == issuer)
519   {
520     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
521                 "Subject malformed\n");
522     return;
523   }
524   GNUNET_asprintf (&id,
525                    "%s.%s",
526                    issuer,
527                    (char*)&cred[1]);
528   subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
529   if (NULL == subject)
530   {
531     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
532                 "Subject malformed\n");
533     return;
534   }
535   GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
536                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
537                                 &signature);
538   json_document = GNUNET_JSONAPI_document_new ();
539   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
540                                                id);
541   GNUNET_free (id);
542   cred_obj = json_object();
543   json_object_set_new (cred_obj, "issuer", json_string (issuer));
544   json_object_set_new (cred_obj, "subject", json_string (subject));
545   json_object_set_new (cred_obj, "expiration", json_integer( cred->expiration.abs_value_us));
546   json_object_set_new (cred_obj, "signature", json_string (signature));
547   GNUNET_JSONAPI_resource_add_attr (json_resource,
548                                     GNUNET_REST_JSONAPI_CREDENTIAL,
549                                     cred_obj);
550   GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
551   GNUNET_JSONAPI_document_serialize (json_document, &result);
552   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553               "Result %s\n",
554               result);
555   json_decref (cred_obj);
556   GNUNET_JSONAPI_document_delete (json_document);
557   resp = GNUNET_REST_create_response (result);
558   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
559   GNUNET_free (result);
560   GNUNET_free (signature);
561   GNUNET_free (issuer);
562   GNUNET_free (subject);
563   cleanup_handle (handle);
564 }
565
566 void
567 get_cred_issuer_cb (void *cls,
568                     struct GNUNET_IDENTITY_Ego *ego,
569                     void **ctx,
570                     const char *name)
571 {
572   struct RequestHandle *handle = cls;
573   struct GNUNET_TIME_Absolute etime_abs;
574   struct GNUNET_TIME_Relative etime_rel;
575   const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer_key;
576   struct GNUNET_HashCode key;
577   struct GNUNET_CREDENTIAL_Credential *cred;
578   char* expiration_str;
579   char* tmp;
580
581   handle->id_op = NULL;
582
583   if (NULL == name)
584   {
585     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586                 "Issuer not configured!\n");
587     GNUNET_SCHEDULER_add_now (&do_error, handle);
588     return;
589   }
590
591   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592               "Connecting to credential service...\n");
593   handle->credential = GNUNET_CREDENTIAL_connect (cfg);
594   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
595               "Connected\n");
596   if (NULL == handle->credential)
597   {
598     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
599                 "Connecting to CREDENTIAL failed\n");
600     GNUNET_SCHEDULER_add_now (&do_error, handle);
601     return;
602   }
603   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION,
604                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION),
605                       &key);
606   if ( GNUNET_NO ==
607        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
608                                                &key) )
609   {
610     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
611                 "Missing expiration\n");
612     GNUNET_SCHEDULER_add_now (&do_error, handle); 
613     return;
614   }
615   expiration_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
616                                                       &key);
617   if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration_str,
618                                                           &etime_rel))
619   {
620     etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
621   } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration_str,
622                                                                  &etime_abs))
623   {
624     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
625                 "Malformed expiration: %s\n", expiration_str);
626     GNUNET_SCHEDULER_add_now (&do_error, handle); 
627     return;
628   }
629   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
630                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
631                       &key);
632   if ( GNUNET_NO ==
633        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
634                                                &key) )
635   {
636     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
637                 "Missing issuer attribute\n");
638     GNUNET_SCHEDULER_add_now (&do_error, handle); 
639     return;
640   }
641   handle->issuer_attr = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get 
642                                       (handle->rest_handle->url_param_map,
643                                        &key));
644   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
645                       strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
646                       &key);
647   if ( GNUNET_NO ==
648        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
649                                                &key) )
650   {
651     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
652                 "Missing subject\n");
653     GNUNET_SCHEDULER_add_now (&do_error, handle);
654     return;
655   }
656   tmp = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
657                                            &key);
658   if (NULL == tmp)
659   {
660     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
661                 "Malformed subject\n");
662     GNUNET_SCHEDULER_add_now (&do_error, handle); 
663     return;
664   }
665   if (GNUNET_OK !=
666       GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
667                                                   strlen (tmp),
668                                                   &handle->subject_key)) {
669     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
670                 "Malformed subject key\n");
671     GNUNET_SCHEDULER_add_now (&do_error, handle);
672     return;
673   }
674   issuer_key = GNUNET_IDENTITY_ego_get_private_key (ego);
675   cred = GNUNET_CREDENTIAL_credential_issue (issuer_key,
676                                              &handle->subject_key,
677                                              handle->issuer_attr,
678                                              &etime_abs);
679   if (NULL == cred)
680   {
681     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
682                 "Failed to create credential\n");
683     GNUNET_SCHEDULER_add_now (&do_error, handle);
684     return;
685   }
686   send_cred_response (handle, cred);
687 }
688
689
690 static void
691 issue_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
692                  const char* url,
693                  void *cls)
694 {
695   struct RequestHandle *handle = cls;
696
697   handle->identity = GNUNET_IDENTITY_connect (cfg,
698                                               NULL,
699                                               NULL);
700   handle->id_op = GNUNET_IDENTITY_get(handle->identity,
701                                       "credential-issuer",
702                                       &get_cred_issuer_cb,
703                                       handle);
704   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
705                                                        &do_error,
706                                                        handle);
707 }
708
709 /**
710  * Handle rest request
711  *
712  * @param handle the lookup handle
713  */
714 static void
715 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
716               const char* url,
717               void *cls)
718 {
719   struct MHD_Response *resp;
720   struct RequestHandle *handle = cls;
721
722   //For GNS, independent of path return all options
723   resp = GNUNET_REST_create_response (NULL);
724   MHD_add_response_header (resp,
725                            "Access-Control-Allow-Methods",
726                            MHD_HTTP_METHOD_GET);
727   handle->proc (handle->proc_cls,
728                 resp,
729                 MHD_HTTP_OK);
730   cleanup_handle (handle);
731 }
732
733
734 /**
735  * Function processing the REST call
736  *
737  * @param method HTTP method
738  * @param url URL of the HTTP request
739  * @param data body of the HTTP request (optional)
740  * @param data_size length of the body
741  * @param proc callback function for the result
742  * @param proc_cls closure for callback function
743  * @return GNUNET_OK if request accepted
744  */
745 static void
746 rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
747                                 GNUNET_REST_ResultProcessor proc,
748                                 void *proc_cls)
749 {
750   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
751   struct GNUNET_REST_RequestHandlerError err;
752
753   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
754   handle->proc_cls = proc_cls;
755   handle->proc = proc;
756   handle->rest_handle = conndata_handle;
757
758   static const struct GNUNET_REST_RequestHandler handlers[] = {
759     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont},
760     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE, &issue_cred_cont},
761     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
762     GNUNET_REST_HANDLER_END
763   };
764
765   if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
766                                                   handlers,
767                                                   &err,
768                                                   handle))
769   {
770     handle->response_code = err.error_code;
771     GNUNET_SCHEDULER_add_now (&do_error, handle);
772   }
773 }
774
775
776 /**
777  * Entry point for the plugin.
778  *
779  * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
780  * @return NULL on error, otherwise the plugin context
781  */
782 void *
783 libgnunet_plugin_rest_credential_init (void *cls)
784 {
785   static struct Plugin plugin;
786   cfg = cls;
787   struct GNUNET_REST_Plugin *api;
788
789   if (NULL != plugin.cfg)
790     return NULL;                /* can only initialize once! */
791   memset (&plugin, 0, sizeof (struct Plugin));
792   plugin.cfg = cfg;
793   api = GNUNET_new (struct GNUNET_REST_Plugin);
794   api->cls = &plugin;
795   api->name = GNUNET_REST_API_NS_CREDENTIAL;
796   api->process_request = &rest_credential_process_request;
797   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
798               _("GNS REST API initialized\n"));
799   return api;
800 }
801
802
803 /**
804  * Exit point from the plugin.
805  *
806  * @param cls the plugin context (as returned by "init")
807  * @return always NULL
808  */
809 void *
810 libgnunet_plugin_rest_credential_done (void *cls)
811 {
812   struct GNUNET_REST_Plugin *api = cls;
813   struct Plugin *plugin = api->cls;
814
815   plugin->cfg = NULL;
816   GNUNET_free (api);
817   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
818               "GNS REST plugin is finished\n");
819   return NULL;
820 }
821
822 /* end of plugin_rest_gns.c */