aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--configure.ac34
-rw-r--r--src/Makefile.am6
-rw-r--r--src/escrow/.gitignore1
-rw-r--r--src/escrow/Makefile.am128
-rw-r--r--src/escrow/escrow.h249
-rw-r--r--src/escrow/escrow_api.c618
-rw-r--r--src/escrow/escrow_plugin_helper.c438
-rw-r--r--src/escrow/escrow_plugin_helper.h142
-rw-r--r--src/escrow/gnunet-escrow.c528
-rw-r--r--src/escrow/plugin_escrow_anastasis.c231
-rw-r--r--src/escrow/plugin_escrow_gns.c1842
-rw-r--r--src/escrow/plugin_escrow_plaintext.c673
-rw-r--r--src/escrow/plugin_gnsrecord_escrow.c173
-rw-r--r--src/escrow/plugin_rest_escrow.c1311
-rwxr-xr-xsrc/escrow/test_gns_escrow.sh48
-rwxr-xr-xsrc/escrow/test_plaintext_escrow.sh47
-rw-r--r--src/include/gnunet_crypto_lib.h17
-rw-r--r--src/include/gnunet_escrow_lib.h437
-rw-r--r--src/include/gnunet_escrow_plugin.h171
-rw-r--r--src/include/gnunet_gnsrecord_lib.h5
-rw-r--r--src/include/gnunet_reclaim_plugin.h1
-rw-r--r--src/util/crypto_ecc.c35
-rw-r--r--src/util/strings.c2
24 files changed, 7137 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index b337cc058..90c692de8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,7 @@ cmake/
72build 72build
73CMakeLists.txt 73CMakeLists.txt
74CMakeFiles.txt 74CMakeFiles.txt
75
76.vscode/settings.json
77src/gnsrecord/gnunet-gnsrecord-tvg
78src/revocation/gnunet-revocation-tvg
diff --git a/configure.ac b/configure.ac
index 3cf7e6cb6..5540d5aa4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -792,6 +792,34 @@ AC_ARG_WITH(jansson,
792AS_IF([test "x$jansson" != x1], 792AS_IF([test "x$jansson" != x1],
793 [AC_MSG_ERROR([GNUnet requires libjansson])]) 793 [AC_MSG_ERROR([GNUnet requires libjansson])])
794 794
795# check for sss (Shamir Secret Sharing) library
796sss=0
797AC_MSG_CHECKING(for sss)
798AC_ARG_WITH(sss,
799 [ --with-sss=PREFIX (base of sss installation)],
800 [AC_MSG_RESULT([$with_sss])
801 AS_CASE([$with_sss],
802 [no],[],
803 [yes],[
804 CHECK_LIBHEADER(SSS, sss, sss_create_shares, sss.h, sss=1,)
805 ],[
806 LDFLAGS="-L$with_sss/lib $LDFLAGS"
807 CPPFLAGS="-I$with_sss/include $CPPFLAGS"
808 AC_CHECK_HEADERS(sss.h,
809 AC_CHECK_LIB([sss], [sss_create_shares],
810 EXT_LIB_PATH="-L$with_sss/lib $EXT_LIB_PATH"
811 sss=1))
812 ])
813 ],
814 [AC_MSG_RESULT([--with-sss not specified])
815 CHECK_LIBHEADER(SSS, sss, sss_create_shares, sss.h,sss=1,)])
816AM_CONDITIONAL(HAVE_SSS, [test "$sss" = 1])
817AS_IF([test "$sss" = 1],
818 [AC_DEFINE([HAVE_SSS],[1],[Have sss library])
819 sss_msg="yes"],
820 [AC_DEFINE([HAVE_SSS],[0],[Lacking sss library])
821 sss_msg="no"])
822
795# check for libpulse(audio) library 823# check for libpulse(audio) library
796pulse=0 824pulse=0
797libpulse_msg="no" 825libpulse_msg="no"
@@ -1965,6 +1993,7 @@ src/zonemaster/zonemaster.conf
1965src/rest/Makefile 1993src/rest/Makefile
1966src/abe/Makefile 1994src/abe/Makefile
1967src/reclaim/Makefile 1995src/reclaim/Makefile
1996src/escrow/Makefile
1968pkgconfig/Makefile 1997pkgconfig/Makefile
1969pkgconfig/gnunetarm.pc 1998pkgconfig/gnunetarm.pc
1970pkgconfig/gnunetats.pc 1999pkgconfig/gnunetats.pc
@@ -2066,6 +2095,10 @@ AS_IF([test "x$conversation_backend" = "xnone"],
2066# -- interface 2095# -- interface
2067interface_msg=`echo $DEFAULT_INTERFACE | tr -d \"` 2096interface_msg=`echo $DEFAULT_INTERFACE | tr -d \"`
2068# -- jansson 2097# -- jansson
2098# -- sss
2099AS_IF([test "$sss" != 1],
2100 [AC_MSG_WARN([sss library not found. GNS escrow plugin will not be compiled.])],
2101 [sss_msg="yes"])
2069# -- libextractor 2102# -- libextractor
2070AS_IF([test "$extractor" != 1], 2103AS_IF([test "$extractor" != 1],
2071 [AC_MSG_WARN([libextractor not found, but various file-sharing functions require it])], 2104 [AC_MSG_WARN([libextractor not found, but various file-sharing functions require it])],
@@ -2178,6 +2211,7 @@ libpulse: ${libpulse_msg}
2178libextractor: ${libextractor_msg} 2211libextractor: ${libextractor_msg}
2179texi2mdoc: ${texi2mdoc_msg} 2212texi2mdoc: ${texi2mdoc_msg}
2180mandoc: ${mandoc_msg} 2213mandoc: ${mandoc_msg}
2214sss: ${sss_msg}
2181 2215
2182GNUnet configuration: 2216GNUnet configuration:
2183===================== 2217=====================
diff --git a/src/Makefile.am b/src/Makefile.am
index 234a63389..64a4e594a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,10 +9,14 @@ if HAVE_TESTING
9 ATS_TESTS = ats-tests 9 ATS_TESTS = ats-tests
10endif 10endif
11 11
12if HAVE_SSS
13 ESCROW_DIR = escrow
14endif
12if HAVE_EXPERIMENTAL 15if HAVE_EXPERIMENTAL
13 EXP_DIR = \ 16 EXP_DIR = \
14 rps \ 17 rps \
15 abd 18 abd \
19 $(ESCROW_DIR)
16if HAVE_ABE 20if HAVE_ABE
17 EXP_DIR += \ 21 EXP_DIR += \
18 abe 22 abe
diff --git a/src/escrow/.gitignore b/src/escrow/.gitignore
new file mode 100644
index 000000000..116fabf88
--- /dev/null
+++ b/src/escrow/.gitignore
@@ -0,0 +1 @@
gnunet-escrow \ No newline at end of file
diff --git a/src/escrow/Makefile.am b/src/escrow/Makefile.am
new file mode 100644
index 000000000..36bb027ab
--- /dev/null
+++ b/src/escrow/Makefile.am
@@ -0,0 +1,128 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11EXTRA_DIST = \
12 escrow.conf \
13 test_escrow.conf \
14 $(check_SCRIPTS)
15
16pkgcfgdir= $(pkgdatadir)/config.d/
17
18libexecdir= $(pkglibdir)/libexec/
19
20pkgcfg_DATA = \
21 escrow.conf
22
23lib_LTLIBRARIES = \
24 libgnunetescrow.la
25plugin_LTLIBRARIES = \
26 libgnunet_plugin_escrow_plaintext.la \
27 libgnunet_plugin_escrow_gns.la \
28 libgnunet_plugin_escrow_anastasis.la \
29 libgnunet_plugin_gnsrecord_escrow.la \
30 libgnunet_plugin_rest_escrow.la
31
32bin_PROGRAMS = \
33 gnunet-escrow
34
35
36libgnunet_plugin_rest_escrow_la_SOURCES = \
37 plugin_rest_escrow.c
38libgnunet_plugin_rest_escrow_la_LIBADD = \
39 libgnunetescrow.la \
40 $(top_builddir)/src/identity/libgnunetidentity.la \
41 $(top_builddir)/src/rest/libgnunetrest.la \
42 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
43 $(LTLIBINTL) -ljansson $(MHD_LIBS)
44libgnunet_plugin_rest_escrow_la_LDFLAGS = \
45 $(GN_PLUGIN_LDFLAGS)
46libgnunet_plugin_rest_escrow_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
47
48
49libgnunetescrow_la_SOURCES = \
50 escrow_api.c \
51 escrow.h
52libgnunetescrow_la_LIBADD = \
53 $(top_builddir)/src/util/libgnunetutil.la \
54 $(GN_LIBINTL) $(XLIB)
55libgnunetescrow_la_LDFLAGS = \
56 $(GN_LIB_LDFLAGS) \
57 -version-info 0:0:0
58
59
60libgnunet_plugin_escrow_plaintext_la_SOURCES = \
61 plugin_escrow_plaintext.c \
62 escrow_plugin_helper.c \
63 escrow_plugin_helper.h
64libgnunet_plugin_escrow_plaintext_la_LIBADD = \
65 libgnunetescrow.la \
66 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
67 $(top_builddir)/src/identity/libgnunetidentity.la \
68 $(LTLIBINTL) $(MHD_LIBS)
69libgnunet_plugin_escrow_plaintext_la_LDFLAGS = \
70 $(GN_PLUGIN_LDFLAGS)
71
72libgnunet_plugin_escrow_gns_la_SOURCES = \
73 plugin_escrow_gns.c \
74 escrow_plugin_helper.c \
75 escrow_plugin_helper.h
76libgnunet_plugin_escrow_gns_la_LIBADD = \
77 libgnunetescrow.la \
78 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
79 $(top_builddir)/src/identity/libgnunetidentity.la \
80 $(top_builddir)/src/namestore/libgnunetnamestore.la \
81 $(top_builddir)/src/gns/libgnunetgns.la \
82 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
83 -lsss \
84 $(LTLIBINTL) $(MHD_LIBS)
85libgnunet_plugin_escrow_gns_la_LDFLAGS = \
86 $(GN_PLUGIN_LDFLAGS)
87
88libgnunet_plugin_escrow_anastasis_la_SOURCES = \
89 plugin_escrow_anastasis.c \
90 escrow_plugin_helper.c \
91 escrow_plugin_helper.h
92libgnunet_plugin_escrow_anastasis_la_LIBADD = \
93 libgnunetescrow.la \
94 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
95 $(top_builddir)/src/identity/libgnunetidentity.la \
96 $(LTLIBINTL) $(MHD_LIBS)
97libgnunet_plugin_escrow_anastasis_la_LDFLAGS = \
98 $(GN_PLUGIN_LDFLAGS)
99
100
101libgnunet_plugin_gnsrecord_escrow_la_SOURCES = \
102 plugin_gnsrecord_escrow.c
103libgnunet_plugin_gnsrecord_escrow_la_LIBADD = \
104 $(top_builddir)/src/util/libgnunetutil.la \
105 $(LTLIBINTL)
106libgnunet_plugin_gnsrecord_escrow_la_LDFLAGS = \
107 $(GN_PLUGIN_LDFLAGS)
108
109
110gnunet_escrow_SOURCES = \
111 gnunet-escrow.c
112gnunet_escrow_LDADD = \
113 libgnunetescrow.la \
114 $(top_builddir)/src/util/libgnunetutil.la \
115 $(top_builddir)/src/namestore/libgnunetnamestore.la \
116 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
117 $(top_builddir)/src/identity/libgnunetidentity.la \
118 $(GN_LIBINTL)
119
120check_SCRIPTS = \
121 test_plaintext_escrow.sh \
122 test_gns_escrow.sh
123 # test_anastasis_escrow.sh
124
125if ENABLE_TEST_RUN
126 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
127 TESTS = $(check_SCRIPTS)
128endif
diff --git a/src/escrow/escrow.h b/src/escrow/escrow.h
new file mode 100644
index 000000000..8fc9123c1
--- /dev/null
+++ b/src/escrow/escrow.h
@@ -0,0 +1,249 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Johannes Späth
23 * @file escrow/escrow.h
24 *
25 * @brief Common type definitions for the escrow component
26 */
27
28#ifndef ESCROW_H
29#define ESCROW_H
30
31#include "gnunet_escrow_lib.h"
32
33
34/**
35 * State while collecting all egos
36 */
37#define ESCROW_PLUGIN_STATE_INIT 0
38
39/**
40 * Done collecting egos
41 */
42#define ESCROW_PLUGIN_STATE_POST_INIT 1
43
44/**
45 * State while cleaning up
46 */
47#define ESCROW_PLUGIN_STATE_CLEANUP 2
48
49
50/**
51 * The ego list
52 */
53struct EgoEntry
54{
55 /**
56 * DLL
57 */
58 struct EgoEntry *next;
59
60 /**
61 * DLL
62 */
63 struct EgoEntry *prev;
64
65 /**
66 * Ego Identifier
67 */
68 char *identifier;
69
70 /**
71 * Public key string
72 */
73 char *keystring;
74
75 /**
76 * The Ego
77 */
78 struct GNUNET_IDENTITY_Ego *ego;
79};
80
81/**
82 * Handle for a plugin instance
83 */
84struct ESCROW_PluginHandle
85{
86 /**
87 * The identity init continuation.
88 */
89 GNUNET_ESCROW_IdentityInitContinuation id_init_cont;
90
91 /**
92 * The ego create continuation.
93 */
94 GNUNET_ESCROW_EgoCreateContinuation ego_create_cont;
95
96 /**
97 * The current restore callback.
98 */
99 GNUNET_ESCROW_EgoContinuation curr_restore_cb;
100
101 /**
102 * The handle to the escrow component.
103 */
104 struct GNUNET_ESCROW_Handle *escrow_handle;
105
106 /**
107 * The state of the plugin (in the initialization phase).
108 */
109 int state;
110
111 /**
112 * The head of the ego list.
113 */
114 struct EgoEntry *ego_head;
115
116 /**
117 * The tail of the ego list
118 */
119 struct EgoEntry *ego_tail;
120
121 /**
122 * The head of the plugin operation list
123 */
124 struct ESCROW_PluginOperationWrapper *plugin_op_head;
125
126 /**
127 * The tail of the plugin operation list
128 */
129 struct ESCROW_PluginOperationWrapper *plugin_op_tail;
130};
131
132/**
133 * Wrapper for an escrow plugin operation
134 */
135struct ESCROW_PluginOperationWrapper
136{
137 /**
138 * Plugin operations are kept in a DLL.
139 */
140 struct ESCROW_PluginOperationWrapper *prev;
141
142 /**
143 * Plugin operations are kept in a DLL.
144 */
145 struct ESCROW_PluginOperationWrapper *next;
146
147 /**
148 * The actual plugin operation
149 */
150 void *plugin_op;
151};
152
153
154/**
155 * Continuation for a plugin operation (e.g. used for restore, as this
156 * callback has to be called from the IDENTITY service after finishing)
157 */
158typedef void (*ESCROW_Plugin_Continuation) (void *cls);
159
160
161/**
162 * Wrapper for the Plugin_AnchorContinuation.
163 *
164 * As this type of function is called from the scheduler, which only takes
165 * one argument as closure, this struct is used to pass more arguments.
166 */
167struct ESCROW_Plugin_AnchorContinuationWrapper
168{
169 /**
170 * Handle for the escrow component
171 */
172 struct GNUNET_ESCROW_Handle *h;
173
174 /**
175 * The escrow anchor
176 */
177 struct GNUNET_ESCROW_Anchor *anchor;
178
179 /**
180 * The unique ID of the respective ESCROW_Operation
181 */
182 uint32_t op_id;
183
184 /**
185 * The error message, NULL on success
186 */
187 const char *emsg;
188};
189
190/**
191 * Wrapper for the Plugin_EgoContinuation.
192 *
193 * As this type of function is called from the scheduler, which only takes
194 * one argument as closure, this struct is used to pass more arguments.
195 */
196struct ESCROW_Plugin_EgoContinuationWrapper
197{
198 /**
199 * Handle for the escrow component
200 */
201 struct GNUNET_ESCROW_Handle *h;
202
203 /**
204 * The restored ego
205 */
206 struct GNUNET_IDENTITY_Ego *ego;
207
208 /**
209 * The unique ID of the respective ESCROW_Operation
210 */
211 uint32_t op_id;
212
213 /**
214 * The error message, NULL on success
215 */
216 const char *emsg;
217};
218
219/**
220 * Wrapper for the Plugin_VerifyContinuation.
221 *
222 * As this type of function is called from the scheduler, which only takes
223 * one argument as closure, this struct is used to pass more arguments.
224 */
225struct ESCROW_Plugin_VerifyContinuationWrapper
226{
227 /**
228 * Handle for the escrow component
229 */
230 struct GNUNET_ESCROW_Handle *h;
231
232 /**
233 * The result of the verification
234 */
235 int verificationResult;
236
237 /**
238 * The unique ID of the respective ESCROW_Operation
239 */
240 uint32_t op_id;
241
242 /**
243 * The error message, NULL on success
244 */
245 const char *emsg;
246};
247
248
249#endif
diff --git a/src/escrow/escrow_api.c b/src/escrow/escrow_api.c
new file mode 100644
index 000000000..bf712d3de
--- /dev/null
+++ b/src/escrow/escrow_api.c
@@ -0,0 +1,618 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Johannes Späth
23 * @file escrow/escrow_api.c
24 *
25 * @brief api to interact with the escrow component
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_escrow_lib.h"
31#include "gnunet_escrow_plugin.h"
32#include "escrow.h"
33
34
35/**
36 * Init canary for the plaintext plugin
37 */
38static int plaintext_initialized;
39
40
41/**
42 * Init canary for the GNS plugin
43 */
44static int gns_initialized;
45
46
47/**
48 * Init canary for the Anastasis plugin
49 */
50static int anastasis_initialized;
51
52
53/**
54 * Plaintext method string
55 */
56static const char *plaintext_string = "plaintext";
57
58
59/**
60 * GNS method string
61 */
62static const char *gns_string = "gns";
63
64
65/**
66 * Anastasis method string
67 */
68static const char *anastasis_string = "anastasis";
69
70
71/**
72 * None method string
73 */
74static const char *none_string = "INVALID-METHOD";
75
76
77/**
78 * Pointer to the plaintext plugin API
79 */
80static struct GNUNET_ESCROW_KeyPluginFunctions *plaintext_api;
81
82
83/**
84 * Pointer to the GNS plugin API
85 */
86static struct GNUNET_ESCROW_KeyPluginFunctions *gns_api;
87
88
89/**
90 * Pointer to the Anastasis plugin API
91 */
92static struct GNUNET_ESCROW_KeyPluginFunctions *anastasis_api;
93
94
95/**
96 * Initialize an escrow plugin
97 *
98 * @param method the escrow method determining the plugin
99 *
100 * @return pointer to the escrow plugin API
101 */
102static const struct GNUNET_ESCROW_KeyPluginFunctions *
103init_plugin (const struct GNUNET_ESCROW_Handle *h,
104 enum GNUNET_ESCROW_Key_Escrow_Method method)
105{
106 switch (method)
107 {
108 case GNUNET_ESCROW_KEY_PLAINTEXT:
109 if (GNUNET_YES == plaintext_initialized)
110 return plaintext_api;
111 plaintext_initialized = GNUNET_YES;
112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
113 "Loading PLAINTEXT escrow plugin\n");
114 plaintext_api = GNUNET_PLUGIN_load ("libgnunet_plugin_escrow_plaintext",
115 (void *)h->cfg);
116 return plaintext_api;
117 case GNUNET_ESCROW_KEY_GNS:
118 if (GNUNET_YES == gns_initialized)
119 return gns_api;
120 gns_initialized = GNUNET_YES;
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 "Loading GNS escrow plugin\n");
123 gns_api = GNUNET_PLUGIN_load ("libgnunet_plugin_escrow_gns",
124 (void *)h->cfg);
125 return gns_api;
126 case GNUNET_ESCROW_KEY_ANASTASIS:
127 if (GNUNET_YES == anastasis_initialized)
128 return anastasis_api;
129 anastasis_initialized = GNUNET_YES;
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Loading ANASTASIS escrow plugin\n");
132 anastasis_api = GNUNET_PLUGIN_load ("libgnunet_plugin_escrow_anastasis",
133 (void *)h->cfg);
134 return anastasis_api;
135 case GNUNET_ESCROW_KEY_NONE: // error case
136 fprintf (stderr, "incorrect escrow method!\n");
137 return NULL;
138 }
139 // should never be reached
140 return NULL;
141}
142
143
144/**
145 * Get a fresh operation id to distinguish between escrow operations
146 *
147 * @param h the escrow handle
148 *
149 * @return next operation id to use
150 */
151static uint32_t
152get_op_id (struct GNUNET_ESCROW_Handle *h)
153{
154 return h->last_op_id_used++;
155}
156
157
158/**
159 * Initialize the escrow component.
160 *
161 * @param cfg the configuration to use
162 *
163 * @return handle to use
164 */
165struct GNUNET_ESCROW_Handle *
166GNUNET_ESCROW_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
167{
168 struct GNUNET_ESCROW_Handle *h;
169
170 h = GNUNET_new (struct GNUNET_ESCROW_Handle);
171 h->cfg = GNUNET_CONFIGURATION_dup (cfg);
172 h->op_head = NULL;
173 h->op_tail = NULL;
174 return h;
175}
176
177
178/**
179 * Unload all loaded plugins on destruction.
180 *
181 * @param h the escrow handle
182 */
183void
184GNUNET_ESCROW_fini (struct GNUNET_ESCROW_Handle *h)
185{
186 struct GNUNET_ESCROW_Operation *op;
187
188 /* unload all loaded plugins */
189 if (GNUNET_YES == plaintext_initialized)
190 {
191 plaintext_initialized = GNUNET_NO;
192 GNUNET_break (NULL ==
193 GNUNET_PLUGIN_unload ("libgnunet_plugin_escrow_plaintext",
194 plaintext_api));
195 plaintext_api = NULL;
196 }
197
198 if (GNUNET_YES == gns_initialized)
199 {
200 gns_initialized = GNUNET_NO;
201 GNUNET_break (NULL ==
202 GNUNET_PLUGIN_unload ("libgnunet_plugin_escrow_gns",
203 gns_api));
204 gns_api = NULL;
205 }
206
207 if (GNUNET_YES == anastasis_initialized)
208 {
209 anastasis_initialized = GNUNET_NO;
210 GNUNET_break (NULL ==
211 GNUNET_PLUGIN_unload ("libgnunet_plugin_escrow_anastasis",
212 anastasis_api));
213 anastasis_api = NULL;
214 }
215
216 /* clean up the operation DLL */
217 while (NULL != (op = h->op_head))
218 {
219 GNUNET_ESCROW_cancel (op);
220 }
221
222 /* free the configuration */
223 GNUNET_free (h->cfg);
224
225 /* free the escrow handle */
226 GNUNET_free (h);
227}
228
229
230static void
231handle_start_escrow_result (void *cls)
232{
233 struct ESCROW_Plugin_AnchorContinuationWrapper *w = cls;
234 struct GNUNET_ESCROW_Operation *op;
235
236 for (op = w->h->op_head; NULL != op; op = op->next)
237 if (op->id == w->op_id)
238 break;
239
240 if (NULL == op)
241 {
242 GNUNET_break (0);
243 return;
244 }
245 GNUNET_CONTAINER_DLL_remove (w->h->op_head, w->h->op_tail, op);
246 if (NULL != op->cb_put)
247 op->cb_put (op->cb_cls, w->anchor, w->emsg);
248 GNUNET_free (op);
249}
250
251
252/**
253 * Put some data in escrow using the specified escrow method
254 *
255 * @param h the handle for the escrow component
256 * @param ego the identity ego to put in escrow
257 * @param userSecret the user secret (e.g. for derivation of escrow identities)
258 * for GNS escrow, this has to be UNIQUE in the whole network!
259 * @param method the escrow method to use
260 * @param cb function to call with the escrow anchor on completion
261 * @param cb_cls closure for @a cb
262 *
263 * @return handle to abort the operation
264 */
265struct GNUNET_ESCROW_Operation *
266GNUNET_ESCROW_put (struct GNUNET_ESCROW_Handle *h,
267 struct GNUNET_IDENTITY_Ego *ego,
268 const char *userSecret,
269 enum GNUNET_ESCROW_Key_Escrow_Method method,
270 GNUNET_ESCROW_AnchorContinuation cb,
271 void *cb_cls)
272{
273 struct GNUNET_ESCROW_Operation *op;
274 const struct GNUNET_ESCROW_KeyPluginFunctions *api;
275
276 op = GNUNET_new (struct GNUNET_ESCROW_Operation);
277 op->h = h;
278 op->id = get_op_id (h);
279 op->method = method;
280 op->cb_put = cb;
281 op->cb_cls = cb_cls;
282 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
283
284 api = init_plugin (h, method);
285 op->plugin_op_wrap = api->start_key_escrow (h,
286 ego,
287 userSecret,
288 &handle_start_escrow_result,
289 op->id);
290
291 return op;
292}
293
294
295static void
296handle_restore_key_result (void *cls)
297{
298 struct ESCROW_Plugin_EgoContinuationWrapper *w = cls;
299 struct GNUNET_ESCROW_Operation *op;
300
301 for (op = w->h->op_head; NULL != op; op = op->next)
302 if (op->id == w->op_id)
303 break;
304
305 if (NULL == op)
306 {
307 GNUNET_break (0);
308 return;
309 }
310 GNUNET_CONTAINER_DLL_remove (w->h->op_head, w->h->op_tail, op);
311 if (NULL != op->cb_get)
312 op->cb_get (op->cb_cls, w->ego, w->emsg);
313 GNUNET_free (op);
314}
315
316
317/**
318 * Get the escrowed data back
319 *
320 * @param h the handle for the escrow component
321 * @param anchor the escrow anchor returned by the GNUNET_ESCROW_put method
322 * @param cb function to call with the restored ego on completion
323 * @param cb_cls closure for @a cb
324 *
325 * @return handle to abort the operation
326 */
327struct GNUNET_ESCROW_Operation *
328GNUNET_ESCROW_get (struct GNUNET_ESCROW_Handle *h,
329 const struct GNUNET_ESCROW_Anchor *anchor,
330 GNUNET_ESCROW_EgoContinuation cb,
331 void *cb_cls)
332{
333 struct GNUNET_ESCROW_Operation *op;
334 const struct GNUNET_ESCROW_KeyPluginFunctions *api;
335
336 op = GNUNET_new (struct GNUNET_ESCROW_Operation);
337 op->h = h;
338 op->id = get_op_id (h);
339 op->method = anchor->method;
340 op->cb_get = cb;
341 op->cb_cls = cb_cls;
342 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
343
344 api = init_plugin (h, anchor->method);
345 op->plugin_op_wrap = api->restore_key (h, anchor, &handle_restore_key_result, op->id);
346
347 return op;
348}
349
350
351static void
352handle_verify_escrow_result (void *cls)
353{
354 struct ESCROW_Plugin_VerifyContinuationWrapper *w = cls;
355 struct GNUNET_ESCROW_Operation *op;
356
357 for (op = w->h->op_head; NULL != op; op = op->next)
358 if (op->id == w->op_id)
359 break;
360
361 if (NULL == op)
362 {
363 GNUNET_break (0);
364 return;
365 }
366 GNUNET_CONTAINER_DLL_remove (w->h->op_head, w->h->op_tail, op);
367 if (NULL != op->cb_verify)
368 op->cb_verify (op->cb_cls, w->verificationResult, w->emsg);
369 GNUNET_free (op);
370}
371
372
373/**
374 * Verify the escrowed data
375 *
376 * @param h the handle for the escrow component
377 * @param ego the identity ego that was put into escrow
378 * @param anchor the escrow anchor returned by the GNUNET_ESCROW_put method
379 * @param method the escrow method to use
380 * @param cb function to call with the verification result on completion
381 * @param cb_cls closure for @a cb
382 *
383 * @return handle to abort the operation
384 */
385struct GNUNET_ESCROW_Operation *
386GNUNET_ESCROW_verify (struct GNUNET_ESCROW_Handle *h,
387 struct GNUNET_IDENTITY_Ego *ego,
388 const struct GNUNET_ESCROW_Anchor *anchor,
389 enum GNUNET_ESCROW_Key_Escrow_Method method,
390 GNUNET_ESCROW_VerifyContinuation cb,
391 void *cb_cls)
392{
393 struct GNUNET_ESCROW_Operation *op;
394 const struct GNUNET_ESCROW_KeyPluginFunctions *api;
395
396 op = GNUNET_new (struct GNUNET_ESCROW_Operation);
397 op->h = h;
398 op->id = get_op_id (h);
399 op->method = method;
400 op->cb_verify = cb;
401 op->cb_cls = cb_cls;
402 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
403
404 api = init_plugin (h, method);
405 op->plugin_op_wrap = api->verify_key_escrow (h, ego, anchor, &handle_verify_escrow_result, op->id);
406
407 return op;
408}
409
410
411/**
412 * Get the status of an escrow, i.e.
413 * -> when the last escrow was
414 * -> when the next escrow is recommended
415 *
416 * @param h the handle for the escrow component
417 * @param ego the identity ego of which the escrow status has to be determined
418 * @param method the escrow method to use
419 *
420 * @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
421 */
422struct GNUNET_ESCROW_Status *
423GNUNET_ESCROW_get_status (struct GNUNET_ESCROW_Handle *h,
424 struct GNUNET_IDENTITY_Ego *ego,
425 enum GNUNET_ESCROW_Key_Escrow_Method method)
426{
427 const struct GNUNET_ESCROW_KeyPluginFunctions *api;
428
429 api = init_plugin (h, method);
430 return api->get_status (h, ego);
431}
432
433
434/**
435 * Deserialize an escrow anchor string (e.g. from command line) into a
436 * GNUNET_ESCROW_Anchor struct
437 * The anchor string is expected to have the following form:
438 * <method>:<egoName>:<anchorData>
439 * with <method>, <egoName> and <anchorData> being URL-encoded
440 *
441 *
442 * @param anchorString the encoded escrow anchor string
443 *
444 * @return the deserialized data packed into a GNUNET_ESCROW_Anchor struct,
445 * NULL if we failed to parse the string
446 */
447struct GNUNET_ESCROW_Anchor *
448GNUNET_ESCROW_anchor_string_to_data (const char *anchorString)
449{
450 struct GNUNET_ESCROW_Anchor *anchor;
451 uint32_t data_size;
452 char *anchorStringCopy, *ptr;
453 char *methodString, *egoNameString, *anchorDataString;
454 char delimiter[] = ":";
455
456 anchorStringCopy = GNUNET_strdup (anchorString);
457 anchor = NULL;
458 methodString = egoNameString = anchorDataString = NULL;
459
460 /* parse and decode method */
461 ptr = strtok (anchorStringCopy, delimiter);
462 if (NULL == ptr)
463 goto END;
464 GNUNET_STRINGS_urldecode (ptr, strlen (ptr), &methodString);
465 /* parse and decode ego name */
466 ptr = strtok (NULL, delimiter);
467 if (NULL == ptr)
468 goto END;
469 GNUNET_STRINGS_urldecode (ptr, strlen (ptr), &egoNameString);
470 /* parse and decode anchor data */
471 ptr = strtok (NULL, delimiter);
472 if (NULL == ptr)
473 goto END;
474 GNUNET_STRINGS_urldecode (ptr, strlen (ptr), &anchorDataString);
475 /* check if string is over */
476 ptr = strtok (NULL, delimiter);
477 if (NULL != ptr)
478 goto END;
479
480 data_size = strlen (anchorDataString); // data is NOT null-terminated
481 anchor = GNUNET_malloc (sizeof (struct GNUNET_ESCROW_Anchor)
482 + data_size
483 + strlen (egoNameString) + 1);
484 anchor->size = data_size;
485 anchor->method = GNUNET_ESCROW_method_string_to_number (methodString);
486
487 // ptr is now used to fill the anchor
488 ptr = (char *)&anchor[1];
489 strcpy (ptr, anchorDataString);
490 ptr += data_size;
491 anchor->egoName = ptr;
492 strcpy (ptr, egoNameString);
493
494 END:
495 /* free all non-NULL strings */
496 if (NULL != anchorStringCopy)
497 GNUNET_free (anchorStringCopy);
498 if (NULL != methodString)
499 GNUNET_free (methodString);
500 if (NULL != egoNameString)
501 GNUNET_free (egoNameString);
502 if (NULL != anchorDataString)
503 GNUNET_free (anchorDataString);
504
505 return anchor;
506}
507
508
509/**
510 * Serialize an escrow anchor (struct GNUNET_ESCROW_Anchor) into a string
511 *
512 * @param anchor the escrow anchor struct
513 *
514 * @return the encoded escrow anchor string
515 */
516char *
517GNUNET_ESCROW_anchor_data_to_string (const struct GNUNET_ESCROW_Anchor *anchor)
518{
519 char *anchorString, *ptr;
520 const char *methodString, *egoNameString, *anchorData;
521 char *methodStringEnc, *egoNameStringEnc, *anchorDataEnc;
522
523 methodString = GNUNET_ESCROW_method_number_to_string (anchor->method);
524 GNUNET_STRINGS_urlencode (methodString, strlen (methodString), &methodStringEnc);
525 egoNameString = anchor->egoName;
526 GNUNET_STRINGS_urlencode (egoNameString, strlen (egoNameString), &egoNameStringEnc);
527 anchorData = (const char *)&anchor[1];
528 GNUNET_STRINGS_urlencode (anchorData, anchor->size, &anchorDataEnc);
529
530 anchorString = GNUNET_malloc (strlen (methodStringEnc) + 1
531 + strlen (egoNameStringEnc) + 1
532 + strlen (anchorDataEnc)
533 + 1);
534
535 ptr = anchorString;
536 GNUNET_memcpy (ptr, methodStringEnc, strlen (methodStringEnc));
537 ptr += strlen (methodStringEnc);
538 GNUNET_free (methodStringEnc);
539 *(ptr++) = ':';
540 GNUNET_memcpy (ptr, egoNameStringEnc, strlen (egoNameStringEnc));
541 ptr += strlen (egoNameStringEnc);
542 GNUNET_free (egoNameStringEnc);
543 *(ptr++) = ':';
544 GNUNET_memcpy (ptr, anchorDataEnc, strlen (anchorDataEnc));
545 ptr += strlen (anchorDataEnc);
546 GNUNET_free (anchorDataEnc);
547 *(ptr++) = '\0';
548
549 return anchorString;
550}
551
552
553/**
554 * Convert a method name string to the respective enum number
555 *
556 * @param methodString the method name string
557 *
558 * @return the enum number
559 */
560enum GNUNET_ESCROW_Key_Escrow_Method
561GNUNET_ESCROW_method_string_to_number (const char *methodString)
562{
563 if (NULL == methodString)
564 return GNUNET_ESCROW_KEY_NONE;
565 if (!strcmp (plaintext_string, methodString))
566 return GNUNET_ESCROW_KEY_PLAINTEXT;
567 else if (!strcmp (gns_string, methodString))
568 return GNUNET_ESCROW_KEY_GNS;
569 else if (!strcmp (anastasis_string, methodString))
570 return GNUNET_ESCROW_KEY_ANASTASIS;
571 else
572 return GNUNET_ESCROW_KEY_NONE;
573}
574
575
576/**
577 * Convert a method enum number to the respective method string
578 *
579 * @param method the method enum number
580 *
581 * @return the method string
582 */
583const char *
584GNUNET_ESCROW_method_number_to_string (enum GNUNET_ESCROW_Key_Escrow_Method method)
585{
586 switch (method)
587 {
588 case GNUNET_ESCROW_KEY_PLAINTEXT:
589 return plaintext_string;
590 case GNUNET_ESCROW_KEY_GNS:
591 return gns_string;
592 case GNUNET_ESCROW_KEY_ANASTASIS:
593 return anastasis_string;
594 default:
595 return none_string;
596 }
597}
598
599
600/**
601 * Cancel an escrow operation.
602 *
603 * @param op operation to cancel
604 */
605void
606GNUNET_ESCROW_cancel (struct GNUNET_ESCROW_Operation *op)
607{
608 const struct GNUNET_ESCROW_KeyPluginFunctions *api;
609 struct GNUNET_ESCROW_Handle *h = op->h;
610
611 api = init_plugin (op->h, op->method);
612 api->cancel_plugin_operation (op->plugin_op_wrap);
613 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
614 GNUNET_free (op);
615}
616
617
618/* end of escrow_api.c */
diff --git a/src/escrow/escrow_plugin_helper.c b/src/escrow/escrow_plugin_helper.c
new file mode 100644
index 000000000..7192123d9
--- /dev/null
+++ b/src/escrow/escrow_plugin_helper.c
@@ -0,0 +1,438 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Johannes Späth
23 * @file escrow/escrow_plugin.c
24 *
25 * @brief helper functions for escrow plugins
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_escrow_plugin.h"
32#include "escrow.h"
33
34
35/**
36 * Maintains the ego list for an escrow plugin.
37 * This function is an implementation of GNUNET_IDENTITY_Callback.
38 *
39 * It is initially called for all egos and then again
40 * whenever a ego's identifier changes or if it is deleted. At the
41 * end of the initial pass over all egos, the function is once called
42 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
43 * be invoked in the future or that there was an error.
44 *
45 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
46 * this function is only called ONCE, and 'NULL' being passed in
47 * 'ego' does indicate an error (i.e. name is taken or no default
48 * value is known). If 'ego' is non-NULL and if '*ctx'
49 * is set in those callbacks, the value WILL be passed to a subsequent
50 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
51 * that one was not NULL).
52 *
53 * When an identity is renamed, this function is called with the
54 * (known) ego but the NEW identifier.
55 *
56 * When an identity is deleted, this function is called with the
57 * (known) ego and "NULL" for the 'identifier'. In this case,
58 * the 'ego' is henceforth invalid (and the 'ctx' should also be
59 * cleaned up).
60 *
61 * @param cls plugin handle
62 * @param ego ego handle
63 * @param ctx context for application to store data for this ego
64 * (during the lifetime of this process, initially NULL)
65 * @param identifier identifier assigned by the user for this ego,
66 * NULL if the user just deleted the ego and it
67 * must thus no longer be used
68 */
69void
70ESCROW_list_ego (void *cls,
71 struct GNUNET_IDENTITY_Ego *ego,
72 void **ctx,
73 const char *identifier)
74{
75 struct ESCROW_PluginHandle *ph = cls;
76 struct EgoEntry *ego_entry;
77 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
78
79 /* don't add/change/delete egos when we are already cleaning up */
80 if (ESCROW_PLUGIN_STATE_CLEANUP == ph->state)
81 return;
82
83 if ((NULL == ego) && (ESCROW_PLUGIN_STATE_INIT == ph->state))
84 {
85 ph->state = ESCROW_PLUGIN_STATE_POST_INIT;
86 /* call IdentityInitContinuation */
87 ph->id_init_cont ();
88 return;
89 }
90 GNUNET_assert (NULL != ego);
91
92 if (ESCROW_PLUGIN_STATE_INIT == ph->state)
93 {
94 ego_entry = GNUNET_new (struct EgoEntry);
95 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
96 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
97 ego_entry->ego = ego;
98 ego_entry->identifier = GNUNET_strdup (identifier);
99 GNUNET_CONTAINER_DLL_insert_tail (ph->ego_head,
100 ph->ego_tail,
101 ego_entry);
102 return;
103 }
104 /* Ego renamed or added */
105 if (identifier != NULL)
106 {
107 for (ego_entry = ph->ego_head; NULL != ego_entry;
108 ego_entry = ego_entry->next)
109 {
110 if (ego_entry->ego == ego)
111 {
112 /* Rename */
113 GNUNET_free (ego_entry->identifier);
114 ego_entry->identifier = GNUNET_strdup (identifier);
115 /* TODO: this handles an edge case when the user restores an ego
116 that already exists, i.e. with the same private key. In that case,
117 @param ego is the same for the new as for the existing ego and this
118 method thinks it is a rename. */
119 if (NULL != ph->ego_create_cont)
120 ph->ego_create_cont (ego);
121 break;
122 }
123 }
124 if (NULL == ego_entry)
125 {
126 /* Add */
127 ego_entry = GNUNET_new (struct EgoEntry);
128 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
129 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
130 ego_entry->ego = ego;
131 ego_entry->identifier = GNUNET_strdup (identifier);
132 GNUNET_CONTAINER_DLL_insert_tail (ph->ego_head,
133 ph->ego_tail,
134 ego_entry);
135 /* new ego is added to the list, call ego_create_cont if this was
136 because of an ESCROW_get operation, i.e. ego_create_cont != NULL */
137 if (NULL != ph->ego_create_cont)
138 ph->ego_create_cont (ego);
139 }
140 }
141 else
142 {
143 /* Delete */
144 for (ego_entry = ph->ego_head; NULL != ego_entry;
145 ego_entry = ego_entry->next)
146 {
147 if (ego_entry->ego == ego)
148 break;
149 }
150 if (NULL == ego_entry)
151 return; /* Not found */
152
153 GNUNET_CONTAINER_DLL_remove (ph->ego_head,
154 ph->ego_tail,
155 ego_entry);
156 GNUNET_free (ego_entry->identifier);
157 GNUNET_free (ego_entry->keystring);
158 GNUNET_free (ego_entry);
159 return;
160 }
161}
162
163
164/**
165 * Cleanup the ego list of an escrow plugin.
166 *
167 * @param ph handle for the plugin
168 */
169void
170ESCROW_cleanup_ego_list (struct ESCROW_PluginHandle *ph)
171{
172 struct EgoEntry *ego_entry;
173
174 while (NULL != (ego_entry = ph->ego_head))
175 {
176 GNUNET_CONTAINER_DLL_remove (ph->ego_head, ph->ego_tail, ego_entry);
177 GNUNET_free (ego_entry->identifier);
178 GNUNET_free (ego_entry->keystring);
179 GNUNET_free (ego_entry);
180 }
181}
182
183
184/**
185 * Build an anchor struct.
186 *
187 * @param method escrow method
188 * @param egoName name of the ego
189 * @param data anchor data
190 * @param data_size size of the anchor data
191 *
192 * @return a new anchor struct
193 */
194struct GNUNET_ESCROW_Anchor *
195ESCROW_build_anchor (enum GNUNET_ESCROW_Key_Escrow_Method method,
196 const char *egoName,
197 void *data,
198 uint32_t data_size)
199{
200 struct GNUNET_ESCROW_Anchor *anchor;
201 char *ptr;
202
203 anchor = GNUNET_malloc (sizeof (struct GNUNET_ESCROW_Anchor)
204 + data_size
205 + strlen (egoName) + 1);
206 anchor->method = method;
207 anchor->size = data_size;
208 ptr = (char *)&anchor[1];
209 GNUNET_memcpy (ptr, data, data_size);
210 ptr += data_size;
211 anchor->egoName = ptr;
212 strcpy (ptr, egoName);
213
214 return anchor;
215}
216
217
218static char *
219string_to_upper (const char *str)
220{
221 char *str_upper;
222 uint16_t i;
223
224 str_upper = GNUNET_strdup (str);
225
226 for (i = 0; i < strlen(str_upper); i++)
227 {
228 if (str_upper[i] >= 'a' && str_upper[i] <= 'z')
229 str_upper[i] -= 32; // 'a' - 'A' = 32
230 }
231
232 return str_upper;
233}
234
235
236static int
237write_config (struct GNUNET_ESCROW_Handle *h)
238{
239 char *conf_file;
240
241 GNUNET_assert (GNUNET_OK ==
242 GNUNET_CONFIGURATION_get_value_filename (h->cfg,
243 "PATHS",
244 "DEFAULTCONFIG",
245 &conf_file));
246 if (GNUNET_OK != GNUNET_CONFIGURATION_write (h->cfg, conf_file))
247 {
248 fprintf (stderr, "unable to write config file\n");
249 GNUNET_free (conf_file);
250 return GNUNET_NO;
251 }
252
253 GNUNET_free (conf_file);
254
255 return GNUNET_OK;
256}
257
258
259static char *
260get_config_section (struct GNUNET_IDENTITY_Ego *ego)
261{
262 struct GNUNET_CRYPTO_EcdsaPublicKey *pub;
263 char *config_section, *pubkey_string;
264
265 pub = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
266 GNUNET_IDENTITY_ego_get_public_key (ego, pub);
267 pubkey_string = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub);
268
269 // allocate enough space for "escrow-PUBKEY"
270 config_section = GNUNET_malloc (7 + strlen (pubkey_string) + 1);
271 sprintf (config_section, "escrow-%s", pubkey_string);
272
273 GNUNET_free (pubkey_string);
274
275 return config_section;
276}
277
278
279/**
280 * Update the status of an escrow in the configuration after a successful
281 * VERIFY operation.
282 *
283 * @param h handle for the escrow component
284 * @param ego the ego of which the escrow status is updated
285 * @param plugin_name the name of the used plugin
286 *
287 * @return GNUNET_OK on success
288 */
289int
290ESCROW_update_escrow_status_verify (struct GNUNET_ESCROW_Handle *h,
291 struct GNUNET_IDENTITY_Ego *ego,
292 const char *plugin_name)
293{
294 char *config_section, *config_option, *plugin_name_upper;
295 struct GNUNET_TIME_Absolute now, next_verification;
296 struct GNUNET_TIME_Relative escrow_interval;
297
298 config_section = get_config_section (ego);
299
300 // allocate enough space for "<plugin_name>_VERIFY_INTERVAL"
301 config_option = GNUNET_malloc (strlen (plugin_name) + 16 + 1);
302 plugin_name_upper = string_to_upper (plugin_name);
303 sprintf (config_option, "%s_VERIFY_INTERVAL", plugin_name_upper);
304
305 now = GNUNET_TIME_absolute_get ();
306 GNUNET_CONFIGURATION_set_value_number (h->cfg,
307 config_section,
308 "LAST_SUCCESSFUL_VERIFICATION_TIME",
309 (unsigned long long)now.abs_value_us);
310 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (h->cfg,
311 "escrow",
312 config_option,
313 &escrow_interval))
314 {
315 fprintf (stderr, "could not find config value for verification interval\n");
316 GNUNET_free (config_section);
317 GNUNET_free (config_option);
318 GNUNET_free (plugin_name_upper);
319 return GNUNET_NO;
320 }
321 next_verification = GNUNET_TIME_absolute_add (now, escrow_interval);
322 GNUNET_CONFIGURATION_set_value_number (h->cfg,
323 config_section,
324 "NEXT_RECOMMENDED_VERIFICATION_TIME",
325 (unsigned long long)next_verification.abs_value_us);
326
327 if (GNUNET_OK != write_config (h))
328 {
329 GNUNET_free (config_section);
330 GNUNET_free (config_option);
331 GNUNET_free (plugin_name_upper);
332 return GNUNET_NO;
333 }
334
335 GNUNET_free (config_section);
336 GNUNET_free (config_option);
337 GNUNET_free (plugin_name_upper);
338
339 return GNUNET_OK;
340}
341
342
343/**
344 * Update the status of an escrow in the configuration after a PUT operation.
345 *
346 * @param h handle for the escrow component
347 * @param ego the ego of which the escrow status is updated
348 * @param plugin_name the name of the used plugin
349 *
350 * @return GNUNET_OK on success
351 */
352int
353ESCROW_update_escrow_status_put (struct GNUNET_ESCROW_Handle *h,
354 struct GNUNET_IDENTITY_Ego *ego,
355 const char *plugin_name)
356{
357 char *config_section;
358
359 config_section = get_config_section (ego);
360
361 GNUNET_CONFIGURATION_set_value_string (h->cfg,
362 config_section,
363 "ESCROW_METHOD",
364 plugin_name);
365
366 if (GNUNET_OK != write_config (h))
367 {
368 GNUNET_free (config_section);
369 return GNUNET_NO;
370 }
371
372 GNUNET_free (config_section);
373
374 return GNUNET_OK;
375}
376
377
378/**
379 * Get the status of an escrow from the configuration.
380 *
381 * @param h handle for the escrow component
382 * @param ego the ego of which the escrow status has to be obtained
383 *
384 * @return the status of the escrow, packed into a GNUNET_ESCROW_Status struct
385 */
386struct GNUNET_ESCROW_Status *
387ESCROW_get_escrow_status (struct GNUNET_ESCROW_Handle *h,
388 struct GNUNET_IDENTITY_Ego *ego)
389{
390 struct GNUNET_ESCROW_Status *status;
391 unsigned long long conf_last_verification, conf_next_verification;
392 char *config_section, *conf_escrow_method;
393
394 config_section = get_config_section (ego);
395
396 status = GNUNET_new (struct GNUNET_ESCROW_Status);
397 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (h->cfg,
398 config_section,
399 "LAST_SUCCESSFUL_VERIFICATION_TIME",
400 &conf_last_verification))
401 {
402 /* failed to get value from config, set last verification time to zero */
403 status->last_successful_verification_time = GNUNET_TIME_absolute_get_zero_();
404 }
405 else
406 status->last_successful_verification_time.abs_value_us = (uint64_t)conf_last_verification;
407
408 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (h->cfg,
409 config_section,
410 "NEXT_RECOMMENDED_VERIFICATION_TIME",
411 &conf_next_verification))
412 {
413 /* failed to get value from config, set next recommended verification to now */
414 status->next_recommended_verification_time = GNUNET_TIME_absolute_get ();
415 }
416 else
417 status->next_recommended_verification_time.abs_value_us = (uint64_t)conf_next_verification;
418
419 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (h->cfg,
420 config_section,
421 "ESCROW_METHOD",
422 &conf_escrow_method))
423 {
424 /* failed to get value from config, set last method to NONE */
425 status->last_method = GNUNET_ESCROW_KEY_NONE;
426 }
427 else
428 status->last_method = GNUNET_ESCROW_method_string_to_number (conf_escrow_method);
429
430 GNUNET_free (config_section);
431 if (NULL != conf_escrow_method)
432 GNUNET_free (conf_escrow_method);
433
434 return status;
435}
436
437
438/* end of escrow_plugin.c */
diff --git a/src/escrow/escrow_plugin_helper.h b/src/escrow/escrow_plugin_helper.h
new file mode 100644
index 000000000..d911800e6
--- /dev/null
+++ b/src/escrow/escrow_plugin_helper.h
@@ -0,0 +1,142 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Johannes Späth
23 * @file escrow/escrow_plugin.h
24 *
25 * @brief helper functions for escrow plugins
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_escrow_plugin.h"
32#include "escrow.h"
33
34
35/**
36 * Maintains the ego list for an escrow plugin.
37 * This function is an implementation of GNUNET_IDENTITY_Callback.
38 *
39 * It is initially called for all egos and then again
40 * whenever a ego's identifier changes or if it is deleted. At the
41 * end of the initial pass over all egos, the function is once called
42 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
43 * be invoked in the future or that there was an error.
44 *
45 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
46 * this function is only called ONCE, and 'NULL' being passed in
47 * 'ego' does indicate an error (i.e. name is taken or no default
48 * value is known). If 'ego' is non-NULL and if '*ctx'
49 * is set in those callbacks, the value WILL be passed to a subsequent
50 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
51 * that one was not NULL).
52 *
53 * When an identity is renamed, this function is called with the
54 * (known) ego but the NEW identifier.
55 *
56 * When an identity is deleted, this function is called with the
57 * (known) ego and "NULL" for the 'identifier'. In this case,
58 * the 'ego' is henceforth invalid (and the 'ctx' should also be
59 * cleaned up).
60 *
61 * @param cls plugin handle
62 * @param ego ego handle
63 * @param ctx context for application to store data for this ego
64 * (during the lifetime of this process, initially NULL)
65 * @param identifier identifier assigned by the user for this ego,
66 * NULL if the user just deleted the ego and it
67 * must thus no longer be used
68 */
69void
70ESCROW_list_ego (void *cls,
71 struct GNUNET_IDENTITY_Ego *ego,
72 void **ctx,
73 const char *identifier);
74
75
76/**
77 * Cleanup the ego list of an escrow plugin.
78 *
79 * @param ph handle for the plugin
80 */
81void
82ESCROW_cleanup_ego_list (struct ESCROW_PluginHandle *ph);
83
84
85/**
86 * Build an anchor struct.
87 *
88 * @param method escrow method
89 * @param egoName name of the ego
90 * @param data anchor data
91 * @param data_size size of the anchor data
92 *
93 * @return a new anchor struct
94 */
95struct GNUNET_ESCROW_Anchor *
96ESCROW_build_anchor (enum GNUNET_ESCROW_Key_Escrow_Method method,
97 const char *egoName,
98 void *data,
99 uint32_t data_size);
100
101
102/**
103 * Update the status of an escrow in the configuration after a VERIFY operation.
104 *
105 * @param h handle for the escrow component
106 * @param ego the ego of which the escrow status is updated
107 * @param plugin_name the name of the used plugin
108 *
109 * @return GNUNET_OK on success
110 */
111int
112ESCROW_update_escrow_status_verify (struct GNUNET_ESCROW_Handle *h,
113 struct GNUNET_IDENTITY_Ego *ego,
114 const char *plugin_name);
115
116
117/**
118 * Update the status of an escrow in the configuration after a PUT operation.
119 *
120 * @param h handle for the escrow component
121 * @param ego the ego of which the escrow status is updated
122 * @param plugin_name the name of the used plugin
123 *
124 * @return GNUNET_OK on success
125 */
126int
127ESCROW_update_escrow_status_put (struct GNUNET_ESCROW_Handle *h,
128 struct GNUNET_IDENTITY_Ego *ego,
129 const char *plugin_name);
130
131
132/**
133 * Get the status of an escrow from the configuration.
134 *
135 * @param h handle for the escrow component
136 * @param ego the ego of which the escrow status has to be obtained
137 *
138 * @return the status of the escrow, packed into a GNUNET_ESCROW_Status struct
139 */
140struct GNUNET_ESCROW_Status *
141ESCROW_get_escrow_status (struct GNUNET_ESCROW_Handle *h,
142 struct GNUNET_IDENTITY_Ego *ego);
diff --git a/src/escrow/gnunet-escrow.c b/src/escrow/gnunet-escrow.c
new file mode 100644
index 000000000..ad34dd8f3
--- /dev/null
+++ b/src/escrow/gnunet-escrow.c
@@ -0,0 +1,528 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Johannes Späth
22 * @file src/escrow/gnunet-escrow.c
23 * @brief Identity Escrow utility
24 *
25 */
26
27#include "platform.h"
28
29#include "gnunet_util_lib.h"
30#include "gnunet_escrow_lib.h"
31
32/**
33 * return value
34 */
35static int ret;
36
37/**
38 * -P option
39 */
40static char *put_ego;
41
42/**
43 * -V option
44 */
45static char *verify_ego;
46
47/**
48 * -G option
49 */
50static int get_flag;
51
52/**
53 * -S option
54 */
55static char *status_ego;
56
57/**
58 * The ego
59 */
60struct GNUNET_IDENTITY_Ego *ego;
61
62/**
63 * User secret string
64 */
65static char *user_secret_string;
66
67/**
68 * Anchor string
69 */
70static char *anchor_string;
71
72/**
73 * The escrow anchor
74 */
75struct GNUNET_ESCROW_Anchor *anchor;
76
77/**
78 * Plugin name
79 */
80static char *method_name;
81
82/**
83 * Escrow method
84 */
85enum GNUNET_ESCROW_Key_Escrow_Method method;
86
87/**
88 * Handle to the escrow component
89 */
90static struct GNUNET_ESCROW_Handle *escrow_handle;
91
92/**
93 * Escrow operation
94 */
95static struct GNUNET_ESCROW_Operation *escrow_op;
96
97/**
98 * Escrow status
99 */
100static struct GNUNET_ESCROW_Status *escrow_status;
101
102/**
103 * Handle to the identity service
104 */
105static struct GNUNET_IDENTITY_Handle *identity_handle;
106
107/**
108 * Cleanup task
109 */
110static struct GNUNET_SCHEDULER_Task *cleanup_task;
111
112
113/**
114 * Called to clean up the escrow component
115 */
116static void
117do_cleanup (void *cls)
118{
119 cleanup_task = NULL;
120 if (NULL != escrow_op)
121 {
122 GNUNET_ESCROW_cancel (escrow_op);
123 escrow_op = NULL;
124 }
125 if (NULL != escrow_handle)
126 GNUNET_ESCROW_fini (escrow_handle);
127 if (NULL != identity_handle)
128 GNUNET_IDENTITY_disconnect (identity_handle);
129 if (NULL != method_name)
130 {
131 GNUNET_free (method_name);
132 method_name = NULL;
133 }
134 if (NULL != user_secret_string)
135 {
136 GNUNET_free (user_secret_string);
137 user_secret_string = NULL;
138 }
139 if (NULL != anchor_string)
140 {
141 GNUNET_free (anchor_string);
142 anchor_string = NULL;
143 }
144 if (NULL != anchor)
145 {
146 GNUNET_free (anchor);
147 anchor = NULL;
148 }
149 if (NULL != put_ego)
150 {
151 GNUNET_free (put_ego);
152 put_ego = NULL;
153 }
154 if (NULL != verify_ego)
155 {
156 GNUNET_free (verify_ego);
157 verify_ego = NULL;
158 }
159 if (NULL != status_ego)
160 {
161 GNUNET_free (status_ego);
162 status_ego = NULL;
163 }
164 if (NULL != escrow_status)
165 {
166 GNUNET_free (escrow_status);
167 escrow_status = NULL;
168 }
169 if (NULL != ego)
170 {
171 /* does not have to be freed, as this is done when
172 cleaning up the ego list in the plugin */
173 ego = NULL;
174 }
175 method = -1;
176}
177
178
179static void
180put_cb (void *cls,
181 struct GNUNET_ESCROW_Anchor *anchor,
182 const char *emsg)
183{
184 char *anchorString;
185
186 escrow_op = NULL;
187
188 if (NULL == anchor)
189 {
190 ret = 1;
191 if (NULL != emsg)
192 fprintf (stderr, "Escrow failed: %s", emsg);
193 }
194 else
195 {
196 anchorString = GNUNET_ESCROW_anchor_data_to_string (anchor);
197
198 fprintf (stdout, "Escrow finished! Please keep the following anchor "
199 "in order to restore the key later!\n%s\n", anchorString);
200 }
201 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
202 GNUNET_free (anchor);
203}
204
205
206static void
207verify_cb (void *cls,
208 int verificationResult,
209 const char *emsg)
210{
211 escrow_op = NULL;
212
213 if (NULL != emsg)
214 fprintf (stderr, "%s", emsg);
215
216 switch (verificationResult)
217 {
218 case GNUNET_ESCROW_VALID:
219 fprintf (stdout, "Escrow is valid!\n");
220 break;
221 case GNUNET_ESCROW_SHARES_MISSING:
222 fprintf (stdout, "Escrow can be restored, but some shares are missing! "
223 "Please perform a new escrow.\n");
224 break;
225 case GNUNET_ESCROW_INVALID:
226 ret = 2;
227 fprintf (stdout, "Escrow is INvalid! Please perform a new escrow.\n");
228 break;
229 default:
230 ret = 1;
231 fprintf (stderr, "invalid verificationResult");
232 }
233 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
234}
235
236
237static void
238get_cb (void *cls,
239 struct GNUNET_IDENTITY_Ego *ego,
240 const char *emsg)
241{
242 escrow_op = NULL;
243
244 if (NULL == ego)
245 {
246 ret = 1;
247 if (NULL != emsg)
248 fprintf (stderr, "Escrow failed: %s", emsg);
249 }
250 else
251 fprintf (stdout, "Identity %s could successfully be restored!\n", anchor->egoName);
252 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
253}
254
255
256static void
257start_process ()
258{
259 /* put */
260 if (NULL != put_ego)
261 {
262 if (NULL == ego)
263 {
264 ret = 1;
265 fprintf (stderr, "Ego %s not found\n", put_ego);
266 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
267 return;
268 }
269 escrow_op = GNUNET_ESCROW_put (escrow_handle,
270 ego,
271 user_secret_string,
272 method,
273 &put_cb,
274 NULL);
275 return;
276 }
277 /* verify */
278 if (NULL != verify_ego)
279 {
280 if (NULL == ego)
281 {
282 ret = 1;
283 fprintf (stderr, "Ego %s not found\n", verify_ego);
284 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
285 return;
286 }
287 escrow_op = GNUNET_ESCROW_verify (escrow_handle,
288 ego,
289 anchor,
290 method,
291 &verify_cb,
292 NULL);
293 return;
294 }
295 /* get */
296 if (GNUNET_YES == get_flag)
297 {
298 escrow_op = GNUNET_ESCROW_get (escrow_handle,
299 anchor,
300 &get_cb,
301 NULL);
302 return;
303 }
304 /* status */
305 if (NULL != status_ego)
306 {
307 if (NULL == ego)
308 {
309 ret = 1;
310 fprintf (stderr, "Ego %s not found\n", status_ego);
311 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
312 return;
313 }
314 escrow_status = GNUNET_ESCROW_get_status (escrow_handle,
315 ego,
316 method);
317
318 if (GNUNET_ESCROW_KEY_NONE == escrow_status->last_method)
319 fprintf (stdout, "No escrow has been performed for identity %s!\n", status_ego);
320 else
321 {
322 fprintf (stdout, "Escrow STATUS information for identity %s\n", status_ego);
323 fprintf (stdout, "=======================================================\n");
324 if (0 == escrow_status->last_successful_verification_time.abs_value_us)
325 fprintf (stdout, "No successful verification! Please VERIFY now.\n");
326 else
327 {
328 fprintf (stdout, "Last successful verification:\t%s\n",
329 GNUNET_STRINGS_absolute_time_to_string (escrow_status->last_successful_verification_time));
330 fprintf (stdout, "Next recommended verification:\t%s\n",
331 GNUNET_STRINGS_absolute_time_to_string (escrow_status->next_recommended_verification_time));
332 }
333 fprintf (stdout, "Last method:\t\t\t%s\n",
334 GNUNET_ESCROW_method_number_to_string (escrow_status->last_method));
335 }
336
337 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
338 return;
339 }
340}
341
342
343static int init = GNUNET_YES;
344
345static void
346ego_cb (void *cls,
347 struct GNUNET_IDENTITY_Ego *e,
348 void **ctx,
349 const char *name)
350{
351 char *ego_name = cls;
352
353 if (NULL == name)
354 {
355 if (GNUNET_YES == init)
356 {
357 init = GNUNET_NO;
358 start_process ();
359 }
360 return;
361 }
362 if (NULL != ego_name && 0 != strcmp (name, ego_name))
363 return;
364 ego = e;
365}
366
367
368static void
369run (void *cls,
370 char *const *args,
371 const char *cfgfile,
372 const struct GNUNET_CONFIGURATION_Handle *c)
373{
374 char *ego_name;
375
376 ret = 0;
377
378 /* check if method is set (needed for all operations except GET) */
379 if (NULL == method_name && GNUNET_YES != get_flag)
380 {
381 ret = 1;
382 fprintf (stderr, _ ("Escrow method (-m option) is missing\n"));
383 return;
384 }
385
386 if (NULL != put_ego)
387 {
388 if (NULL != verify_ego || GNUNET_YES == get_flag || NULL != status_ego)
389 {
390 ret = 1;
391 fprintf (stderr, _ ("-P may only be used without -V, -G or -S!\n"));
392 return;
393 }
394 /* put */
395 ego_name = put_ego;
396 }
397 else if (NULL != verify_ego)
398 {
399 if (GNUNET_YES == get_flag || NULL != status_ego)
400 {
401 ret = 1;
402 fprintf (stderr, _ ("-V may only be used without -P, -G or -S!\n"));
403 return;
404 }
405 /* verify */
406 if (NULL == anchor_string)
407 {
408 ret = 1;
409 fprintf (stderr, _ ("-a is needed for -V!\n"));
410 return;
411 }
412 ego_name = verify_ego;
413 }
414 else if (GNUNET_YES == get_flag)
415 {
416 if (NULL != status_ego)
417 {
418 ret = 1;
419 fprintf (stderr, _ ("-G may only be used without -P, -V or -S!\n"));
420 return;
421 }
422 /* get */
423 if (NULL == anchor_string)
424 {
425 ret = 1;
426 fprintf (stderr, _ ("-a is needed for -G!\n"));
427 return;
428 }
429 ego_name = NULL;
430 }
431 else if (NULL != status_ego)
432 {
433 /* status */
434 ego_name = status_ego;
435 }
436 else
437 {
438 /* nothing */
439 ret = 1;
440 fprintf (stderr, _ ("-P, -V, -G or -S option must be specified!\n"));
441 return;
442 }
443
444 /* determine method */
445 if (NULL != method_name)
446 {
447 method = GNUNET_ESCROW_method_string_to_number (method_name);
448 if (GNUNET_ESCROW_KEY_NONE == method)
449 {
450 ret = 1;
451 fprintf (stderr, _ ("unknown method name!\n"));
452 return;
453 }
454 }
455 else // initialize to error value (should not be used in this case)
456 method = GNUNET_ESCROW_KEY_NONE;
457
458 escrow_handle = GNUNET_ESCROW_init (c);
459
460 if (NULL != anchor_string)
461 {
462 /* parse anchor_string according to method */
463 anchor = GNUNET_ESCROW_anchor_string_to_data (anchor_string);
464 if (NULL == anchor)
465 {
466 ret = 1;
467 fprintf (stderr, _ ("failed to parse anchor string!\n"));
468 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
469 return;
470 }
471 }
472
473 /* connect to identity service in order to get the egos */
474 identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, ego_name);
475}
476
477
478int
479main (int argc, char *const argv[])
480{
481 struct GNUNET_GETOPT_CommandLineOption options[] = {
482 GNUNET_GETOPT_option_string ('P',
483 "put",
484 "NAME",
485 gettext_noop ("Put the ego NAME in escrow"),
486 &put_ego),
487 GNUNET_GETOPT_option_string ('V',
488 "verify",
489 "NAME",
490 gettext_noop ("Verify the escrow of the ego NAME"),
491 &verify_ego),
492 GNUNET_GETOPT_option_flag ('G',
493 "get",
494 gettext_noop ("Get an ego back from escrow"),
495 &get_flag),
496 GNUNET_GETOPT_option_string ('S',
497 "status",
498 "NAME",
499 gettext_noop ("Get the status of the escrow of ego NAME"),
500 &status_ego),
501 GNUNET_GETOPT_option_string ('u',
502 "userSecret",
503 "USER_SECRET",
504 gettext_noop ("The user secret string"),
505 &user_secret_string),
506 GNUNET_GETOPT_option_string ('a',
507 "anchor",
508 "ANCHOR",
509 gettext_noop ("The escrow anchor"),
510 &anchor_string),
511 GNUNET_GETOPT_option_string ('m',
512 "method",
513 "METHOD",
514 gettext_noop ("The escrow method (and plugin) to use"),
515 &method_name),
516 GNUNET_GETOPT_OPTION_END
517 };
518 if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
519 argv,
520 "gnunet-escrow",
521 _ ("escrow command line tool"),
522 options,
523 &run,
524 NULL))
525 return 1;
526 else
527 return ret;
528}
diff --git a/src/escrow/plugin_escrow_anastasis.c b/src/escrow/plugin_escrow_anastasis.c
new file mode 100644
index 000000000..8a5c05e24
--- /dev/null
+++ b/src/escrow/plugin_escrow_anastasis.c
@@ -0,0 +1,231 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file escrow/plugin_escrow_anastasis.c
23 * @brief escrow-plugin-anastasis escrow plugin for escrow of the key using Anastasis
24 *
25 * @author Johannes Späth
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_escrow_plugin.h"
30#include "escrow_plugin_helper.h"
31#include <inttypes.h>
32
33
34/**
35 * Identity handle
36 */
37static struct GNUNET_IDENTITY_Handle *identity_handle;
38
39/**
40 * Handle for the plugin instance
41 */
42static struct ESCROW_PluginHandle ph;
43
44
45/**
46 * Start the Anastasis escrow of the key
47 *
48 * @param h the handle for the escrow component
49 * @param ego the identity ego containing the private key
50 * @param userSecret the user secret (e.g. for derivation of escrow identities)
51 * @param cb the function called upon completion
52 * @param op_id unique ID of the respective ESCROW_Operation
53 *
54 * @return plugin operation wrapper
55 */
56struct ESCROW_PluginOperationWrapper *
57start_anastasis_key_escrow (struct GNUNET_ESCROW_Handle *h,
58 struct GNUNET_IDENTITY_Ego *ego,
59 const char *userSecret,
60 GNUNET_SCHEDULER_TaskCallback cb,
61 uint32_t op_id)
62{
63 struct ESCROW_Plugin_AnchorContinuationWrapper *w;
64
65 w = GNUNET_new (struct ESCROW_Plugin_AnchorContinuationWrapper);
66 w->h = h;
67 w->op_id = op_id;
68
69 // TODO: implement
70 w->anchor = NULL;
71 w->emsg = _ ("Anastasis escrow is not yet implemented!\n");
72 GNUNET_SCHEDULER_add_now (cb, w);
73 return NULL;
74}
75
76
77/**
78 * Verify the Anastasis escrow of the key
79 *
80 * @param h the handle for the escrow component
81 * @param ego the identity ego containing the private key
82 * @param anchor the escrow anchor needed to restore the key
83 * @param cb the function called upon completion
84 * @param op_id unique ID of the respective ESCROW_Operation
85 *
86 * @return plugin operation wrapper
87 */
88struct ESCROW_PluginOperationWrapper *
89verify_anastasis_key_escrow (struct GNUNET_ESCROW_Handle *h,
90 struct GNUNET_IDENTITY_Ego *ego,
91 const struct GNUNET_ESCROW_Anchor *anchor,
92 GNUNET_SCHEDULER_TaskCallback cb,
93 uint32_t op_id)
94{
95 struct ESCROW_Plugin_VerifyContinuationWrapper *w;
96
97 w = GNUNET_new (struct ESCROW_Plugin_VerifyContinuationWrapper);
98 w->h = h;
99 w->op_id = op_id;
100
101 // TODO: implement
102 w->verificationResult = GNUNET_ESCROW_INVALID;
103 w->emsg = _ ("Anastasis escrow is not yet implemented!\n");
104 GNUNET_SCHEDULER_add_now (cb, w);
105 return NULL;
106}
107
108
109/**
110 * Restore the key from Anastasis escrow
111 *
112 * @param h the handle for the escrow component
113 * @param anchor the escrow anchor needed to restore the key
114 * @param cb the function called upon completion
115 * @param op_id unique ID of the respective ESCROW_Operation
116 *
117 * @return plugin operation wrapper
118 */
119struct ESCROW_PluginOperationWrapper *
120restore_anastasis_key_escrow (struct GNUNET_ESCROW_Handle *h,
121 const struct GNUNET_ESCROW_Anchor *anchor,
122 GNUNET_SCHEDULER_TaskCallback cb,
123 uint32_t op_id)
124{
125 struct ESCROW_Plugin_EgoContinuationWrapper *w;
126
127 w = GNUNET_new (struct ESCROW_Plugin_EgoContinuationWrapper);
128 w->h = h;
129 w->op_id = op_id;
130
131 // TODO: implement
132 w->ego = NULL;
133 w->emsg = _ ("Anastasis escrow is not yet implemented!\n");
134 GNUNET_SCHEDULER_add_now (cb, w);
135 return NULL;
136}
137
138
139/**
140 * Get the status of a Anastasis escrow
141 *
142 * @param h the handle for the escrow component
143 * @param ego the identity ego of which the status has to be obtained
144 *
145 * @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
146 */
147struct GNUNET_ESCROW_Status *
148anastasis_get_status (struct GNUNET_ESCROW_Handle *h,
149 struct GNUNET_IDENTITY_Ego *ego)
150{
151 return ESCROW_get_escrow_status (h, ego);
152}
153
154
155/**
156 * Cancel an Anastasis plugin operation.
157 *
158 * @param plugin_op_wrap the plugin operation wrapper containing the operation
159 */
160void
161cancel_anastasis_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
162{
163 // TODO: implement
164 return;
165}
166
167
168/**
169 * IdentityInitContinuation for the Anastasis plugin
170 */
171static void
172anastasis_cont_init ()
173{
174 return;
175}
176
177
178/**
179 * Entry point for the plugin.
180 *
181 * @param cls Config info
182 *
183 * @return the exported block API
184 */
185void *
186libgnunet_plugin_escrow_anastasis_init (void *cls)
187{
188 struct GNUNET_ESCROW_KeyPluginFunctions *api;
189 struct GNUNET_CONFIGURATION_Handle *cfg = cls;
190
191 api = GNUNET_new (struct GNUNET_ESCROW_KeyPluginFunctions);
192 api->start_key_escrow = &start_anastasis_key_escrow;
193 api->verify_key_escrow = &verify_anastasis_key_escrow;
194 api->restore_key = &restore_anastasis_key_escrow;
195 api->get_status = &anastasis_get_status;
196 api->cancel_plugin_operation = &cancel_anastasis_operation;
197
198 ph.state = ESCROW_PLUGIN_STATE_INIT;
199 ph.id_init_cont = &anastasis_cont_init;
200
201 identity_handle = GNUNET_IDENTITY_connect (cfg,
202 &ESCROW_list_ego,
203 &ph);
204
205 return api;
206}
207
208
209/**
210 * Exit point from the plugin.
211 *
212 * @param cls the return value from #libgnunet_plugin_block_test_init()
213 *
214 * @return NULL
215 */
216void *
217libgnunet_plugin_escrow_anastasis_done (void *cls)
218{
219 struct GNUNET_ESCROW_KeyPluginFunctions *api = cls;
220
221 ph.state = ESCROW_PLUGIN_STATE_CLEANUP;
222
223 GNUNET_free (api);
224 GNUNET_IDENTITY_disconnect (identity_handle);
225 ESCROW_cleanup_ego_list (&ph);
226
227 return NULL;
228}
229
230
231/* end of plugin_escrow_anastasis.c */
diff --git a/src/escrow/plugin_escrow_gns.c b/src/escrow/plugin_escrow_gns.c
new file mode 100644
index 000000000..6889d1dd0
--- /dev/null
+++ b/src/escrow/plugin_escrow_gns.c
@@ -0,0 +1,1842 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file escrow/plugin_escrow_gns.c
23 * @brief escrow-plugin-gns escrow plugin for the escrow of the key
24 * using GNS and escrow identities
25 *
26 * @author Johannes Späth
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_escrow_plugin.h"
31#include "escrow_plugin_helper.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_gns_service.h"
34#include "gnunet_gnsrecord_lib.h"
35#include "escrow.h"
36#include <sss.h>
37#include <inttypes.h>
38
39
40/**
41 * Continuation with a private key (used for restore_private_key)
42 */
43typedef void (*PkContinuation) (void *cls,
44 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk);
45
46
47struct IdentityOperationEntry
48{
49 /**
50 * DLL
51 */
52 struct IdentityOperationEntry *prev;
53
54 /**
55 * DLL
56 */
57 struct IdentityOperationEntry *next;
58
59 /**
60 * Identity operation
61 */
62 struct GNUNET_IDENTITY_Operation *id_op;
63
64 /**
65 * Private key of the respective ego
66 */
67 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
68
69 /**
70 * Name of the respective ego
71 */
72 char *name;
73
74 /**
75 * Index of the respective share
76 */
77 uint8_t i;
78
79 /**
80 * The plugin operation that started the identity operation
81 */
82 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
83};
84
85
86struct PkEntry
87{
88 /**
89 * DLL
90 */
91 struct PkEntry *prev;
92
93 /**
94 * DLL
95 */
96 struct PkEntry *next;
97
98 /**
99 * private key
100 */
101 struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
102
103 /**
104 * index of the respective share
105 */
106 uint8_t i;
107};
108
109
110struct NamestoreQueueEntry
111{
112 /**
113 * DLL
114 */
115 struct NamestoreQueueEntry *prev;
116
117 /**
118 * DLL
119 */
120 struct NamestoreQueueEntry *next;
121
122 /**
123 * Namestore queue entry
124 */
125 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
126
127 /**
128 * Plugin operation that called the namestore operation
129 */
130 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
131};
132
133
134// define TimeoutTaskEntry here, as it is already needed in GnsLookupRequest
135struct TimeoutTaskEntry;
136
137
138struct GnsLookupRequestEntry
139{
140 /**
141 * DLL
142 */
143 struct GnsLookupRequestEntry *prev;
144
145 /**
146 * DLL
147 */
148 struct GnsLookupRequestEntry *next;
149
150 /**
151 * GNS lookup request
152 */
153 struct GNUNET_GNS_LookupRequest *lr;
154
155 /**
156 * Plugin operation that started the lookup
157 */
158 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
159
160 /**
161 * index of the respective share
162 */
163 uint8_t i;
164
165 /**
166 * Timeout task scheduled for this lookup request
167 */
168 struct TimeoutTaskEntry *tt;
169};
170
171
172struct TimeoutTaskEntry
173{
174 /**
175 * DLL
176 */
177 struct TimeoutTaskEntry *prev;
178
179 /**
180 * DLL
181 */
182 struct TimeoutTaskEntry *next;
183
184 /**
185 * Timeout task
186 */
187 struct GNUNET_SCHEDULER_Task *tt;
188
189 /**
190 * GNS lookup request this timeout is for
191 */
192 struct GnsLookupRequestEntry *gns_lr;
193
194 /**
195 * Plugin operation that started the timeout
196 */
197 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
198};
199
200
201struct ESCROW_GnsPluginOperation
202{
203 /**
204 * Handle for the escrow component
205 */
206 struct GNUNET_ESCROW_Handle *h;
207
208 /**
209 * Scheduler task the SCHEDULE operation returns (needed for cancellation)
210 */
211 struct GNUNET_SCHEDULER_Task *sched_task;
212
213 /**
214 * Namestore handle
215 */
216 struct GNUNET_NAMESTORE_Handle *ns_h;
217
218 /**
219 * GNS handle
220 */
221 struct GNUNET_GNS_Handle *gns_h;
222
223 /**
224 * Continuation for a plugin operation (e.g. used for restore, as this
225 * callback has to be called from the IDENTITY service after finishing)
226 */
227 ESCROW_Plugin_Continuation cont;
228
229 /**
230 * Ego continuation wrapper
231 */
232 struct ESCROW_Plugin_EgoContinuationWrapper *ego_wrap;
233
234 /**
235 * Anchor continuation wrapper
236 */
237 struct ESCROW_Plugin_AnchorContinuationWrapper *anchor_wrap;
238
239 /**
240 * Verify continuation wrapper
241 */
242 struct ESCROW_Plugin_VerifyContinuationWrapper *verify_wrap;
243
244 /**
245 * Counter for the created escrow identities
246 */
247 uint8_t escrow_id_counter;
248
249 /**
250 * Number of shares
251 */
252 uint8_t shares;
253
254 /**
255 * Share threshold
256 */
257 uint8_t share_threshold;
258
259 /**
260 * Share expiration time
261 */
262 struct GNUNET_TIME_Relative share_expiration_time;
263
264 /**
265 * Continuation to be called with the restored private key
266 */
267 PkContinuation restore_pk_cont;
268
269 /**
270 * Closure for @a cont
271 */
272 void *restore_pk_cont_cls;
273
274 /**
275 * Array for the restored keyshares
276 */
277 sss_Keyshare *restored_keyshares;
278
279 /**
280 * Identity operation for the create of the restored ego
281 */
282 struct GNUNET_IDENTITY_Operation *id_op;
283
284 /**
285 * The ego
286 */
287 struct GNUNET_IDENTITY_Ego *ego;
288
289 /**
290 * The anchor
291 */
292 const struct GNUNET_ESCROW_Anchor *anchor;
293
294 /**
295 * The name of the ego
296 */
297 char *egoName;
298
299 /**
300 * Private key of the ego
301 */
302 struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
303
304 /**
305 * User secret string
306 */
307 char *userSecret;
308
309 /**
310 * DLL head for identity operations
311 */
312 struct IdentityOperationEntry *id_ops_head;
313
314 /**
315 * DLL tail for identity operations
316 */
317 struct IdentityOperationEntry *id_ops_tail;
318
319 /**
320 * DLL head for escrow private keys
321 */
322 struct PkEntry *escrow_pks_head;
323
324 /**
325 * DLL tail for escrow private keys
326 */
327 struct PkEntry *escrow_pks_tail;
328
329 /**
330 * DLL head for namestore queue entries
331 */
332 struct NamestoreQueueEntry *ns_qes_head;
333
334 /**
335 * DLL tail for namestore queue entries
336 */
337 struct NamestoreQueueEntry *ns_qes_tail;
338
339 /**
340 * DLL head for GNS lookup requests
341 */
342 struct GnsLookupRequestEntry *gns_lrs_head;
343
344 /**
345 * DLL tail for GNS lookup requests
346 */
347 struct GnsLookupRequestEntry *gns_lrs_tail;
348
349 /**
350 * DLL head for GNS timeout tasks
351 */
352 struct TimeoutTaskEntry *tts_head;
353
354 /**
355 * DLL tail for GNS timeout tasks
356 */
357 struct TimeoutTaskEntry *tts_tail;
358};
359
360/**
361 * Identity handle
362 */
363static struct GNUNET_IDENTITY_Handle *identity_handle;
364
365/**
366 * Handle for the plugin instance
367 */
368static struct ESCROW_PluginHandle ph;
369
370
371/**
372 * Clean up a plugin operation, i.e. remove it from the list and
373 * free the respective memory
374 */
375static void
376cleanup_plugin_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
377{
378 struct ESCROW_GnsPluginOperation *p_op;
379 struct IdentityOperationEntry *curr_id_op, *next_id_op;
380 struct PkEntry *curr_pk, *next_pk;
381 struct NamestoreQueueEntry *curr_ns_qe, *next_ns_qe;
382 struct GnsLookupRequestEntry *curr_gns_lr, *next_gns_lr;
383 struct TimeoutTaskEntry *curr_tt, *next_tt;
384
385 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
386
387 GNUNET_CONTAINER_DLL_remove (ph.plugin_op_head,
388 ph.plugin_op_tail,
389 plugin_op_wrap);
390 if (NULL != p_op->anchor_wrap)
391 GNUNET_free (p_op->anchor_wrap);
392 if (NULL != p_op->ego_wrap)
393 GNUNET_free (p_op->ego_wrap);
394 if (NULL != p_op->verify_wrap)
395 GNUNET_free (p_op->verify_wrap);
396 if (NULL != p_op->userSecret)
397 GNUNET_free (p_op->userSecret);
398 /* clean up identity operation list */
399 for (curr_id_op = p_op->id_ops_head; NULL != curr_id_op; curr_id_op = next_id_op)
400 {
401 next_id_op = curr_id_op->next;
402 GNUNET_CONTAINER_DLL_remove (p_op->id_ops_head,
403 p_op->id_ops_tail,
404 curr_id_op);
405 GNUNET_IDENTITY_cancel (curr_id_op->id_op);
406 GNUNET_free (curr_id_op->pk);
407 GNUNET_free (curr_id_op->name);
408 GNUNET_free (curr_id_op);
409 }
410 /* clean up escrow pk list */
411 for (curr_pk = p_op->escrow_pks_head; NULL != curr_pk; curr_pk = next_pk)
412 {
413 next_pk = curr_pk->next;
414 GNUNET_CONTAINER_DLL_remove (p_op->escrow_pks_head,
415 p_op->escrow_pks_tail,
416 curr_pk);
417 GNUNET_free (curr_pk);
418 }
419 /* clean up namestore operation list */
420 for (curr_ns_qe = p_op->ns_qes_head; NULL != curr_ns_qe; curr_ns_qe = next_ns_qe)
421 {
422 next_ns_qe = curr_ns_qe->next;
423 GNUNET_CONTAINER_DLL_remove (p_op->ns_qes_head,
424 p_op->ns_qes_tail,
425 curr_ns_qe);
426 // also frees the curr_ns_qe->ns_qe
427 GNUNET_NAMESTORE_cancel (curr_ns_qe->ns_qe);
428 GNUNET_free (curr_ns_qe);
429 }
430 /* clean up GNS lookup request list */
431 for (curr_gns_lr = p_op->gns_lrs_head; NULL != curr_gns_lr; curr_gns_lr = next_gns_lr)
432 {
433 next_gns_lr = curr_gns_lr->next;
434 GNUNET_CONTAINER_DLL_remove (p_op->gns_lrs_head,
435 p_op->gns_lrs_tail,
436 curr_gns_lr);
437 GNUNET_GNS_lookup_cancel (curr_gns_lr->lr);
438 GNUNET_free (curr_gns_lr);
439 }
440 /* clean up timeout task list */
441 for (curr_tt = p_op->tts_head; NULL != curr_tt; curr_tt = next_tt)
442 {
443 next_tt = curr_tt->next;
444 GNUNET_CONTAINER_DLL_remove (p_op->tts_head,
445 p_op->tts_tail,
446 curr_tt);
447 GNUNET_SCHEDULER_cancel (curr_tt->tt);
448 GNUNET_free (curr_tt);
449 }
450 /* free the keyshares array */
451 if (NULL != p_op->restored_keyshares)
452 GNUNET_free (p_op->restored_keyshares);
453 /* disconnect from namestore service */
454 if (NULL != p_op->ns_h)
455 GNUNET_NAMESTORE_disconnect (p_op->ns_h);
456 /* disconnect from GNS service */
457 if (NULL != p_op->gns_h)
458 GNUNET_GNS_disconnect (p_op->gns_h);
459 /* cancel scheduled task */
460 if (NULL != p_op->sched_task)
461 GNUNET_SCHEDULER_cancel (p_op->sched_task);
462 /* cancel identity operation */
463 if (NULL != p_op->id_op)
464 GNUNET_IDENTITY_cancel (p_op->id_op);
465 if (NULL != p_op->egoName)
466 GNUNET_free (p_op->egoName);
467 GNUNET_free (p_op);
468 GNUNET_free (plugin_op_wrap);
469}
470
471
472static void
473start_cont (void *cls)
474{
475 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
476 struct ESCROW_GnsPluginOperation *p_op;
477
478 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
479 p_op->sched_task = NULL;
480 p_op->cont (p_op->anchor_wrap);
481
482 cleanup_plugin_operation (plugin_op_wrap);
483}
484
485
486static void
487verify_cont (void *cls)
488{
489 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
490 struct ESCROW_GnsPluginOperation *p_op;
491
492 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
493 p_op->sched_task = NULL;
494 p_op->cont (p_op->verify_wrap);
495
496 cleanup_plugin_operation (plugin_op_wrap);
497}
498
499
500static void
501handle_restore_error (void *cls)
502{
503 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
504 struct ESCROW_GnsPluginOperation *p_op;
505
506 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
507 p_op->sched_task = NULL;
508 p_op->cont (p_op->ego_wrap);
509
510 cleanup_plugin_operation (plugin_op_wrap);
511}
512
513
514sss_Keyshare *
515split_private_key (struct ESCROW_GnsPluginOperation *p_op)
516{
517 sss_Keyshare *keyshares;
518
519 keyshares = GNUNET_malloc (sizeof (sss_Keyshare) * p_op->shares);
520 sss_create_keyshares (keyshares,
521 p_op->pk.d,
522 p_op->shares,
523 p_op->share_threshold);
524
525 return keyshares;
526}
527
528
529static void
530keyshare_distribution_finished (void *cls)
531{
532 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
533 struct ESCROW_GnsPluginOperation *p_op;
534
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All keyshares distributed\n");
536
537 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
538
539 p_op->anchor_wrap->anchor = ESCROW_build_anchor (GNUNET_ESCROW_KEY_GNS,
540 p_op->egoName,
541 p_op->userSecret,
542 strlen (p_op->userSecret));
543
544 /* update escrow status, i.e. set the last escrow method */
545 ESCROW_update_escrow_status_put (p_op->h, p_op->ego, "gns");
546
547 /* call the continuation */
548 start_cont (plugin_op_wrap);
549}
550
551
552static void
553keyshare_distributed (void *cls,
554 int32_t success,
555 const char *emsg)
556{
557 struct NamestoreQueueEntry *ns_qe = cls;
558 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
559 struct ESCROW_GnsPluginOperation *p_op;
560
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Keyshare distributed\n");
562
563 plugin_op_wrap = ns_qe->plugin_op_wrap;
564 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
565
566 // remove qe from our list
567 GNUNET_CONTAINER_DLL_remove (p_op->ns_qes_head,
568 p_op->ns_qes_tail,
569 ns_qe);
570
571 if (GNUNET_SYSERR == success)
572 {
573 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
574 "Failed to store keyshare %s\n",
575 emsg);
576 p_op->anchor_wrap->anchor = NULL;
577 p_op->anchor_wrap->emsg = _ ("Keyshare distribution failed!\n");
578 p_op->cont (p_op->anchor_wrap);
579 // this also cancels all running namestore operations
580 cleanup_plugin_operation (plugin_op_wrap);
581 return;
582 }
583
584 // check if all namestore operations are finished
585 GNUNET_free (ns_qe);
586 if (NULL == p_op->ns_qes_head)
587 {
588 // schedule the further execution, lets NAMESTORE clean up its operation list
589 GNUNET_SCHEDULER_add_now (&keyshare_distribution_finished, plugin_op_wrap);
590 }
591}
592
593
594static char *
595get_label (const char *userSecret)
596{
597 char *label;
598 struct GNUNET_HashCode hash;
599 struct GNUNET_CRYPTO_HashAsciiEncoded hashEnc;
600
601 // the label is the hash of the userSecret
602 GNUNET_CRYPTO_hash (userSecret, strlen (userSecret), &hash);
603 GNUNET_CRYPTO_hash_to_enc (&hash, &hashEnc);
604 label = GNUNET_strdup ((char *)hashEnc.encoding);
605
606 return label;
607}
608
609
610static int
611distribute_keyshares (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
612 sss_Keyshare *keyshares)
613{
614 struct ESCROW_GnsPluginOperation *p_op;
615 struct GNUNET_NAMESTORE_Handle *ns_h;
616 struct NamestoreQueueEntry *curr_ns_qe;
617 struct PkEntry *curr_pk;
618 char *curr_label;
619 struct GNUNET_GNSRECORD_Data curr_rd[1];
620
621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Distributing keyshares\n");
622
623 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
624
625 ns_h = GNUNET_NAMESTORE_connect (p_op->h->cfg);
626 p_op->ns_h = ns_h;
627
628 for (curr_pk = p_op->escrow_pks_head; NULL != curr_pk; curr_pk = curr_pk->next)
629 {
630 curr_label = get_label (p_op->userSecret);
631 curr_ns_qe = GNUNET_new (struct NamestoreQueueEntry);
632
633 curr_rd[0].data_size = sizeof (sss_Keyshare);
634 curr_rd[0].data = keyshares[curr_pk->i];
635 curr_rd[0].record_type = GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE;
636 curr_rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
637 curr_rd[0].expiration_time = p_op->share_expiration_time.rel_value_us;
638
639 curr_ns_qe->plugin_op_wrap = plugin_op_wrap;
640 curr_ns_qe->ns_qe = GNUNET_NAMESTORE_records_store (ns_h,
641 &curr_pk->pk,
642 curr_label,
643 1,
644 curr_rd,
645 &keyshare_distributed,
646 curr_ns_qe);
647 GNUNET_CONTAINER_DLL_insert_tail (p_op->ns_qes_head,
648 p_op->ns_qes_tail,
649 curr_ns_qe);
650 GNUNET_free (curr_label);
651 }
652
653 return GNUNET_OK;
654}
655
656
657void
658escrow_ids_finished (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
659{
660 struct ESCROW_GnsPluginOperation *p_op;
661 sss_Keyshare *keyshares;
662
663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All escrow identities created\n");
664
665 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
666
667 /* split the private key (SSS) */
668 keyshares = split_private_key (p_op);
669 if (NULL == keyshares)
670 {
671 p_op->anchor_wrap->anchor = NULL;
672 p_op->anchor_wrap->emsg = _ ("Failed to split the key!\n");
673 start_cont (plugin_op_wrap);
674 return;
675 }
676
677 /* distribute the shares to the identities */
678 if (GNUNET_OK != distribute_keyshares (plugin_op_wrap, keyshares))
679 {
680 p_op->anchor_wrap->anchor = NULL;
681 p_op->anchor_wrap->emsg = _ ("Failed to distribute the keyshares!\n");
682 start_cont (plugin_op_wrap);
683 return;
684 }
685
686 /* operation continues in keyshare_distribution_finished
687 after all keyshares have been distributed */
688}
689
690
691void
692escrow_id_created (void *cls,
693 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
694 const char *emsg)
695{
696 struct IdentityOperationEntry *id_op = cls;
697 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
698 struct ESCROW_GnsPluginOperation *p_op;
699 struct PkEntry *pk_entry;
700
701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Escrow identity %d created\n", id_op->i);
702
703 plugin_op_wrap = id_op->plugin_op_wrap;
704 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
705
706 if (NULL == pk)
707 {
708 if (NULL != emsg)
709 {
710 fprintf (stderr,
711 "Identity create operation returned with error: %s\n",
712 emsg);
713 p_op->anchor_wrap->emsg = _ ("Identity create failed!\n");
714 }
715 else
716 p_op->anchor_wrap->emsg = _ ("Failed to create ego!\n");
717 p_op->anchor_wrap->anchor = NULL;
718 p_op->cont (p_op->anchor_wrap);
719 // this also cancels all running identity operations
720 cleanup_plugin_operation (plugin_op_wrap);
721 return;
722 }
723
724 /* escrow identity successfully created */
725 GNUNET_CONTAINER_DLL_remove (p_op->id_ops_head,
726 p_op->id_ops_tail,
727 id_op);
728
729 /* insert pk into our list */
730 pk_entry = GNUNET_new (struct PkEntry);
731 pk_entry->pk = *pk;
732 pk_entry->i = id_op->i;
733 GNUNET_CONTAINER_DLL_insert_tail (p_op->escrow_pks_head,
734 p_op->escrow_pks_tail,
735 pk_entry);
736
737 GNUNET_free (id_op);
738
739 /* check if this was the last id_op */
740 p_op->escrow_id_counter++;
741 if (p_op->escrow_id_counter == p_op->shares)
742 {
743 escrow_ids_finished (plugin_op_wrap);
744 }
745}
746
747
748static uint8_t
749count_digits (uint8_t n)
750{
751 uint8_t i = 0;
752
753 do
754 {
755 i++;
756 n /= 10;
757 } while (n != 0);
758
759 return i;
760}
761
762
763static char *
764get_escrow_id_name (const char *name,
765 uint8_t i)
766{
767 char *str, *prefix, *number;
768 uint8_t j = 0;
769
770 prefix = "escrow-id_";
771 number = GNUNET_malloc (count_digits (i) + 1);
772 sprintf (number, "%d", i);
773
774 str = GNUNET_malloc (strlen (prefix)
775 + strlen (name)
776 + 1
777 + strlen (number)
778 + 1);
779
780 memcpy (str, prefix, strlen (prefix));
781 j += strlen (prefix);
782 memcpy (str + j, name, strlen (name));
783 j += strlen (name);
784 str[j++] = '_';
785 memcpy (str + j, number, strlen (number));
786 j += strlen (number);
787 str[j] = '\0';
788
789 GNUNET_free (number);
790
791 return str;
792}
793
794
795static int
796escrow_id_exists (const char *name,
797 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
798{
799 struct EgoEntry *curr;
800
801 for (curr = ph.ego_head; NULL != curr; curr = curr->next)
802 {
803 if (0 == strcmp (name, curr->identifier))
804 {
805 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (curr->ego),
806 pk,
807 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
808 return GNUNET_YES;
809 else // the escrow id's name exists for an ego, but the pk is wrong
810 return GNUNET_SYSERR;
811 }
812 }
813
814 return GNUNET_NO;
815}
816
817
818static struct GNUNET_CRYPTO_EcdsaPrivateKey *
819derive_private_key (const char *name,
820 const char *password,
821 uint8_t i)
822{
823 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
824 static const char ctx[] = "gnunet-escrow-id-ctx";
825
826 pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
827 GNUNET_CRYPTO_kdf (pk,
828 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
829 ctx, strlen (ctx),
830 password, strlen (password),
831 name, strlen (name),
832 &i, 1,
833 NULL);
834
835 pk->d[0] &= 248;
836 pk->d[31] &= 127;
837 pk->d[31] |= 64;
838
839 return pk;
840}
841
842
843static void
844handle_existing_wrong_ego_deletion (void *cls,
845 const char *emsg)
846{
847 struct IdentityOperationEntry *curr_id_op = cls;
848 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
849 struct ESCROW_GnsPluginOperation *p_op;
850
851 plugin_op_wrap = curr_id_op->plugin_op_wrap;
852 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
853
854 if (NULL != emsg)
855 {
856 fprintf (stderr,
857 "Identity create operation returned with error: %s\n",
858 emsg);
859 p_op->anchor_wrap->emsg = _ ("Identity delete of wrong existing ego failed!\n");
860 p_op->anchor_wrap->anchor = NULL;
861 p_op->cont (p_op->anchor_wrap);
862 // this also cancels all running identity operations
863 cleanup_plugin_operation (plugin_op_wrap);
864 return;
865 }
866
867 /* no error occured, so create the new identity */
868 // the IdentityOperationEntry is reused, so only the id_op is updated
869 curr_id_op->id_op = GNUNET_IDENTITY_create (identity_handle,
870 curr_id_op->name,
871 curr_id_op->pk,
872 &escrow_id_created,
873 curr_id_op);
874}
875
876
877static void
878create_escrow_identities (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
879 const char *name)
880{
881 struct ESCROW_GnsPluginOperation *p_op;
882 struct GNUNET_CRYPTO_EcdsaPrivateKey *curr_pk;
883 char *curr_name;
884 struct IdentityOperationEntry *curr_id_op;
885 struct PkEntry *curr_pk_entry;
886 int exists_ret;
887
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating escrow identities\n");
889
890 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
891
892 for (uint8_t i = 0; i < p_op->shares; i++)
893 {
894 curr_pk = derive_private_key (name, p_op->userSecret, i);
895 curr_name = get_escrow_id_name (name, i);
896
897 // check if the escrow identity already exists
898 exists_ret = escrow_id_exists (curr_name, curr_pk);
899 if (GNUNET_SYSERR == exists_ret)
900 {
901 /* an ego with identifier name but the wrong pk exists, delete it first */
902 curr_id_op = GNUNET_new (struct IdentityOperationEntry);
903 curr_id_op->pk = curr_pk;
904 curr_id_op->name = curr_name;
905 curr_id_op->i = i;
906 curr_id_op->plugin_op_wrap = plugin_op_wrap;
907 curr_id_op->id_op = GNUNET_IDENTITY_delete (identity_handle,
908 curr_name,
909 &handle_existing_wrong_ego_deletion,
910 curr_id_op);
911 GNUNET_CONTAINER_DLL_insert (p_op->id_ops_head,
912 p_op->id_ops_tail,
913 curr_id_op);
914 }
915 else if (GNUNET_YES == exists_ret)
916 {
917 // the escrow id already exists, so insert the pk into our list
918 curr_pk_entry = GNUNET_new (struct PkEntry);
919 curr_pk_entry->pk = *curr_pk;
920 curr_pk_entry->i = i;
921 GNUNET_CONTAINER_DLL_insert (p_op->escrow_pks_head,
922 p_op->escrow_pks_tail,
923 curr_pk_entry);
924
925 p_op->escrow_id_counter++;
926 if (p_op->escrow_id_counter == p_op->shares)
927 {
928 escrow_ids_finished (plugin_op_wrap);
929 }
930 }
931 else // GNUNET_NO
932 {
933 /* store the identity operation in our list */
934 curr_id_op = GNUNET_new (struct IdentityOperationEntry);
935 curr_id_op->pk = curr_pk;
936 curr_id_op->name = curr_name;
937 curr_id_op->i = i;
938 curr_id_op->plugin_op_wrap = plugin_op_wrap;
939 curr_id_op->id_op = GNUNET_IDENTITY_create (identity_handle,
940 curr_name,
941 curr_pk,
942 &escrow_id_created,
943 curr_id_op);
944 GNUNET_CONTAINER_DLL_insert (p_op->id_ops_head,
945 p_op->id_ops_tail,
946 curr_id_op);
947 }
948 }
949}
950
951
952static void
953handle_config_load_error (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
954 char *emsg)
955{
956 struct ESCROW_GnsPluginOperation *p_op;
957
958 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
959
960 if (NULL != p_op->anchor_wrap)
961 {
962 p_op->anchor_wrap->anchor = NULL;
963 p_op->anchor_wrap->emsg = emsg;
964 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
965 return;
966 }
967
968 if (NULL != p_op->verify_wrap)
969 {
970 p_op->verify_wrap->verificationResult = GNUNET_ESCROW_INVALID;
971 p_op->verify_wrap->emsg = emsg;
972 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
973 return;
974 }
975
976 if (NULL != p_op->ego_wrap)
977 {
978 p_op->ego_wrap->ego = NULL;
979 p_op->ego_wrap->emsg = emsg;
980 p_op->sched_task = GNUNET_SCHEDULER_add_now (&handle_restore_error, plugin_op_wrap);
981 return;
982 }
983}
984
985
986static int
987load_keyshare_config (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
988{
989 struct ESCROW_GnsPluginOperation *p_op;
990 unsigned long long shares, share_threshold;
991 struct GNUNET_TIME_Relative share_expiration_time;
992
993 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
994
995 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (p_op->h->cfg,
996 "escrow",
997 "gns_shares",
998 &shares))
999 {
1000 handle_config_load_error (plugin_op_wrap,
1001 "Number of shares not specified in config!\n");
1002 return GNUNET_SYSERR;
1003 }
1004 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (p_op->h->cfg,
1005 "escrow",
1006 "gns_share_threshold",
1007 &share_threshold))
1008 {
1009 handle_config_load_error (plugin_op_wrap,
1010 "Share threshold not specified in config\n");
1011 return GNUNET_SYSERR;
1012 }
1013 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (p_op->h->cfg,
1014 "escrow",
1015 "gns_share_expiration_time",
1016 &share_expiration_time))
1017 {
1018 handle_config_load_error (plugin_op_wrap,
1019 "Share expiration time not specified in config\n");
1020 return GNUNET_SYSERR;
1021 }
1022 p_op->shares = (uint8_t)shares;
1023 p_op->share_threshold = (uint8_t)share_threshold;
1024 p_op->share_expiration_time.rel_value_us = share_expiration_time.rel_value_us;
1025
1026 return GNUNET_OK;
1027}
1028
1029
1030static void
1031continue_start (void *cls)
1032{
1033 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
1034 struct ESCROW_GnsPluginOperation *p_op;
1035 struct GNUNET_TIME_Relative delay;
1036 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
1037 struct EgoEntry *ego_entry;
1038 char *pub_keystring;
1039
1040 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
1041
1042 if (ESCROW_PLUGIN_STATE_POST_INIT != ph.state)
1043 {
1044 delay.rel_value_us = 100 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
1045 GNUNET_SCHEDULER_add_delayed (delay, &continue_start, plugin_op_wrap);
1046 return;
1047 }
1048
1049 GNUNET_IDENTITY_ego_get_public_key (p_op->ego, &ego_pub);
1050 pub_keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_pub);
1051 for (ego_entry = ph.ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1052 if (0 == strcmp (pub_keystring, ego_entry->keystring))
1053 break;
1054
1055 GNUNET_free (pub_keystring);
1056 if (NULL == ego_entry)
1057 {
1058 p_op->anchor_wrap->anchor = NULL;
1059 p_op->anchor_wrap->emsg = _ ("Identity was not found in plugin!\n");
1060 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
1061 return;
1062 }
1063
1064 p_op->egoName = GNUNET_strdup (ego_entry->identifier);
1065
1066 /* load config */
1067 if (GNUNET_OK != load_keyshare_config (plugin_op_wrap))
1068 {
1069 p_op->anchor_wrap->anchor = NULL;
1070 p_op->anchor_wrap->emsg = _ ("Failed to load keyshare configuration parameters!\n");
1071 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
1072 return;
1073 }
1074
1075 /* create the escrow identities */
1076 create_escrow_identities (plugin_op_wrap, p_op->egoName);
1077
1078 /* operation continues in escrow_ids_finished
1079 after all escrow identities are created */
1080}
1081
1082
1083/**
1084 * Start the GNS escrow of the key
1085 *
1086 * @param h the handle for the escrow component
1087 * @param ego the identity ego containing the private key
1088 * @param userSecret the user secret (used for derivation of escrow identities)
1089 * this has to be UNIQUE in the whole network!
1090 * @param cb the function called upon completion
1091 * @param op_id unique ID of the respective ESCROW_Operation
1092 *
1093 * @return plugin operation wrapper
1094 */
1095struct ESCROW_PluginOperationWrapper *
1096start_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
1097 struct GNUNET_IDENTITY_Ego *ego,
1098 const char *userSecret,
1099 GNUNET_SCHEDULER_TaskCallback cb,
1100 uint32_t op_id)
1101{
1102 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
1103 struct ESCROW_GnsPluginOperation *p_op;
1104 struct ESCROW_Plugin_AnchorContinuationWrapper *w;
1105 struct GNUNET_TIME_Relative delay;
1106
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting GNS escrow\n");
1108
1109 // create a new GNS plugin operation (in a wrapper) and insert it into the DLL
1110 plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
1111 plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_GnsPluginOperation);
1112 GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
1113 ph.plugin_op_tail,
1114 plugin_op_wrap);
1115
1116 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
1117 p_op->h = h;
1118 p_op->cont = cb;
1119 p_op->ego = ego;
1120
1121 w = GNUNET_new (struct ESCROW_Plugin_AnchorContinuationWrapper);
1122 w->h = h;
1123 w->op_id = op_id;
1124 p_op->anchor_wrap = w;
1125
1126 if (NULL == ego || NULL == userSecret)
1127 {
1128 w->anchor = NULL;
1129 if (NULL == ego)
1130 w->emsg = _ ("ESCROW_put was called with ego == NULL\n");
1131 else if (NULL == userSecret)
1132 w->emsg = _ ("GNS escrow needs a user secret!\n");
1133 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
1134 return plugin_op_wrap;
1135 }
1136 p_op->pk = *GNUNET_IDENTITY_ego_get_private_key (ego);
1137 p_op->userSecret = GNUNET_strdup (userSecret);
1138
1139 if (ESCROW_PLUGIN_STATE_POST_INIT == ph.state)
1140 {
1141 continue_start (plugin_op_wrap);
1142 }
1143 else
1144 {
1145 delay.rel_value_us = 200 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
1146 GNUNET_SCHEDULER_add_delayed (delay, &continue_start, plugin_op_wrap);
1147 }
1148
1149 return plugin_op_wrap;
1150}
1151
1152
1153static uint8_t
1154count_keyshares (const sss_Keyshare *keyshares, uint8_t n)
1155{
1156 uint8_t i, c;
1157 sss_Keyshare null_ks;
1158
1159 memset (null_ks, 0, sizeof (sss_Keyshare));
1160
1161 c = 0;
1162 for (i = 0; i < n; i++)
1163 {
1164 if (0 != memcmp (keyshares[i], &null_ks, sizeof (sss_Keyshare)))
1165 c++;
1166 }
1167
1168 return c;
1169}
1170
1171
1172static void
1173remove_empty_keyshares (sss_Keyshare *keyshares, uint8_t n)
1174{
1175 uint8_t i, j;
1176 sss_Keyshare null_ks;
1177
1178 memset (null_ks, 0, sizeof (sss_Keyshare));
1179
1180 for (i = j = 0; i < n; i++)
1181 {
1182 if (0 != memcmp (keyshares[i], &null_ks, sizeof (sss_Keyshare)))
1183 {
1184 memcpy (keyshares[j], keyshares[i], sizeof (sss_Keyshare));
1185 j++;
1186 }
1187 }
1188}
1189
1190
1191static void
1192process_keyshares (void *cls)
1193{
1194 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
1195 struct ESCROW_GnsPluginOperation *p_op;
1196 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
1197 uint8_t keyshares_count;
1198
1199 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
1200
1201 /* check if enough keyshares have been restored */
1202 keyshares_count = count_keyshares (p_op->restored_keyshares, p_op->shares);
1203 if (keyshares_count < p_op->share_threshold)
1204 {
1205 /* the key cannot be restored */
1206 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1207 "need %hhu shares, but could only get %hhu\n",
1208 p_op->share_threshold,
1209 keyshares_count);
1210
1211 if (NULL != p_op->verify_wrap) // this was called by a verify operation
1212 {
1213 p_op->verify_wrap->emsg =
1214 _ ("key could not be restored, failed to get enough keyshares\n");
1215 p_op->restore_pk_cont (p_op->restore_pk_cont_cls, NULL);
1216 return;
1217 }
1218
1219 if (NULL != p_op->ego_wrap) // this was called by a restore operation
1220 {
1221 p_op->ego_wrap->emsg =
1222 _ ("key could not be restored, failed to get enough keyshares\n");
1223 p_op->restore_pk_cont (p_op->restore_pk_cont_cls, NULL);
1224 return;
1225 }
1226 }
1227
1228 /* combine the shares */
1229 if (keyshares_count != p_op->shares)
1230 remove_empty_keyshares (p_op->restored_keyshares, p_op->shares);
1231
1232 pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1233 sss_combine_keyshares (pk->d,
1234 p_op->restored_keyshares,
1235 keyshares_count);
1236
1237 p_op->restore_pk_cont (p_op->restore_pk_cont_cls, pk);
1238}
1239
1240
1241static void
1242process_gns_lookup_result (void *cls,
1243 uint32_t rd_count,
1244 const struct GNUNET_GNSRECORD_Data *rd)
1245{
1246 struct GnsLookupRequestEntry *gns_lr = cls;
1247 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
1248 struct ESCROW_GnsPluginOperation *p_op;
1249 sss_Keyshare keyshare;
1250 char keyshare_string[64], *end;
1251
1252 plugin_op_wrap = gns_lr->plugin_op_wrap;
1253 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
1254
1255 /* remove gns_lr from our list */
1256 GNUNET_CONTAINER_DLL_remove (p_op->gns_lrs_head,
1257 p_op->gns_lrs_tail,
1258 gns_lr);
1259
1260 /* cancel the timeout for that lookup */
1261 GNUNET_CONTAINER_DLL_remove (p_op->tts_head,
1262 p_op->tts_tail,
1263 gns_lr->tt);
1264 GNUNET_SCHEDULER_cancel (gns_lr->tt->tt);
1265 GNUNET_free (gns_lr->tt);
1266
1267 if (1 != rd_count)
1268 {
1269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1270 "did not get exactly _one_ record from GNS\n");
1271 goto END;
1272 }
1273
1274 if (sizeof (sss_Keyshare) != rd[0].data_size)
1275 {
1276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1277 "the size of the GNS record differs from the size of a keyshare\n");
1278 goto END;
1279 }
1280
1281 GNUNET_memcpy (&keyshare,
1282 rd[0].data,
1283 rd[0].data_size);
1284
1285 end = GNUNET_STRINGS_data_to_string (&keyshare,
1286 sizeof (sss_Keyshare),
1287 keyshare_string,
1288 sizeof (keyshare_string));
1289 GNUNET_break (NULL != end);
1290 *end = '\0';
1291
1292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293 "got keyshare %s from GNS\n", keyshare_string);
1294
1295 GNUNET_memcpy (p_op->restored_keyshares[gns_lr->i],
1296 &keyshare,
1297 sizeof (sss_Keyshare));
1298
1299 END:
1300 GNUNET_free (gns_lr);
1301
1302 // check if this was the last gns_lr, i.e. our list is empty
1303 if (NULL == p_op->gns_lrs_head)
1304 {
1305 // schedule the further execution, lets GNS clean up its operation list
1306 GNUNET_SCHEDULER_add_now (&process_keyshares, plugin_op_wrap);
1307 }
1308}
1309
1310
1311static void
1312timeout_gns_request (void *cls)
1313{
1314 struct TimeoutTaskEntry *curr_tt = cls;
1315 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
1316 struct ESCROW_GnsPluginOperation *p_op;
1317
1318 plugin_op_wrap = curr_tt->plugin_op_wrap;
1319 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
1320
1321 /* remove timeout task from our list */
1322 GNUNET_CONTAINER_DLL_remove (p_op->tts_head,
1323 p_op->tts_tail,
1324 curr_tt);
1325
1326 /* cancel the GNS lookup and remove it from our list */
1327 GNUNET_GNS_lookup_cancel (curr_tt->gns_lr->lr);
1328 GNUNET_CONTAINER_DLL_remove (p_op->gns_lrs_head,
1329 p_op->gns_lrs_tail,
1330 curr_tt->gns_lr);
1331 GNUNET_free (curr_tt->gns_lr);
1332
1333 GNUNET_free (curr_tt);
1334
1335 /* check if this was the last pending GNS lookup */
1336 if (NULL == p_op->gns_lrs_head)
1337 {
1338 // no need to schedule, as the timeout is already scheduled
1339 process_keyshares (plugin_op_wrap);
1340 }
1341}
1342
1343
1344static char *
1345get_user_secret_from_anchor (const struct GNUNET_ESCROW_Anchor *anchor)
1346{
1347 char *userSecret;
1348
1349 userSecret = GNUNET_malloc (anchor->size);
1350 GNUNET_memcpy (userSecret, &anchor[1], anchor->size);
1351
1352 return userSecret;
1353}
1354
1355
1356static void
1357restore_private_key (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
1358 const struct GNUNET_ESCROW_Anchor *anchor,
1359 PkContinuation cont,
1360 void *cont_cls)
1361{
1362 struct ESCROW_GnsPluginOperation *p_op;
1363 struct GNUNET_CRYPTO_EcdsaPrivateKey *curr_escrow_pk;
1364 struct GNUNET_CRYPTO_EcdsaPublicKey curr_escrow_pub;
1365 char *label;
1366 struct GnsLookupRequestEntry *curr_gns_lr;
1367 struct GNUNET_TIME_Relative delay;
1368 struct TimeoutTaskEntry *curr_tt;
1369
1370 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
1371
1372 p_op->gns_h = GNUNET_GNS_connect (p_op->h->cfg);
1373 p_op->restore_pk_cont = cont;
1374 p_op->restore_pk_cont_cls = cont_cls;
1375 p_op->restored_keyshares = GNUNET_malloc (sizeof (sss_Keyshare) * p_op->shares);
1376 // ensure that the array is initialized with 0, as this is needed for counting the shares
1377 memset (p_op->restored_keyshares, 0, sizeof (sss_Keyshare) * p_op->shares);
1378 p_op->userSecret = get_user_secret_from_anchor (anchor);
1379
1380 label = get_label (p_op->userSecret);
1381
1382 // init delay to 2s
1383 delay.rel_value_us = 2 * GNUNET_TIME_relative_get_second_().rel_value_us;
1384
1385 for (uint8_t i = 0; i < p_op->shares; i++)
1386 {
1387 curr_escrow_pk = derive_private_key (anchor->egoName, p_op->userSecret, i);
1388
1389 curr_gns_lr = GNUNET_new (struct GnsLookupRequestEntry);
1390 curr_gns_lr->plugin_op_wrap = plugin_op_wrap;
1391 curr_gns_lr->i = i;
1392 GNUNET_CRYPTO_ecdsa_key_get_public (curr_escrow_pk, &curr_escrow_pub);
1393 curr_gns_lr->lr = GNUNET_GNS_lookup (p_op->gns_h,
1394 label,
1395 &curr_escrow_pub,
1396 GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE,
1397 GNUNET_GNS_LO_DEFAULT,
1398 &process_gns_lookup_result,
1399 curr_gns_lr);
1400 GNUNET_CONTAINER_DLL_insert_tail (p_op->gns_lrs_head,
1401 p_op->gns_lrs_tail,
1402 curr_gns_lr);
1403
1404 /* start timeout for GNS lookup (cancels the lr if not yet finished) */
1405 curr_tt = GNUNET_new (struct TimeoutTaskEntry);
1406 curr_tt->gns_lr = curr_gns_lr;
1407 curr_tt->plugin_op_wrap = plugin_op_wrap;
1408 curr_tt->tt = GNUNET_SCHEDULER_add_delayed (delay,
1409 &timeout_gns_request,
1410 curr_tt);
1411 GNUNET_CONTAINER_DLL_insert_tail (p_op->tts_head,
1412 p_op->tts_tail,
1413 curr_tt);
1414
1415 // set the timeout task for the current gns lr entry
1416 curr_gns_lr->tt = curr_tt;
1417 }
1418 GNUNET_free (label);
1419}
1420
1421
1422static void
1423verify_restored_pk (void *cls,
1424 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
1425{
1426 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
1427 struct ESCROW_GnsPluginOperation *p_op;
1428 const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_pk;
1429 int verificationResult;
1430
1431 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
1432
1433 if (NULL == pk)
1434 verificationResult = GNUNET_ESCROW_INVALID;
1435 else
1436 {
1437 ego_pk = GNUNET_IDENTITY_ego_get_private_key (p_op->ego);
1438 verificationResult = memcmp (pk,
1439 ego_pk,
1440 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
1441 == 0 ? GNUNET_ESCROW_VALID : GNUNET_ESCROW_INVALID;
1442 }
1443
1444 // check if all shares could be restored
1445 if (GNUNET_ESCROW_VALID == verificationResult &&
1446 count_keyshares (p_op->restored_keyshares, p_op->shares) < p_op->shares)
1447 verificationResult = GNUNET_ESCROW_SHARES_MISSING;
1448
1449 /* update the escrow status if valid */
1450 if (GNUNET_ESCROW_VALID == verificationResult)
1451 ESCROW_update_escrow_status_verify (p_op->h, p_op->ego, "gns");
1452
1453 p_op->verify_wrap->verificationResult = verificationResult;
1454 verify_cont (plugin_op_wrap);
1455}
1456
1457
1458static void
1459continue_verify (void *cls)
1460{
1461 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
1462 struct ESCROW_GnsPluginOperation *p_op;
1463 struct GNUNET_TIME_Relative delay;
1464 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
1465 struct EgoEntry *ego_entry;
1466 char *pub_keystring;
1467
1468 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
1469
1470 if (ESCROW_PLUGIN_STATE_POST_INIT != ph.state)
1471 {
1472 delay.rel_value_us = 100 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
1473 GNUNET_SCHEDULER_add_delayed (delay, &continue_verify, plugin_op_wrap);
1474 return;
1475 }
1476
1477 GNUNET_IDENTITY_ego_get_public_key (p_op->ego, &ego_pub);
1478 pub_keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_pub);
1479 for (ego_entry = ph.ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1480 if (0 == strcmp (pub_keystring, ego_entry->keystring))
1481 break;
1482
1483 GNUNET_free (pub_keystring);
1484 if (NULL == ego_entry)
1485 {
1486 p_op->verify_wrap->verificationResult = GNUNET_ESCROW_INVALID;
1487 p_op->verify_wrap->emsg = _ ("Identity was not found in plugin!\n");
1488 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
1489 return;
1490 }
1491
1492 p_op->egoName = GNUNET_strdup (ego_entry->identifier);
1493
1494 if (0 != strcmp (p_op->egoName, p_op->anchor->egoName))
1495 {
1496 p_op->verify_wrap->verificationResult = GNUNET_ESCROW_INVALID;
1497 p_op->verify_wrap->emsg = _ ("This anchor was not created when putting that ego in escrow!\n");
1498 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
1499 return;
1500 }
1501
1502 /* load config */
1503 if (GNUNET_OK != load_keyshare_config (plugin_op_wrap))
1504 {
1505 p_op->verify_wrap->verificationResult = GNUNET_ESCROW_INVALID;
1506 p_op->verify_wrap->emsg = _ ("Failed to load keyshare configuration parameters!\n");
1507 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
1508 return;
1509 }
1510
1511 restore_private_key (plugin_op_wrap,
1512 p_op->anchor,
1513 &verify_restored_pk,
1514 plugin_op_wrap);
1515}
1516
1517
1518/**
1519 * Verify the GNS escrow of the key
1520 *
1521 * @param h the handle for the escrow component
1522 * @param ego the identity ego containing the private key
1523 * @param anchor the escrow anchor needed to restore the key
1524 * @param cb the function called upon completion
1525 * @param op_id unique ID of the respective ESCROW_Operation
1526 *
1527 * @return plugin operation wrapper
1528 */
1529struct ESCROW_PluginOperationWrapper *
1530verify_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
1531 struct GNUNET_IDENTITY_Ego *ego,
1532 const struct GNUNET_ESCROW_Anchor *anchor,
1533 GNUNET_SCHEDULER_TaskCallback cb,
1534 uint32_t op_id)
1535{
1536 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
1537 struct ESCROW_GnsPluginOperation *p_op;
1538 struct ESCROW_Plugin_VerifyContinuationWrapper *w;
1539 struct GNUNET_TIME_Relative delay;
1540
1541 // create a new GNS plugin operation (in a wrapper) and insert it into the DLL
1542 plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
1543 plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_GnsPluginOperation);
1544 GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
1545 ph.plugin_op_tail,
1546 plugin_op_wrap);
1547
1548 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
1549 p_op->h = h;
1550 p_op->cont = cb;
1551 p_op->ego = ego;
1552 p_op->anchor = anchor;
1553
1554 w = GNUNET_new (struct ESCROW_Plugin_VerifyContinuationWrapper);
1555 w->h = h;
1556 w->op_id = op_id;
1557 p_op->verify_wrap = w;
1558
1559 if (NULL == ego)
1560 {
1561 w->verificationResult = GNUNET_ESCROW_INVALID;
1562 w->emsg = _ ("ESCROW_verify was called with ego == NULL!\n");
1563 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
1564 return plugin_op_wrap;
1565 }
1566 if (GNUNET_ESCROW_KEY_GNS != anchor->method)
1567 {
1568 w->verificationResult = GNUNET_ESCROW_INVALID;
1569 w->emsg = _ ("This anchor was not created using GNS escrow!\n");
1570 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
1571 return plugin_op_wrap;
1572 }
1573
1574 if (ESCROW_PLUGIN_STATE_POST_INIT == ph.state)
1575 {
1576 continue_verify (plugin_op_wrap);
1577 }
1578 else
1579 {
1580 delay.rel_value_us = 200 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
1581 GNUNET_SCHEDULER_add_delayed (delay, &continue_verify, plugin_op_wrap);
1582 }
1583
1584 return plugin_op_wrap;
1585}
1586
1587
1588void
1589ego_created (struct GNUNET_IDENTITY_Ego *ego)
1590{
1591 struct ESCROW_PluginOperationWrapper *curr;
1592 struct ESCROW_GnsPluginOperation *curr_p_op;
1593 char *ego_pk_string, *curr_pk_string;
1594
1595 ego_pk_string = GNUNET_CRYPTO_ecdsa_private_key_to_string (
1596 GNUNET_IDENTITY_ego_get_private_key (ego));
1597
1598 for (curr = ph.plugin_op_head; NULL != curr; curr = curr->next)
1599 {
1600 curr_p_op = (struct ESCROW_GnsPluginOperation *)curr->plugin_op;
1601 curr_pk_string = GNUNET_CRYPTO_ecdsa_private_key_to_string (&curr_p_op->pk);
1602 // compare the strings of the private keys
1603 if (0 == strcmp (ego_pk_string, curr_pk_string))
1604 {
1605 // the ego was created due to a restore operation that is not yet finished
1606 curr_p_op->ego_wrap->ego = ego;
1607 curr_p_op->cont (curr_p_op->ego_wrap);
1608
1609 cleanup_plugin_operation (curr);
1610
1611 GNUNET_free (curr_pk_string);
1612 GNUNET_free (ego_pk_string);
1613 return;
1614 }
1615 GNUNET_free (curr_pk_string);
1616 }
1617 GNUNET_free (ego_pk_string);
1618}
1619
1620
1621static void
1622id_create_finished (void *cls,
1623 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
1624 const char *emsg)
1625{
1626 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
1627 struct ESCROW_GnsPluginOperation *p_op;
1628
1629 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
1630
1631 if (NULL == pk)
1632 {
1633 if (NULL != emsg)
1634 {
1635 fprintf (stderr,
1636 "Identity create operation returned with error: %s\n",
1637 emsg);
1638 p_op->ego_wrap->emsg = _ ("Identity create failed!\n");
1639 }
1640 else
1641 p_op->ego_wrap->emsg = _ ("Failed to create ego!\n");
1642 p_op->ego_wrap->ego = NULL;
1643 p_op->cont (p_op->ego_wrap);
1644 return;
1645 }
1646
1647 /* no error occurred, p_op->restore_cont will be called in ego_created, which
1648 is called from ESCROW_list_ego after adding the new ego to our list */
1649 p_op->pk = *pk;
1650}
1651
1652
1653static void
1654restore_ego_from_pk (void *cls,
1655 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
1656{
1657 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
1658 struct ESCROW_GnsPluginOperation *p_op;
1659
1660 p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
1661
1662 if (NULL == pk)
1663 {
1664 p_op->ego_wrap->ego = NULL;
1665 handle_restore_error (plugin_op_wrap);
1666 return;
1667 }
1668
1669 p_op->id_op = GNUNET_IDENTITY_create (identity_handle,
1670 p_op->egoName,
1671 pk,
1672 &id_create_finished,
1673 plugin_op_wrap);
1674}
1675
1676
1677/**
1678 * Restore the key from GNS escrow
1679 *
1680 * @param h the handle for the escrow component
1681 * @param anchor the escrow anchor needed to restore the key
1682 * @param cb the function called upon completion
1683 * @param op_id unique ID of the respective ESCROW_Operation
1684 *
1685 * @return plugin operation wrapper
1686 */
1687struct ESCROW_PluginOperationWrapper *
1688restore_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
1689 const struct GNUNET_ESCROW_Anchor *anchor,
1690 GNUNET_SCHEDULER_TaskCallback cb,
1691 uint32_t op_id)
1692{
1693 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
1694 struct ESCROW_GnsPluginOperation *p_op;
1695 struct ESCROW_Plugin_EgoContinuationWrapper *w;
1696
1697 // create a new GNS plugin operation (in a wrapper) and insert it into the DLL
1698 plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
1699 plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_GnsPluginOperation);
1700 GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
1701 ph.plugin_op_tail,
1702 plugin_op_wrap);
1703
1704 p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
1705 p_op->h = h;
1706 // set cont here (has to be scheduled from the IDENTITY service when it finished)
1707 p_op->cont = cb;
1708 p_op->egoName = GNUNET_strdup (anchor->egoName);
1709 p_op->anchor = anchor;
1710
1711 w = GNUNET_new (struct ESCROW_Plugin_EgoContinuationWrapper);
1712 w->h = h;
1713 w->op_id = op_id;
1714 p_op->ego_wrap = w;
1715
1716 if (NULL == anchor)
1717 {
1718 w->ego = NULL;
1719 w->emsg = _ ("ESCROW_get was called with anchor == NULL!\n");
1720 // schedule handle_restore_error, which calls the callback and cleans up
1721 p_op->sched_task = GNUNET_SCHEDULER_add_now (&handle_restore_error, plugin_op_wrap);
1722 return plugin_op_wrap;
1723 }
1724
1725 /* load config */
1726 if (GNUNET_OK != load_keyshare_config (plugin_op_wrap))
1727 return plugin_op_wrap;
1728
1729 restore_private_key (plugin_op_wrap,
1730 anchor,
1731 &restore_ego_from_pk,
1732 plugin_op_wrap);
1733
1734 return plugin_op_wrap;
1735}
1736
1737
1738/**
1739 * Get the status of a GNS escrow
1740 *
1741 * @param h the handle for the escrow component
1742 * @param ego the identity ego of which the status has to be obtained
1743 *
1744 * @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
1745 */
1746struct GNUNET_ESCROW_Status *
1747gns_get_status (struct GNUNET_ESCROW_Handle *h,
1748 struct GNUNET_IDENTITY_Ego *ego)
1749{
1750 return ESCROW_get_escrow_status (h, ego);
1751}
1752
1753
1754/**
1755 * Cancel a GNS plugin operation.
1756 *
1757 * @param plugin_op_wrap the plugin operation wrapper containing the operation
1758 */
1759void
1760cancel_gns_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
1761{
1762 struct ESCROW_PluginOperationWrapper *curr;
1763
1764 for (curr = ph.plugin_op_head; NULL != curr; curr = curr->next)
1765 {
1766 if (curr == plugin_op_wrap)
1767 {
1768 GNUNET_CONTAINER_DLL_remove (ph.plugin_op_head,
1769 ph.plugin_op_tail,
1770 curr);
1771 cleanup_plugin_operation (curr);
1772 return;
1773 }
1774 }
1775}
1776
1777
1778/**
1779 * IdentityInitContinuation for the GNS plugin
1780 */
1781void
1782gns_cont_init ()
1783{
1784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS plugin initialized\n");
1785}
1786
1787
1788/**
1789 * Entry point for the plugin.
1790 *
1791 * @param cls Config info
1792 *
1793 * @return the exported block API
1794 */
1795void *
1796libgnunet_plugin_escrow_gns_init (void *cls)
1797{
1798 struct GNUNET_ESCROW_KeyPluginFunctions *api;
1799 struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1800
1801 api = GNUNET_new (struct GNUNET_ESCROW_KeyPluginFunctions);
1802 api->start_key_escrow = &start_gns_key_escrow;
1803 api->verify_key_escrow = &verify_gns_key_escrow;
1804 api->restore_key = &restore_gns_key_escrow;
1805 api->get_status = &gns_get_status;
1806 api->cancel_plugin_operation = &cancel_gns_operation;
1807
1808 ph.state = ESCROW_PLUGIN_STATE_INIT;
1809 ph.id_init_cont = &gns_cont_init;
1810
1811 ph.ego_create_cont = &ego_created;
1812 identity_handle = GNUNET_IDENTITY_connect (cfg,
1813 &ESCROW_list_ego,
1814 &ph);
1815
1816 return api;
1817}
1818
1819
1820/**
1821 * Exit point from the plugin.
1822 *
1823 * @param cls the return value from #libgnunet_plugin_block_test_init()
1824 *
1825 * @return NULL
1826 */
1827void *
1828libgnunet_plugin_escrow_gns_done (void *cls)
1829{
1830 struct GNUNET_ESCROW_KeyPluginFunctions *api = cls;
1831
1832 ph.state = ESCROW_PLUGIN_STATE_CLEANUP;
1833
1834 GNUNET_free (api);
1835 GNUNET_IDENTITY_disconnect (identity_handle);
1836 ESCROW_cleanup_ego_list (&ph);
1837
1838 return NULL;
1839}
1840
1841
1842/* end of plugin_escrow_gns.c */
diff --git a/src/escrow/plugin_escrow_plaintext.c b/src/escrow/plugin_escrow_plaintext.c
new file mode 100644
index 000000000..86f49955f
--- /dev/null
+++ b/src/escrow/plugin_escrow_plaintext.c
@@ -0,0 +1,673 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file escrow/plugin_escrow_plaintext.c
23 * @brief escrow-plugin-plaintext escrow plugin for plaintext escrow of the key
24 *
25 * @author Johannes Späth
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_escrow_plugin.h"
30#include "escrow_plugin_helper.h"
31#include "gnunet_identity_service.h"
32#include "escrow.h"
33#include <inttypes.h>
34
35
36struct ESCROW_PlaintextPluginOperation
37{
38 /**
39 * Handle for the escrow component
40 */
41 struct GNUNET_ESCROW_Handle *h;
42
43 /**
44 * Scheduler task the SCHEDULE operation returns (needed for cancellation)
45 */
46 struct GNUNET_SCHEDULER_Task *sched_task;
47
48 /**
49 * Identity operation
50 */
51 struct GNUNET_IDENTITY_Operation *id_op;
52
53 /**
54 * Private key of the created ego
55 */
56 struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
57
58 /**
59 * The ego
60 */
61 struct GNUNET_IDENTITY_Ego *ego;
62
63 /**
64 * The anchor
65 */
66 const struct GNUNET_ESCROW_Anchor *anchor;
67
68 /**
69 * Name of the ego
70 */
71 char *egoName;
72
73 /**
74 * Continuation for a plugin operation (e.g. used for restore, as this
75 * callback has to be called from the IDENTITY service after finishing)
76 */
77 ESCROW_Plugin_Continuation cont;
78
79 /**
80 * Ego continuation wrapper
81 */
82 struct ESCROW_Plugin_EgoContinuationWrapper *ego_wrap;
83
84 /**
85 * Anchor continuation wrapper
86 */
87 struct ESCROW_Plugin_AnchorContinuationWrapper *anchor_wrap;
88
89 /**
90 * Verify continuation wrapper
91 */
92 struct ESCROW_Plugin_VerifyContinuationWrapper *verify_wrap;
93};
94
95/**
96 * Identity handle
97 */
98static struct GNUNET_IDENTITY_Handle *identity_handle;
99
100/**
101 * Handle for the plugin instance
102 */
103static struct ESCROW_PluginHandle ph;
104
105
106/**
107 * Clean up a plugin operation, i.e. remove it from the list and
108 * free the respective memory
109 */
110static void
111cleanup_plugin_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
112{
113 struct ESCROW_PlaintextPluginOperation *p_op;
114
115 p_op = (struct ESCROW_PlaintextPluginOperation*)plugin_op_wrap->plugin_op;
116
117 GNUNET_CONTAINER_DLL_remove (ph.plugin_op_head,
118 ph.plugin_op_tail,
119 plugin_op_wrap);
120 if (NULL != p_op->anchor_wrap)
121 GNUNET_free (p_op->anchor_wrap);
122 if (NULL != p_op->ego_wrap)
123 GNUNET_free (p_op->ego_wrap);
124 if (NULL != p_op->verify_wrap)
125 GNUNET_free (p_op->verify_wrap);
126 if (NULL != p_op->egoName)
127 GNUNET_free (p_op->egoName);
128 GNUNET_free (p_op);
129 GNUNET_free (plugin_op_wrap);
130}
131
132
133static void
134start_cont (void *cls)
135{
136 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
137 struct ESCROW_PlaintextPluginOperation *p_op;
138
139 p_op = (struct ESCROW_PlaintextPluginOperation*)plugin_op_wrap->plugin_op;
140 p_op->sched_task = NULL;
141 p_op->cont (p_op->anchor_wrap);
142
143 cleanup_plugin_operation (plugin_op_wrap);
144}
145
146
147static void
148continue_start (void *cls)
149{
150 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
151 struct ESCROW_PlaintextPluginOperation *p_op;
152 struct GNUNET_TIME_Relative delay;
153 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
154 struct EgoEntry *ego_entry;
155 char *pub_keystring;
156 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
157 char *pkString;
158
159 p_op = (struct ESCROW_PlaintextPluginOperation *)plugin_op_wrap->plugin_op;
160
161 if (ESCROW_PLUGIN_STATE_POST_INIT != ph.state)
162 {
163 delay.rel_value_us = 100 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
164 GNUNET_SCHEDULER_add_delayed (delay, &continue_start, plugin_op_wrap);
165 return;
166 }
167
168 GNUNET_IDENTITY_ego_get_public_key (p_op->ego, &ego_pub);
169 pub_keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_pub);
170 for (ego_entry = ph.ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
171 if (0 == strcmp (pub_keystring, ego_entry->keystring))
172 break;
173
174 GNUNET_free (pub_keystring);
175 if (NULL == ego_entry)
176 {
177 p_op->anchor_wrap->anchor = NULL;
178 p_op->anchor_wrap->emsg = _ ("Identity was not found in plugin!\n");
179 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
180 return;
181 }
182
183 p_op->egoName = GNUNET_strdup (ego_entry->identifier);
184
185 pk = GNUNET_IDENTITY_ego_get_private_key (p_op->ego);
186 pkString = GNUNET_CRYPTO_ecdsa_private_key_to_string (pk);
187
188 p_op->anchor_wrap->anchor = ESCROW_build_anchor (GNUNET_ESCROW_KEY_PLAINTEXT,
189 p_op->egoName,
190 pkString,
191 strlen (pkString));
192
193 /* update escrow status, i.e. set the last escrow method */
194 ESCROW_update_escrow_status_put (p_op->h, p_op->ego, "plaintext");
195
196 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
197}
198
199
200/**
201 * Start the plaintext escrow of the key, i.e. simply hand out the key
202 *
203 * @param h the handle for the escrow component
204 * @param ego the identity ego containing the private key
205 * @param userSecret the user secret (e.g. for derivation of escrow identities)
206 * @param cb the function called upon completion
207 * @param op_id unique ID of the respective ESCROW_Operation
208 *
209 * @return plugin operation wrapper
210 */
211struct ESCROW_PluginOperationWrapper *
212start_plaintext_key_escrow (struct GNUNET_ESCROW_Handle *h,
213 struct GNUNET_IDENTITY_Ego *ego,
214 const char *userSecret,
215 ESCROW_Plugin_Continuation cb,
216 uint32_t op_id)
217{
218 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
219 struct ESCROW_PlaintextPluginOperation *p_op;
220 struct ESCROW_Plugin_AnchorContinuationWrapper *w;
221 struct GNUNET_TIME_Relative delay;
222
223 // create a new plaintext plugin operation (in a wrapper) and insert it into the DLL
224 plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
225 plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_PlaintextPluginOperation);
226 GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
227 ph.plugin_op_tail,
228 plugin_op_wrap);
229
230 p_op = (struct ESCROW_PlaintextPluginOperation *)plugin_op_wrap->plugin_op;
231 p_op->h = h;
232 p_op->cont = cb;
233 p_op->ego = ego;
234
235 w = GNUNET_new (struct ESCROW_Plugin_AnchorContinuationWrapper);
236 w->h = h;
237 w->op_id = op_id;
238 p_op->anchor_wrap = w;
239
240 if (NULL == ego)
241 {
242 w->anchor = NULL;
243 w->emsg = _ ("ESCROW_put was called with ego == NULL!\n");
244 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
245 return plugin_op_wrap;
246 }
247
248 if (ESCROW_PLUGIN_STATE_POST_INIT == ph.state)
249 {
250 continue_start (plugin_op_wrap);
251 }
252 else
253 {
254 delay.rel_value_us = 200 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
255 GNUNET_SCHEDULER_add_delayed (delay, &continue_start, plugin_op_wrap);
256 }
257
258 return plugin_op_wrap;
259}
260
261
262static void
263verify_cont (void *cls)
264{
265 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
266 struct ESCROW_PlaintextPluginOperation *p_op;
267
268 p_op = (struct ESCROW_PlaintextPluginOperation*)plugin_op_wrap->plugin_op;
269 p_op->sched_task = NULL;
270 p_op->cont (p_op->verify_wrap);
271
272 cleanup_plugin_operation (plugin_op_wrap);
273}
274
275
276static void
277continue_verify (void *cls)
278{
279 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
280 struct ESCROW_PlaintextPluginOperation *p_op;
281 struct GNUNET_TIME_Relative delay;
282 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
283 char *pkString;
284 int verificationResult;
285 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
286 struct EgoEntry *ego_entry;
287 char *pub_keystring;
288
289 p_op = (struct ESCROW_PlaintextPluginOperation *)plugin_op_wrap->plugin_op;
290
291 if (ESCROW_PLUGIN_STATE_POST_INIT != ph.state)
292 {
293 delay.rel_value_us = 100 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
294 GNUNET_SCHEDULER_add_delayed (delay, &continue_verify, plugin_op_wrap);
295 return;
296 }
297
298 GNUNET_IDENTITY_ego_get_public_key (p_op->ego, &ego_pub);
299 pub_keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_pub);
300 for (ego_entry = ph.ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
301 if (0 == strcmp (pub_keystring, ego_entry->keystring))
302 break;
303
304 GNUNET_free (pub_keystring);
305 if (NULL == ego_entry)
306 {
307 p_op->anchor_wrap->anchor = NULL;
308 p_op->anchor_wrap->emsg = _ ("Identity was not found in plugin!\n");
309 p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
310 return;
311 }
312
313 p_op->egoName = GNUNET_strdup (ego_entry->identifier);
314
315 if (0 != strcmp (p_op->egoName, p_op->anchor->egoName))
316 {
317 p_op->verify_wrap->verificationResult = GNUNET_ESCROW_INVALID;
318 p_op->verify_wrap->emsg = _ ("This anchor was not created when putting that ego in escrow!\n");
319 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
320 return;
321 }
322 pk = GNUNET_IDENTITY_ego_get_private_key (p_op->ego);
323 pkString = GNUNET_CRYPTO_ecdsa_private_key_to_string (pk);
324 verificationResult = strncmp (pkString,
325 (char *)&p_op->anchor[1],
326 p_op->anchor->size) == 0 ?
327 GNUNET_ESCROW_VALID : GNUNET_ESCROW_INVALID;
328
329 /* update the escrow status if valid */
330 if (GNUNET_ESCROW_VALID == verificationResult)
331 ESCROW_update_escrow_status_verify (p_op->h, p_op->ego, "plaintext");
332
333 p_op->verify_wrap->verificationResult = verificationResult;
334 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
335}
336
337
338/**
339 * Verify the plaintext escrow of the key
340 *
341 * @param h the handle for the escrow component
342 * @param ego the identity ego containing the private key
343 * @param anchor the escrow anchor needed to restore the key
344 * @param cb the function called upon completion
345 * @param op_id unique ID of the respective ESCROW_Operation
346 *
347 * @return plugin operation wrapper
348 */
349struct ESCROW_PluginOperationWrapper *
350verify_plaintext_key_escrow (struct GNUNET_ESCROW_Handle *h,
351 struct GNUNET_IDENTITY_Ego *ego,
352 const struct GNUNET_ESCROW_Anchor *anchor,
353 ESCROW_Plugin_Continuation cb,
354 uint32_t op_id)
355{
356 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
357 struct ESCROW_PlaintextPluginOperation *p_op;
358 struct ESCROW_Plugin_VerifyContinuationWrapper *w;
359 struct GNUNET_TIME_Relative delay;
360
361 // create a new plaintext plugin operation (in a wrapper) and insert it into the DLL
362 plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
363 plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_PlaintextPluginOperation);
364 GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
365 ph.plugin_op_tail,
366 plugin_op_wrap);
367
368 p_op = (struct ESCROW_PlaintextPluginOperation *)plugin_op_wrap->plugin_op;
369 p_op->h = h;
370 p_op->cont = cb;
371 p_op->ego = ego;
372 p_op->anchor = anchor;
373
374 w = GNUNET_new (struct ESCROW_Plugin_VerifyContinuationWrapper);
375 w->h = h;
376 w->op_id = op_id;
377 p_op->verify_wrap = w;
378
379 if (NULL == ego)
380 {
381 w->verificationResult = GNUNET_ESCROW_INVALID;
382 w->emsg = _ ("ESCROW_verify was called with ego == NULL!\n");
383 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
384 return plugin_op_wrap;
385 }
386 if (GNUNET_ESCROW_KEY_PLAINTEXT != anchor->method)
387 {
388 w->verificationResult = GNUNET_ESCROW_INVALID;
389 w->emsg = _ ("This anchor was not created using plaintext escrow!\n");
390 p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
391 return plugin_op_wrap;
392 }
393
394 if (ESCROW_PLUGIN_STATE_POST_INIT == ph.state)
395 {
396 continue_verify (plugin_op_wrap);
397 }
398 else
399 {
400 delay.rel_value_us = 200 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
401 GNUNET_SCHEDULER_add_delayed (delay, &continue_verify, plugin_op_wrap);
402 }
403
404 return plugin_op_wrap;
405}
406
407
408static void
409ego_created (struct GNUNET_IDENTITY_Ego *ego)
410{
411 struct ESCROW_PluginOperationWrapper *curr;
412 struct ESCROW_PlaintextPluginOperation *curr_p_op;
413 char *ego_pk_string, *curr_pk_string;
414
415 ego_pk_string = GNUNET_CRYPTO_ecdsa_private_key_to_string (
416 GNUNET_IDENTITY_ego_get_private_key(ego));
417
418 for (curr = ph.plugin_op_head; NULL != curr; curr = curr->next)
419 {
420 curr_p_op = (struct ESCROW_PlaintextPluginOperation *)curr->plugin_op;
421 curr_pk_string = GNUNET_CRYPTO_ecdsa_private_key_to_string (&curr_p_op->pk);
422 // compare the strings of the private keys
423 if (0 == strcmp (ego_pk_string, curr_pk_string))
424 {
425 // the ego was created due to a restore operation that is not yet finished
426 curr_p_op->ego_wrap->ego = ego;
427 curr_p_op->cont (curr_p_op->ego_wrap);
428
429 cleanup_plugin_operation (curr);
430
431 GNUNET_free (curr_pk_string);
432 GNUNET_free (ego_pk_string);
433 return;
434 }
435 GNUNET_free (curr_pk_string);
436 }
437 GNUNET_free (ego_pk_string);
438}
439
440
441/**
442 * Creation operation finished.
443 * This method only handles errors that may have occurred. On success,
444 * the callback is executed by the ESCROW_list_ego function, as the
445 * new ego is in our ego list only after ESCROW_list_ego has added it.
446 *
447 * @param cls pointer to operation handle
448 * @param pk private key of the ego, or NULL on error
449 * @param emsg error message, NULL on success
450 */
451static void
452create_finished (void *cls,
453 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
454 const char *emsg)
455{
456 struct ESCROW_PlaintextPluginOperation *p_op = cls;
457
458 if (NULL == pk)
459 {
460 if (NULL != emsg)
461 {
462 fprintf (stderr,
463 "Identity create operation returned with error: %s\n",
464 emsg);
465 p_op->ego_wrap->emsg = _ ("Identity create failed!\n");
466 }
467 else
468 p_op->ego_wrap->emsg = _ ("Failed to create ego!\n");
469 p_op->ego_wrap->ego = NULL;
470 p_op->cont (p_op->ego_wrap);
471 return;
472 }
473
474 /* no error occurred, p_op->restore_cont will be called in ego_created, which
475 is called from ESCROW_list_ego after adding the new ego to our list */
476 p_op->pk = *pk;
477}
478
479
480static void
481handle_restore_error (void *cls)
482{
483 struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
484 struct ESCROW_PlaintextPluginOperation *p_op;
485
486 p_op = (struct ESCROW_PlaintextPluginOperation*)plugin_op_wrap->plugin_op;
487 p_op->sched_task = NULL;
488 p_op->cont (p_op->ego_wrap);
489
490 cleanup_plugin_operation (plugin_op_wrap);
491}
492
493
494/**
495 * Restore the key from plaintext escrow
496 *
497 * @param h the handle for the escrow component
498 * @param anchor the escrow anchor needed to restore the key
499 * @param cb the function called upon completion
500 * @param op_id unique ID of the respective ESCROW_Operation
501 *
502 * @return plugin operation wrapper
503 */
504struct ESCROW_PluginOperationWrapper *
505restore_plaintext_key_escrow (struct GNUNET_ESCROW_Handle *h,
506 const struct GNUNET_ESCROW_Anchor *anchor,
507 ESCROW_Plugin_Continuation cb,
508 uint32_t op_id)
509{
510 struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
511 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
512 struct ESCROW_PlaintextPluginOperation *p_op;
513 struct ESCROW_Plugin_EgoContinuationWrapper *w;
514
515 // create a new plaintext plugin operation (in a wrapper) and insert it into the DLL
516 plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
517 plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_PlaintextPluginOperation);
518 GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
519 ph.plugin_op_tail,
520 plugin_op_wrap);
521
522 p_op = (struct ESCROW_PlaintextPluginOperation *)plugin_op_wrap->plugin_op;
523 p_op->h = h;
524 // set cont here (has to be scheduled from the IDENTITY service when it finished)
525 p_op->cont = cb;
526
527 w = GNUNET_new (struct ESCROW_Plugin_EgoContinuationWrapper);
528 w->h = h;
529 w->op_id = op_id;
530 p_op->ego_wrap = w;
531
532 if (NULL == anchor)
533 {
534 w->ego = NULL;
535 w->emsg = _ ("ESCROW_get was called with anchor == NULL!\n");
536 // schedule handle_restore_error, which calls the callback and cleans up
537 p_op->sched_task = GNUNET_SCHEDULER_add_now (&handle_restore_error, plugin_op_wrap);
538 return plugin_op_wrap;
539 }
540 if (GNUNET_OK !=
541 GNUNET_CRYPTO_ecdsa_private_key_from_string ((char *)&anchor[1],
542 anchor->size,
543 &pk))
544 {
545 w->ego = NULL;
546 w->emsg = _ ("Failed to create ECDSA private key from escrow anchor!\n");
547 // schedule handle_restore_error, which calls the callback and cleans up
548 p_op->sched_task = GNUNET_SCHEDULER_add_now (&handle_restore_error, plugin_op_wrap);
549 return plugin_op_wrap;
550 }
551
552 p_op->id_op = GNUNET_IDENTITY_create (identity_handle,
553 anchor->egoName,
554 &pk,
555 &create_finished,
556 p_op);
557
558 return plugin_op_wrap;
559}
560
561
562/**
563 * Get the status of a plaintext escrow
564 *
565 * @param h the handle for the escrow component
566 * @param ego the identity ego of which the status has to be obtained
567 *
568 * @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
569 */
570struct GNUNET_ESCROW_Status *
571plaintext_get_status (struct GNUNET_ESCROW_Handle *h,
572 struct GNUNET_IDENTITY_Ego *ego)
573{
574 return ESCROW_get_escrow_status (h, ego);
575}
576
577
578/**
579 * Cancel a plaintext plugin operation.
580 *
581 * @param plugin_op_wrap the plugin operation wrapper containing the operation
582 */
583void
584cancel_plaintext_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
585{
586 struct ESCROW_PluginOperationWrapper *curr;
587 struct ESCROW_PlaintextPluginOperation *plugin_op;
588
589 for (curr = ph.plugin_op_head; NULL != curr; curr = curr->next)
590 {
591 if (curr == plugin_op_wrap)
592 {
593 GNUNET_CONTAINER_DLL_remove (ph.plugin_op_head,
594 ph.plugin_op_tail,
595 curr);
596 plugin_op = (struct ESCROW_PlaintextPluginOperation *)curr->plugin_op;
597 GNUNET_IDENTITY_cancel (plugin_op->id_op);
598 if (NULL != plugin_op->sched_task)
599 GNUNET_SCHEDULER_cancel (plugin_op->sched_task);
600 GNUNET_free (plugin_op);
601 GNUNET_free (curr);
602 return;
603 }
604 }
605}
606
607
608/**
609 * IdentityInitContinuation for the plaintext plugin
610 */
611static void
612plaintext_cont_init ()
613{
614 return;
615}
616
617
618/**
619 * Entry point for the plugin.
620 *
621 * @param cls Config info
622 *
623 * @return the exported block API
624 */
625void *
626libgnunet_plugin_escrow_plaintext_init (void *cls)
627{
628 struct GNUNET_ESCROW_KeyPluginFunctions *api;
629 struct GNUNET_CONFIGURATION_Handle *cfg = cls;
630
631 api = GNUNET_new (struct GNUNET_ESCROW_KeyPluginFunctions);
632 api->start_key_escrow = &start_plaintext_key_escrow;
633 api->verify_key_escrow = &verify_plaintext_key_escrow;
634 api->restore_key = &restore_plaintext_key_escrow;
635 api->get_status = &plaintext_get_status;
636 api->cancel_plugin_operation = &cancel_plaintext_operation;
637
638 ph.state = ESCROW_PLUGIN_STATE_INIT;
639 ph.id_init_cont = &plaintext_cont_init;
640
641 // set ego_create_cont here so it is called every time an ego is created
642 ph.ego_create_cont = &ego_created;
643 identity_handle = GNUNET_IDENTITY_connect (cfg,
644 &ESCROW_list_ego,
645 &ph);
646
647 return api;
648}
649
650
651/**
652 * Exit point from the plugin.
653 *
654 * @param cls the return value from #libgnunet_plugin_block_test_init()
655 *
656 * @return NULL
657 */
658void *
659libgnunet_plugin_escrow_plaintext_done (void *cls)
660{
661 struct GNUNET_ESCROW_KeyPluginFunctions *api = cls;
662
663 ph.state = ESCROW_PLUGIN_STATE_CLEANUP;
664
665 GNUNET_free (api);
666 GNUNET_IDENTITY_disconnect (identity_handle);
667 ESCROW_cleanup_ego_list (&ph);
668
669 return NULL;
670}
671
672
673/* end of plugin_escrow_plaintext.c */
diff --git a/src/escrow/plugin_gnsrecord_escrow.c b/src/escrow/plugin_gnsrecord_escrow.c
new file mode 100644
index 000000000..82ed3af96
--- /dev/null
+++ b/src/escrow/plugin_gnsrecord_escrow.c
@@ -0,0 +1,173 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file escrow/plugin_gnsrecord_escrow.c
23 * @brief gnsrecord plugin to provide the API for escrow records
24 *
25 * @author Johannes Späth
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_gnsrecord_plugin.h"
33
34/**
35 * Convert the 'value' of a record to a string.
36 *
37 * @param cls closure, unused
38 * @param type type of the record
39 * @param data value in binary encoding
40 * @param data_size number of bytes in @a data
41 * @return NULL on error, otherwise human-readable representation of the value
42 */
43static char *
44value_to_string (void *cls, uint32_t type, const void *data, size_t data_size)
45{
46 switch (type)
47 {
48 case GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE:
49 return GNUNET_STRINGS_data_to_string_alloc (data, data_size);
50
51 default:
52 return NULL;
53 }
54}
55
56/**
57 * Convert human-readable version of a 'value' of a record to the binary
58 * representation.
59 *
60 * @param cls closure, unused
61 * @param type type of the record
62 * @param s human-readable string
63 * @param data set to value in binary encoding (will be allocated)
64 * @param data_size set to number of bytes in @a data
65 * @return #GNUNET_OK on success
66 */
67static int
68string_to_value (void *cls, uint32_t type, const char *s, void **data,
69 size_t *data_size)
70{
71 if (NULL == s)
72 return GNUNET_SYSERR;
73 switch (type)
74 {
75 case GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE:
76 return GNUNET_STRINGS_string_to_data (s, strlen (s), *data, *data_size);
77
78 default:
79 return GNUNET_SYSERR;
80 }
81}
82
83
84/**
85 * Mapping of record type numbers to human-readable
86 * record type names.
87 */
88static struct
89{
90 const char *name;
91 uint32_t number;
92} name_map[] = {
93 { "GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE", GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE },
94 { NULL, UINT32_MAX }
95};
96
97
98/**
99 * Convert a type name (i.e. "AAAA") to the corresponding number.
100 *
101 * @param cls closure, unused
102 * @param dns_typename name to convert
103 * @return corresponding number, UINT32_MAX on error
104 */
105static uint32_t
106typename_to_number (void *cls, const char *dns_typename)
107{
108 unsigned int i;
109
110 i = 0;
111 while ((NULL != name_map[i].name) &&
112 (0 != strcasecmp (dns_typename, name_map[i].name)))
113 i++;
114 return name_map[i].number;
115}
116
117
118/**
119 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
120 *
121 * @param cls closure, unused
122 * @param type number of a type to convert
123 * @return corresponding typestring, NULL on error
124 */
125static const char *
126number_to_typename (void *cls, uint32_t type)
127{
128 unsigned int i;
129
130 i = 0;
131 while ((NULL != name_map[i].name) && (type != name_map[i].number))
132 i++;
133 return name_map[i].name;
134}
135
136
137/**
138 * Entry point for the plugin.
139 *
140 * @param cls NULL
141 * @return the exported block API
142 */
143void *
144libgnunet_plugin_gnsrecord_escrow_init (void *cls)
145{
146 struct GNUNET_GNSRECORD_PluginFunctions *api;
147
148 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
149 api->value_to_string = &value_to_string;
150 api->string_to_value = &string_to_value;
151 api->typename_to_number = &typename_to_number;
152 api->number_to_typename = &number_to_typename;
153 return api;
154}
155
156
157/**
158 * Exit point from the plugin.
159 *
160 * @param cls the return value from #libgnunet_plugin_block_test_init
161 * @return NULL
162 */
163void *
164libgnunet_plugin_gnsrecord_escrow_done (void *cls)
165{
166 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
167
168 GNUNET_free (api);
169 return NULL;
170}
171
172
173/* end of plugin_gnsrecord_escrow.c */
diff --git a/src/escrow/plugin_rest_escrow.c b/src/escrow/plugin_rest_escrow.c
new file mode 100644
index 000000000..796578dd6
--- /dev/null
+++ b/src/escrow/plugin_rest_escrow.c
@@ -0,0 +1,1311 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Johannes Späth
22 * @file escrow/plugin_rest_escrow.c
23 * @brief GNUnet Escrow REST plugin
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include "gnunet_escrow_lib.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_rest_lib.h"
31#include "microhttpd.h"
32#include <jansson.h>
33
34/**
35 * Escrow Namespace
36 */
37#define GNUNET_REST_API_NS_ESCROW "/escrow"
38
39/**
40 * Escrow Put Namespace
41 */
42#define GNUNET_REST_API_NS_ESCROW_PUT "/escrow/put"
43
44/**
45 * Escrow Get Namespace
46 */
47#define GNUNET_REST_API_NS_ESCROW_GET "/escrow/get"
48
49/**
50 * Escrow Verify Namespace
51 */
52#define GNUNET_REST_API_NS_ESCROW_VERIFY "/escrow/verify"
53
54/**
55 * Escrow Status Namespace
56 */
57#define GNUNET_REST_API_NS_ESCROW_STATUS "/escrow/status"
58
59/**
60 * Error message Unknown Error
61 */
62#define GNUNET_REST_ESCROW_ERROR_UNKNOWN "Unknown Error"
63
64/**
65 * Error message Missing identity name
66 */
67#define GNUNET_REST_ESCROW_MISSING_NAME "Missing identity name"
68
69/**
70 * Error message Missing escrow anchor
71 */
72#define GNUNET_REST_ESCROW_MISSING_ANCHOR "Missing escrow anchor"
73
74/**
75 * Error message Identity not found
76 */
77#define GNUNET_REST_ESCROW_ID_NOT_FOUND "Identity not found"
78
79/**
80 * Error message Method not found
81 */
82#define GNUNET_REST_ESCROW_METHOD_NOT_FOUND "Method not found"
83
84/**
85 * Error message Escrow failed
86 */
87#define GNUNET_REST_ESCROW_ESCROW_FAILED "Escrow failed"
88
89/**
90 * Error message Restoration failed
91 */
92#define GNUNET_REST_ESCROW_RESTORE_FAILED "Restoration failed"
93
94/**
95 * Error message Got invalid status
96 */
97#define GNUNET_REST_ESCROW_INVALID_STATUS "Got invalid status"
98
99/**
100 * Error message No data
101 */
102#define GNUNET_REST_ERROR_NO_DATA "No data"
103
104/**
105 * Error message Data invalid
106 */
107#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
108
109/**
110 * Error message Failed to parse anchor
111 */
112#define GNUNET_REST_ESCROW_ANCHOR_ERROR "Failed to parse anchor"
113
114/**
115 * Parameter anchor-data
116 */
117#define GNUNET_REST_ESCROW_PARAM_ANCHOR_DATA "anchorData"
118
119/**
120 * Parameter method
121 */
122#define GNUNET_REST_ESCROW_PARAM_METHOD "method"
123
124/**
125 * Parameter user-secret
126 */
127#define GNUNET_REST_ESCROW_PARAM_USER_SECRET "userSecret"
128
129/**
130 * Parameter pubkey
131 */
132#define GNUNET_REST_ESCROW_PARAM_PUBKEY "pubkey"
133
134/**
135 * Parameter name
136 */
137#define GNUNET_REST_ESCROW_PARAM_NAME "name"
138
139/**
140 * Parameter verification-result
141 */
142#define GNUNET_REST_ESCROW_PARAM_VERIFICATION_RESULT "verificationResult"
143
144/**
145 * Parameter last-method
146 */
147#define GNUNET_REST_ESCROW_PARAM_LAST_METHOD "lastMethod"
148
149/**
150 * Parameter last-successful-verification
151 */
152#define GNUNET_REST_ESCROW_PARAM_LAST_VERIF "lastSuccessfulVerification"
153
154/**
155 * Parameter next-recommended-verification
156 */
157#define GNUNET_REST_ESCROW_PARAM_NEXT_VERIF "nextRecommendedVerification"
158
159/**
160 * State while collecting all egos
161 */
162#define ID_REST_STATE_INIT 0
163
164/**
165 * Done collecting egos
166 */
167#define ID_REST_STATE_POST_INIT 1
168
169/**
170 * The configuration handle
171 */
172const struct GNUNET_CONFIGURATION_Handle *cfg;
173
174/**
175 * HTTP methods allows for this plugin
176 */
177static char *allow_methods;
178
179/**
180 * Ego list
181 */
182static struct EgoEntry *ego_head;
183
184/**
185 * Ego list
186 */
187static struct EgoEntry *ego_tail;
188
189/**
190 * The processing state
191 */
192static int state;
193
194/**
195 * Handle to the identity service
196 */
197static struct GNUNET_IDENTITY_Handle *identity_handle;
198
199/**
200 * Handle to the escrow component
201 */
202static struct GNUNET_ESCROW_Handle *escrow_handle;
203
204/**
205 * @brief struct returned by the initialization function of the plugin
206 */
207struct Plugin
208{
209 const struct GNUNET_CONFIGURATION_Handle *cfg;
210};
211
212/**
213 * The ego list
214 */
215struct EgoEntry
216{
217 /**
218 * DLL
219 */
220 struct EgoEntry *next;
221
222 /**
223 * DLL
224 */
225 struct EgoEntry *prev;
226
227 /**
228 * Ego Identifier
229 */
230 char *identifier;
231
232 /**
233 * Public key string
234 */
235 char *keystring;
236
237 /**
238 * The Ego
239 */
240 struct GNUNET_IDENTITY_Ego *ego;
241};
242
243/**
244 * The request handle
245 */
246struct RequestHandle
247{
248 /**
249 * DLL
250 */
251 struct RequestHandle *next;
252
253 /**
254 * DLL
255 */
256 struct RequestHandle *prev;
257
258 /**
259 * The data from the REST request
260 */
261 const char *data;
262
263 /**
264 * The name to look up
265 */
266 char *name;
267
268 /**
269 * the length of the REST data
270 */
271 size_t data_size;
272
273 /**
274 * ESCROW Operation
275 */
276 struct GNUNET_ESCROW_Operation *op;
277
278 /**
279 * Rest connection
280 */
281 struct GNUNET_REST_RequestHandle *rest_handle;
282
283 /**
284 * Desired timeout for the lookup (default is no timeout).
285 */
286 struct GNUNET_TIME_Relative timeout;
287
288 /**
289 * ID of a task associated with the resolution process.
290 */
291 struct GNUNET_SCHEDULER_Task *timeout_task;
292
293 /**
294 * The plugin result processor
295 */
296 GNUNET_REST_ResultProcessor proc;
297
298 /**
299 * The closure of the result processor
300 */
301 void *proc_cls;
302
303 /**
304 * The url
305 */
306 char *url;
307
308 /**
309 * Error response message
310 */
311 char *emsg;
312
313 /**
314 * Response code
315 */
316 int response_code;
317
318 /**
319 * Response object
320 */
321 json_t *resp_object;
322};
323
324/**
325 * DLL
326 */
327static struct RequestHandle *requests_head;
328
329/**
330 * DLL
331 */
332static struct RequestHandle *requests_tail;
333
334/**
335 * Cleanup lookup handle
336 * @param handle Handle to clean up
337 */
338static void
339cleanup_handle (void *cls)
340{
341 struct RequestHandle *handle = cls;
342
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
344 if (NULL != handle->timeout_task)
345 {
346 GNUNET_SCHEDULER_cancel (handle->timeout_task);
347 handle->timeout_task = NULL;
348 }
349
350 if (NULL != handle->url)
351 GNUNET_free (handle->url);
352 if (NULL != handle->emsg)
353 GNUNET_free (handle->emsg);
354 if (NULL != handle->name)
355 GNUNET_free (handle->name);
356 GNUNET_CONTAINER_DLL_remove (requests_head,
357 requests_tail,
358 handle);
359 GNUNET_free (handle);
360}
361
362
363/**
364 * Task run on errors. Reports an error and cleans up everything.
365 *
366 * @param cls the `struct RequestHandle`
367 */
368static void
369do_error (void *cls)
370{
371 struct RequestHandle *handle = cls;
372 struct MHD_Response *resp;
373 json_t *json_error = json_object ();
374 char *response;
375
376 if (NULL == handle->emsg)
377 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ERROR_UNKNOWN);
378
379 json_object_set_new (json_error, "error", json_string (handle->emsg));
380
381 if (0 == handle->response_code)
382 handle->response_code = MHD_HTTP_OK;
383 response = json_dumps (json_error, 0);
384 resp = GNUNET_REST_create_response (response);
385 MHD_add_response_header (resp, "Content-Type", "application/json");
386 handle->proc (handle->proc_cls, resp, handle->response_code);
387 json_decref (json_error);
388 GNUNET_free (response);
389 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
390}
391
392
393static enum GNUNET_ESCROW_Key_Escrow_Method
394determine_escrow_method (struct GNUNET_CONTAINER_MultiHashMap *url_param_map)
395{
396 struct GNUNET_HashCode method_key;
397 char *method_string;
398 enum GNUNET_ESCROW_Key_Escrow_Method method;
399
400 GNUNET_CRYPTO_hash ("method", strlen ("method"), &method_key);
401 method_string = GNUNET_CONTAINER_multihashmap_get (url_param_map,
402 &method_key);
403 // default method is plaintext
404 if (NULL == method_string)
405 method = GNUNET_ESCROW_KEY_PLAINTEXT;
406 else
407 method = GNUNET_ESCROW_method_string_to_number (method_string);
408
409 return method;
410}
411
412
413static char *
414get_user_secret_from_payload (struct RequestHandle *handle)
415{
416 json_t *json_data;
417 json_error_t err;
418 char *user_secret, *user_secret_cpy;
419 int json_unpack_state;
420 char term_data[handle->data_size + 1];
421
422 if (0 >= handle->data_size)
423 {
424 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
425 handle->response_code = MHD_HTTP_BAD_REQUEST;
426 GNUNET_SCHEDULER_add_now (&do_error, handle);
427 return NULL;
428 }
429
430 term_data[handle->data_size] = '\0';
431 GNUNET_memcpy (term_data, handle->data, handle->data_size);
432 json_data = json_loads (term_data, JSON_DECODE_ANY, &err);
433 if (NULL == json_data)
434 {
435 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
436 handle->response_code = MHD_HTTP_BAD_REQUEST;
437 GNUNET_SCHEDULER_add_now (&do_error, handle);
438 json_decref (json_data);
439 return NULL;
440 }
441
442 json_unpack_state = 0;
443 json_unpack_state =
444 json_unpack (json_data, "{s:s}",
445 GNUNET_REST_ESCROW_PARAM_USER_SECRET, &user_secret);
446 if (0 != json_unpack_state)
447 {
448 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
449 handle->response_code = MHD_HTTP_BAD_REQUEST;
450 GNUNET_SCHEDULER_add_now (&do_error, handle);
451 json_decref (json_data);
452 return NULL;
453 }
454
455 if (NULL == user_secret)
456 {
457 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
458 handle->response_code = MHD_HTTP_BAD_REQUEST;
459 GNUNET_SCHEDULER_add_now (&do_error, handle);
460 json_decref (json_data);
461 return NULL;
462 }
463 if (0 >= strlen (user_secret))
464 {
465 json_decref (json_data);
466 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
467 handle->response_code = MHD_HTTP_BAD_REQUEST;
468 GNUNET_SCHEDULER_add_now (&do_error, handle);
469 return NULL;
470 }
471
472 user_secret_cpy = GNUNET_strdup (user_secret);
473 json_decref (json_data);
474
475 return user_secret_cpy;
476}
477
478
479static void
480escrow_finished (void *cls,
481 struct GNUNET_ESCROW_Anchor *anchor,
482 const char *emsg)
483{
484 struct RequestHandle *handle = cls;
485 struct MHD_Response *resp;
486 json_t *json_anchor;
487 const char*anchor_data;
488 char *anchor_data_enc, *result_string;
489
490 if (NULL == anchor)
491 {
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493 "Failed to escrow ego.\n");
494 handle->response_code = MHD_HTTP_NO_CONTENT;
495 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ESCROW_FAILED);
496 GNUNET_SCHEDULER_add_now (&do_error, handle);
497 return;
498 }
499
500 json_anchor = json_object ();
501 json_object_set_new (json_anchor,
502 GNUNET_REST_ESCROW_PARAM_METHOD,
503 json_string (GNUNET_ESCROW_method_number_to_string (
504 anchor->method)));
505 json_object_set_new (json_anchor,
506 GNUNET_REST_ESCROW_PARAM_NAME,
507 json_string (anchor->egoName));
508 anchor_data = (const char *)&anchor[1];
509 GNUNET_STRINGS_urlencode (anchor_data, anchor->size, &anchor_data_enc);
510 json_object_set_new (json_anchor,
511 GNUNET_REST_ESCROW_PARAM_ANCHOR_DATA,
512 json_string (anchor_data_enc));
513
514 result_string = json_dumps (json_anchor, 0);
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
516 resp = GNUNET_REST_create_response (result_string);
517 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
518 MHD_add_response_header (resp, "Content-Type", "application/json");
519
520 json_decref (json_anchor);
521 GNUNET_free (result_string);
522 GNUNET_free (anchor_data_enc);
523
524 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
525}
526
527
528/**
529 * Respond to PUT (start_escrow) request
530 *
531 * @param con_handle the connection handle
532 * @param url the url
533 * @param cls the RequestHandle
534 */
535static void
536escrow_identity (struct GNUNET_REST_RequestHandle *con_handle,
537 const char *url,
538 void *cls)
539{
540 struct RequestHandle *handle = cls;
541 struct EgoEntry *ego_entry;
542 char *identity, *userSecret;
543 enum GNUNET_ESCROW_Key_Escrow_Method method;
544
545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
546 "Putting %s into escrow.\n",
547 handle->url);
548
549 if (strlen (GNUNET_REST_API_NS_ESCROW_PUT) >= strlen (handle->url))
550 {
551 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
552 handle->response_code = MHD_HTTP_NOT_FOUND;
553 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_MISSING_NAME);
554 GNUNET_SCHEDULER_add_now (&do_error, handle);
555 return;
556 }
557 identity = handle->url + strlen (GNUNET_REST_API_NS_ESCROW_PUT) + 1;
558
559 for (ego_entry = ego_head; NULL != ego_entry;
560 ego_entry = ego_entry->next)
561 if (0 == strcmp (identity, ego_entry->identifier))
562 break;
563
564 if (NULL == ego_entry)
565 {
566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567 "Identity %s not found.\n",
568 identity);
569 handle->response_code = MHD_HTTP_NOT_FOUND;
570 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
571 GNUNET_SCHEDULER_add_now (&do_error, handle);
572 return;
573 }
574
575 /* determine method */
576 method = determine_escrow_method (handle->rest_handle->url_param_map);
577 if (GNUNET_ESCROW_KEY_NONE == method)
578 {
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "Method not found.\n");
581 handle->response_code = MHD_HTTP_NOT_FOUND;
582 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_METHOD_NOT_FOUND);
583 GNUNET_SCHEDULER_add_now (&do_error, handle);
584 return;
585 }
586
587 /* get user secret */
588 if (GNUNET_ESCROW_KEY_PLAINTEXT != method)
589 {
590 userSecret = get_user_secret_from_payload (handle);
591 if (NULL == userSecret)
592 // get_user_secret_from_payload () already cleaned up
593 return;
594 }
595 else
596 userSecret = NULL;
597
598 handle->op = GNUNET_ESCROW_put (escrow_handle,
599 ego_entry->ego,
600 userSecret,
601 method,
602 &escrow_finished,
603 handle);
604
605 if (NULL != userSecret)
606 GNUNET_free (userSecret);
607}
608
609
610static struct GNUNET_ESCROW_Anchor *
611build_anchor (const char *method_string,
612 const char *ego_name,
613 const char *anchor_data_enc)
614{
615 struct GNUNET_ESCROW_Anchor *anchor;
616 char *ptr;
617 enum GNUNET_ESCROW_Key_Escrow_Method method;
618 char *anchor_data;
619
620 method = GNUNET_ESCROW_method_string_to_number (method_string);
621 if (GNUNET_ESCROW_KEY_NONE == method)
622 return NULL;
623 GNUNET_STRINGS_urldecode (anchor_data_enc,
624 strlen (anchor_data_enc),
625 &anchor_data);
626
627 anchor = GNUNET_malloc (sizeof (struct GNUNET_ESCROW_Anchor)
628 + strlen (anchor_data)
629 + strlen (ego_name) + 1);
630 anchor->method = method;
631 anchor->size = strlen (anchor_data);
632 ptr = (char *)&anchor[1];
633 GNUNET_memcpy (ptr, anchor_data, strlen (anchor_data));
634 ptr += strlen (anchor_data);
635 anchor->egoName = ptr;
636 strcpy (ptr, ego_name);
637
638 GNUNET_free (anchor_data);
639
640 return anchor;
641}
642
643
644static struct GNUNET_ESCROW_Anchor *
645get_anchor_from_payload (struct RequestHandle *handle)
646{
647 json_t *json_data;
648 json_error_t err;
649 char *method, *ego_name, *anchor_data_enc;
650 int json_unpack_state;
651 char term_data[handle->data_size + 1];
652 struct GNUNET_ESCROW_Anchor *anchor;
653
654 if (0 >= handle->data_size)
655 {
656 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
657 handle->response_code = MHD_HTTP_BAD_REQUEST;
658 GNUNET_SCHEDULER_add_now (&do_error, handle);
659 return NULL;
660 }
661
662 term_data[handle->data_size] = '\0';
663 GNUNET_memcpy (term_data, handle->data, handle->data_size);
664 json_data = json_loads (term_data, JSON_DECODE_ANY, &err);
665 if (NULL == json_data)
666 {
667 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
668 handle->response_code = MHD_HTTP_BAD_REQUEST;
669 GNUNET_SCHEDULER_add_now (&do_error, handle);
670 json_decref (json_data);
671 return NULL;
672 }
673
674 json_unpack_state = 0;
675 json_unpack_state =
676 json_unpack (json_data, "{s:s, s:s, s:s}",
677 GNUNET_REST_ESCROW_PARAM_METHOD, &method,
678 GNUNET_REST_ESCROW_PARAM_NAME, &ego_name,
679 GNUNET_REST_ESCROW_PARAM_ANCHOR_DATA, &anchor_data_enc);
680 if (0 != json_unpack_state)
681 {
682 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
683 handle->response_code = MHD_HTTP_BAD_REQUEST;
684 GNUNET_SCHEDULER_add_now (&do_error, handle);
685 json_decref (json_data);
686 return NULL;
687 }
688
689 if (NULL == method || NULL == ego_name || NULL == anchor_data_enc)
690 {
691 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
692 handle->response_code = MHD_HTTP_BAD_REQUEST;
693 GNUNET_SCHEDULER_add_now (&do_error, handle);
694 json_decref (json_data);
695 return NULL;
696 }
697 if (0 >= strlen (method) || 0 >= strlen (ego_name) || 0 >= strlen (anchor_data_enc))
698 {
699 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
700 handle->response_code = MHD_HTTP_BAD_REQUEST;
701 GNUNET_SCHEDULER_add_now (&do_error, handle);
702 json_decref (json_data);
703 return NULL;
704 }
705
706 anchor = build_anchor (method, ego_name, anchor_data_enc);
707 if (NULL == anchor)
708 {
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
710 "Failed to parse anchor.\n");
711 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
712 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ANCHOR_ERROR);
713 GNUNET_SCHEDULER_add_now (&do_error, handle);
714 json_decref (json_data);
715 return NULL;
716 }
717
718 json_decref (json_data);
719
720 return anchor;
721}
722
723
724static void
725restore_finished (void *cls,
726 struct GNUNET_IDENTITY_Ego *ego,
727 const char *emsg)
728{
729 struct RequestHandle *handle = cls;
730 struct EgoEntry *ego_entry;
731 struct MHD_Response *resp;
732 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
733 json_t *json_ego;
734 char *keystring, *result_string;
735
736 if (NULL == ego)
737 {
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
739 "Failed to restore ego.\n");
740 handle->response_code = MHD_HTTP_NO_CONTENT;
741 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_RESTORE_FAILED);
742 GNUNET_SCHEDULER_add_now (&do_error, handle);
743 return;
744 }
745
746 GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub);
747 keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_pub);
748
749 for (ego_entry = ego_head; NULL != ego_entry;
750 ego_entry = ego_entry->next)
751 if (0 == strcmp (keystring, ego_entry->keystring))
752 break;
753
754 if (NULL == ego_entry)
755 {
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757 "Identity not found despite successful restoration.\n");
758 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
759 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
760 GNUNET_SCHEDULER_add_now (&do_error, handle);
761 GNUNET_free (keystring);
762 return;
763 }
764
765 json_ego = json_object ();
766 json_object_set_new (json_ego,
767 GNUNET_REST_ESCROW_PARAM_NAME,
768 json_string (ego_entry->identifier));
769 json_object_set_new (json_ego,
770 GNUNET_REST_ESCROW_PARAM_PUBKEY,
771 json_string (ego_entry->keystring));
772
773 result_string = json_dumps (json_ego, 0);
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
775 resp = GNUNET_REST_create_response (result_string);
776 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
777 MHD_add_response_header (resp, "Content-Type", "application/json");
778
779 json_decref (json_ego);
780 GNUNET_free (result_string);
781 GNUNET_free (keystring);
782
783 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
784}
785
786
787/**
788 * Respond to GET (restore) request
789 *
790 * @param con_handle the connection handle
791 * @param url the url
792 * @param cls the RequestHandle
793 */
794static void
795get_escrowed_identity (struct GNUNET_REST_RequestHandle *con_handle,
796 const char *url,
797 void *cls)
798{
799 struct RequestHandle *handle = cls;
800 struct GNUNET_ESCROW_Anchor *anchor;
801
802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803 "Getting %s from escrow.\n",
804 handle->url);
805
806 /* get anchor */
807 anchor = get_anchor_from_payload (handle);
808 if (NULL == anchor)
809 // get_anchor_from_payload () already cleaned up
810 return;
811
812 handle->op = GNUNET_ESCROW_get (escrow_handle,
813 anchor,
814 &restore_finished,
815 handle);
816}
817
818
819static void
820verify_finished (void *cls,
821 int verificationResult,
822 const char *emsg)
823{
824 struct RequestHandle *handle = cls;
825 struct MHD_Response *resp;
826 json_t *json_verif;
827 const char *verif_string;
828 char *result_string;
829
830 switch (verificationResult)
831 {
832 case GNUNET_ESCROW_VALID:
833 verif_string = "valid";
834 break;
835 case GNUNET_ESCROW_INVALID:
836 verif_string = "invalid";
837 break;
838 case GNUNET_ESCROW_SHARES_MISSING:
839 verif_string = "shares_missing";
840 break;
841 default:
842 verif_string = "unknown";
843 }
844
845 json_verif = json_object ();
846 json_object_set_new (json_verif,
847 GNUNET_REST_ESCROW_PARAM_VERIFICATION_RESULT,
848 json_string (verif_string));
849
850 result_string = json_dumps (json_verif, 0);
851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
852 resp = GNUNET_REST_create_response (result_string);
853 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
854 MHD_add_response_header (resp, "Content-Type", "application/json");
855
856 json_decref (json_verif);
857 GNUNET_free (result_string);
858
859 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
860}
861
862
863/**
864 * Respond to VERIFY request
865 *
866 * @param con_handle the connection handle
867 * @param url the url
868 * @param cls the RequestHandle
869 */
870static void
871verify_escrow (struct GNUNET_REST_RequestHandle *con_handle,
872 const char *url,
873 void *cls)
874{
875 struct RequestHandle *handle = cls;
876 struct EgoEntry *ego_entry;
877 struct GNUNET_ESCROW_Anchor *anchor;
878 char *identity;
879 enum GNUNET_ESCROW_Key_Escrow_Method method;
880
881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
882 "Verifying escrow of %s.\n",
883 handle->url);
884
885 if (strlen (GNUNET_REST_API_NS_ESCROW_VERIFY) >= strlen (handle->url))
886 {
887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
888 handle->response_code = MHD_HTTP_NOT_FOUND;
889 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_MISSING_NAME);
890 GNUNET_SCHEDULER_add_now (&do_error, handle);
891 return;
892 }
893 identity = handle->url + strlen (GNUNET_REST_API_NS_ESCROW_VERIFY) + 1;
894
895 for (ego_entry = ego_head; NULL != ego_entry;
896 ego_entry = ego_entry->next)
897 if (0 == strcmp (identity, ego_entry->identifier))
898 break;
899
900 if (NULL == ego_entry)
901 {
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Identity %s not found.\n",
904 identity);
905 handle->response_code = MHD_HTTP_NOT_FOUND;
906 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
907 GNUNET_SCHEDULER_add_now (&do_error, handle);
908 return;
909 }
910
911 /* determine method */
912 method = determine_escrow_method (handle->rest_handle->url_param_map);
913 if (GNUNET_ESCROW_KEY_NONE == method)
914 {
915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
916 "Method not found.\n");
917 handle->response_code = MHD_HTTP_NOT_FOUND;
918 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_METHOD_NOT_FOUND);
919 GNUNET_SCHEDULER_add_now (&do_error, handle);
920 return;
921 }
922
923 /* get anchor */
924 anchor = get_anchor_from_payload (handle);
925 if (NULL == anchor)
926 // get_anchor_from_payload () already cleaned up
927 return;
928
929 handle->op = GNUNET_ESCROW_verify (escrow_handle,
930 ego_entry->ego,
931 anchor,
932 method,
933 &verify_finished,
934 handle);
935}
936
937
938/**
939 * Respond to STATUS request
940 *
941 * @param con_handle the connection handle
942 * @param url the url
943 * @param cls the RequestHandle
944 */
945static void
946get_escrow_status (struct GNUNET_REST_RequestHandle *con_handle,
947 const char *url,
948 void *cls)
949{
950 struct RequestHandle *handle = cls;
951 struct EgoEntry *ego_entry;
952 struct GNUNET_ESCROW_Status *status;
953 struct MHD_Response *resp;
954 char *identity;
955 enum GNUNET_ESCROW_Key_Escrow_Method method;
956 json_t *json_status;
957 char *result_string;
958
959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
960 "Getting escrow status of %s.\n",
961 handle->url);
962
963 if (strlen (GNUNET_REST_API_NS_ESCROW_STATUS) >= strlen (handle->url))
964 {
965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
966 handle->response_code = MHD_HTTP_NOT_FOUND;
967 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_MISSING_NAME);
968 GNUNET_SCHEDULER_add_now (&do_error, handle);
969 return;
970 }
971 identity = handle->url + strlen (GNUNET_REST_API_NS_ESCROW_STATUS) + 1;
972
973 for (ego_entry = ego_head; NULL != ego_entry;
974 ego_entry = ego_entry->next)
975 if (0 == strcmp (identity, ego_entry->identifier))
976 break;
977
978 if (NULL == ego_entry)
979 {
980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
981 "Identity %s not found.\n",
982 identity);
983 handle->response_code = MHD_HTTP_NOT_FOUND;
984 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_ID_NOT_FOUND);
985 GNUNET_SCHEDULER_add_now (&do_error, handle);
986 return;
987 }
988
989 /* determine method */
990 method = determine_escrow_method (handle->rest_handle->url_param_map);
991 if (GNUNET_ESCROW_KEY_NONE == method)
992 {
993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
994 "Method not found.\n");
995 handle->response_code = MHD_HTTP_NOT_FOUND;
996 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_METHOD_NOT_FOUND);
997 GNUNET_SCHEDULER_add_now (&do_error, handle);
998 return;
999 }
1000
1001 status = GNUNET_ESCROW_get_status (escrow_handle,
1002 ego_entry->ego,
1003 method);
1004
1005 if (NULL == status)
1006 {
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008 "Got invalid status.\n");
1009 handle->response_code = MHD_HTTP_NO_CONTENT;
1010 handle->emsg = GNUNET_strdup (GNUNET_REST_ESCROW_INVALID_STATUS);
1011 GNUNET_SCHEDULER_add_now (&do_error, handle);
1012 return;
1013 }
1014
1015 /* create and send response */
1016 json_status = json_object ();
1017 if (GNUNET_ESCROW_KEY_NONE == status->last_method)
1018 json_object_set_new (json_status,
1019 GNUNET_REST_ESCROW_PARAM_LAST_METHOD,
1020 json_string ("none"));
1021 else
1022 {
1023 json_object_set_new (json_status,
1024 GNUNET_REST_ESCROW_PARAM_LAST_METHOD,
1025 json_string (
1026 GNUNET_ESCROW_method_number_to_string (status->last_method)));
1027 json_object_set_new (json_status,
1028 GNUNET_REST_ESCROW_PARAM_LAST_VERIF,
1029 json_integer (
1030 status->last_successful_verification_time.abs_value_us / 1000));
1031 json_object_set_new (json_status,
1032 GNUNET_REST_ESCROW_PARAM_NEXT_VERIF,
1033 json_integer (
1034 status->next_recommended_verification_time.abs_value_us / 1000));
1035 }
1036
1037 result_string = json_dumps (json_status, 0);
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_string);
1039 resp = GNUNET_REST_create_response (result_string);
1040 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1041 MHD_add_response_header (resp, "Content-Type", "application/json");
1042
1043 json_decref (json_status);
1044 GNUNET_free (result_string);
1045
1046 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1047}
1048
1049
1050/**
1051 * Respond to OPTIONS request
1052 *
1053 * @param con_handle the connection handle
1054 * @param url the url
1055 * @param cls the RequestHandle
1056 */
1057static void
1058options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1059 const char *url,
1060 void *cls)
1061{
1062 struct MHD_Response *resp;
1063 struct RequestHandle *handle = cls;
1064
1065 // For now, independent of path return all options
1066 resp = GNUNET_REST_create_response (NULL);
1067 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1068 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1069 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1070 return;
1071}
1072
1073
1074/**
1075 * If listing is enabled, prints information about the egos.
1076 *
1077 * This function is initially called for all egos and then again
1078 * whenever a ego's identifier changes or if it is deleted. At the
1079 * end of the initial pass over all egos, the function is once called
1080 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1081 * be invoked in the future or that there was an error.
1082 *
1083 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1084 * this function is only called ONCE, and 'NULL' being passed in
1085 * 'ego' does indicate an error (i.e. name is taken or no default
1086 * value is known). If 'ego' is non-NULL and if '*ctx'
1087 * is set in those callbacks, the value WILL be passed to a subsequent
1088 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1089 * that one was not NULL).
1090 *
1091 * When an identity is renamed, this function is called with the
1092 * (known) ego but the NEW identifier.
1093 *
1094 * When an identity is deleted, this function is called with the
1095 * (known) ego and "NULL" for the 'identifier'. In this case,
1096 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1097 * cleaned up).
1098 *
1099 * @param cls closure
1100 * @param ego ego handle
1101 * @param ctx context for application to store data for this ego
1102 * (during the lifetime of this process, initially NULL)
1103 * @param identifier identifier assigned by the user for this ego,
1104 * NULL if the user just deleted the ego and it
1105 * must thus no longer be used
1106 */
1107static void
1108list_ego (void *cls,
1109 struct GNUNET_IDENTITY_Ego *ego,
1110 void **ctx,
1111 const char *identifier)
1112{
1113 struct EgoEntry *ego_entry;
1114 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1115
1116 if ((NULL == ego) && (ID_REST_STATE_INIT == state))
1117 {
1118 state = ID_REST_STATE_POST_INIT;
1119 return;
1120 }
1121 if (ID_REST_STATE_INIT == state)
1122 {
1123 ego_entry = GNUNET_new (struct EgoEntry);
1124 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1125 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1126 ego_entry->ego = ego;
1127 ego_entry->identifier = GNUNET_strdup (identifier);
1128 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1129 ego_tail,
1130 ego_entry);
1131 }
1132 /* Ego renamed or added */
1133 if (identifier != NULL)
1134 {
1135 for (ego_entry = ego_head; NULL != ego_entry;
1136 ego_entry = ego_entry->next)
1137 {
1138 if (ego_entry->ego == ego)
1139 {
1140 /* Rename */
1141 GNUNET_free (ego_entry->identifier);
1142 ego_entry->identifier = GNUNET_strdup (identifier);
1143 break;
1144 }
1145 }
1146 if (NULL == ego_entry)
1147 {
1148 /* Add */
1149 ego_entry = GNUNET_new (struct EgoEntry);
1150 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1151 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1152 ego_entry->ego = ego;
1153 ego_entry->identifier = GNUNET_strdup (identifier);
1154 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1155 ego_tail,
1156 ego_entry);
1157 }
1158 }
1159 else
1160 {
1161 /* Delete */
1162 for (ego_entry = ego_head; NULL != ego_entry;
1163 ego_entry = ego_entry->next)
1164 {
1165 if (ego_entry->ego == ego)
1166 break;
1167 }
1168 if (NULL == ego_entry)
1169 return; /* Not found */
1170
1171 GNUNET_CONTAINER_DLL_remove (ego_head,
1172 ego_tail,
1173 ego_entry);
1174 GNUNET_free (ego_entry->identifier);
1175 GNUNET_free (ego_entry->keystring);
1176 GNUNET_free (ego_entry);
1177 return;
1178 }
1179
1180}
1181
1182
1183/**
1184 * Function processing the REST call
1185 *
1186 * @param method HTTP method
1187 * @param url URL of the HTTP request
1188 * @param data body of the HTTP request (optional)
1189 * @param data_size length of the body
1190 * @param proc callback function for the result
1191 * @param proc_cls closure for callback function
1192 * @return GNUNET_OK if request accepted
1193 */
1194static enum GNUNET_GenericReturnValue
1195rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1196 GNUNET_REST_ResultProcessor proc,
1197 void *proc_cls)
1198{
1199 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1200 struct GNUNET_REST_RequestHandlerError err;
1201 static const struct GNUNET_REST_RequestHandler handlers[] =
1202 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_ESCROW_STATUS, &get_escrow_status },
1203 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_ESCROW_VERIFY, &verify_escrow },
1204 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_ESCROW_GET, &get_escrowed_identity },
1205 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_ESCROW_PUT, &escrow_identity },
1206 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_ESCROW, &options_cont },
1207 GNUNET_REST_HANDLER_END };
1208
1209
1210 handle->response_code = 0;
1211 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1212 handle->proc_cls = proc_cls;
1213 handle->proc = proc;
1214 handle->rest_handle = rest_handle;
1215 handle->data = rest_handle->data;
1216 handle->data_size = rest_handle->data_size;
1217
1218 handle->url = GNUNET_strdup (rest_handle->url);
1219 if (handle->url[strlen (handle->url) - 1] == '/')
1220 handle->url[strlen (handle->url) - 1] = '\0';
1221 handle->timeout_task =
1222 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1223 GNUNET_CONTAINER_DLL_insert (requests_head,
1224 requests_tail,
1225 handle);
1226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1227 if (GNUNET_NO ==
1228 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1229 {
1230 cleanup_handle (handle);
1231 return GNUNET_NO;
1232 }
1233
1234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1235 return GNUNET_YES;
1236}
1237
1238
1239/**
1240 * Entry point for the plugin.
1241 *
1242 * @param cls Config info
1243 * @return NULL on error, otherwise the plugin context
1244 */
1245void *
1246libgnunet_plugin_rest_escrow_init (void *cls)
1247{
1248 static struct Plugin plugin;
1249 struct GNUNET_REST_Plugin *api;
1250
1251 cfg = cls;
1252 if (NULL != plugin.cfg)
1253 return NULL; /* can only initialize once! */
1254 memset (&plugin, 0, sizeof(struct Plugin));
1255 plugin.cfg = cfg;
1256 api = GNUNET_new (struct GNUNET_REST_Plugin);
1257 api->cls = &plugin;
1258 api->name = GNUNET_REST_API_NS_ESCROW;
1259 api->process_request = &rest_process_request;
1260 GNUNET_asprintf (&allow_methods,
1261 "%s, %s, %s",
1262 MHD_HTTP_METHOD_GET,
1263 MHD_HTTP_METHOD_POST,
1264 MHD_HTTP_METHOD_OPTIONS);
1265 state = ID_REST_STATE_INIT;
1266 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
1267 escrow_handle = GNUNET_ESCROW_init (cfg);
1268
1269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Escrow REST API initialized\n"));
1270 return api;
1271}
1272
1273
1274/**
1275 * Exit point from the plugin.
1276 *
1277 * @param cls the plugin context (as returned by "init")
1278 * @return always NULL
1279 */
1280void *
1281libgnunet_plugin_rest_escrow_done (void *cls)
1282{
1283 struct GNUNET_REST_Plugin *api = cls;
1284 struct Plugin *plugin = api->cls;
1285 struct EgoEntry *ego_entry;
1286 struct EgoEntry *ego_tmp;
1287
1288 plugin->cfg = NULL;
1289 while (NULL != requests_head)
1290 cleanup_handle (requests_head);
1291 if (NULL != escrow_handle)
1292 GNUNET_ESCROW_fini (escrow_handle);
1293 if (NULL != identity_handle)
1294 GNUNET_IDENTITY_disconnect (identity_handle);
1295 for (ego_entry = ego_head; NULL != ego_entry;)
1296 {
1297 ego_tmp = ego_entry;
1298 ego_entry = ego_entry->next;
1299 GNUNET_free (ego_tmp->identifier);
1300 GNUNET_free (ego_tmp->keystring);
1301 GNUNET_free (ego_tmp);
1302 }
1303
1304 GNUNET_free (allow_methods);
1305 GNUNET_free (api);
1306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Escrow REST plugin is finished\n");
1307 return NULL;
1308}
1309
1310
1311/* end of plugin_rest_escrow.c */
diff --git a/src/escrow/test_gns_escrow.sh b/src/escrow/test_gns_escrow.sh
new file mode 100755
index 000000000..ea0d591dd
--- /dev/null
+++ b/src/escrow/test_gns_escrow.sh
@@ -0,0 +1,48 @@
1#!/bin/sh
2
3LOCATION=$(which gnunet-config)
4if [ -z $LOCATION ]
5then
6 LOCATION="gnunet-config"
7fi
8$LOCATION --version 1> /dev/null
9if test $? != 0
10then
11 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
12 exit 77
13fi
14
15rm -rf `gnunet-config -c test_escrow.conf -s PATHS -o GNUNET_HOME -f`
16
17which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
18
19gnunet-arm -s -c test_escrow.conf
20gnunet-identity -C testego -c test_escrow.conf
21ANCHOR=$(gnunet-escrow -m gns -P testego -u secret -c test_escrow.conf)
22if test $? != 0
23then
24 echo "GNS escrow failed!"
25 gnunet-arm -e -c test_escrow.conf
26 exit 1
27else
28 ANCHOR=$(echo $ANCHOR | awk 'NF>1{print $NF}')
29 echo "using anchor $ANCHOR"
30fi
31gnunet-escrow -m gns -V testego -a $ANCHOR -c test_escrow.conf
32if test $? != 0
33then
34 echo "GNS verification failed!"
35 gnunet-arm -e -c test_escrow.conf
36 exit 1
37fi
38gnunet-identity -D testego -c test_escrow.conf
39gnunet-escrow -G -a $ANCHOR -c test_escrow.conf
40if test $? != 0
41then
42 echo "GNS restore failed!"
43 gnunet-arm -e -c test_escrow.conf
44 exit 1
45fi
46gnunet-arm -e -c test_escrow.conf
47
48exit 0
diff --git a/src/escrow/test_plaintext_escrow.sh b/src/escrow/test_plaintext_escrow.sh
new file mode 100755
index 000000000..00072b1da
--- /dev/null
+++ b/src/escrow/test_plaintext_escrow.sh
@@ -0,0 +1,47 @@
1#!/bin/sh
2
3LOCATION=$(which gnunet-config)
4if [ -z $LOCATION ]
5then
6 LOCATION="gnunet-config"
7fi
8$LOCATION --version 1> /dev/null
9if test $? != 0
10then
11 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
12 exit 77
13fi
14
15rm -rf `gnunet-config -c test_escrow.conf -s PATHS -o GNUNET_HOME -f`
16
17which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
18
19gnunet-arm -s -c test_escrow.conf
20gnunet-identity -C testego -c test_escrow.conf
21ANCHOR=$(gnunet-escrow -m plaintext -P testego -c test_escrow.conf)
22if test $? != 0
23then
24 echo "Plaintext escrow failed!"
25 gnunet-arm -e -c test_escrow.conf
26 exit 1
27else
28 ANCHOR=$(echo $ANCHOR | awk 'NF>1{print $NF}')
29fi
30gnunet-escrow -m plaintext -V testego -a $ANCHOR -c test_escrow.conf
31if test $? != 0
32then
33 echo "Plaintext verification failed!"
34 gnunet-arm -e -c test_escrow.conf
35 exit 1
36fi
37gnunet-identity -D testego -c test_escrow.conf
38gnunet-escrow -G -a $ANCHOR -c test_escrow.conf
39if test $? != 0
40then
41 echo "Plaintext restore failed!"
42 gnunet-arm -e -c test_escrow.conf
43 exit 1
44fi
45gnunet-arm -e -c test_escrow.conf
46
47exit 0
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h
index 03fb16a43..085d7187f 100644
--- a/src/include/gnunet_crypto_lib.h
+++ b/src/include/gnunet_crypto_lib.h
@@ -1198,6 +1198,21 @@ GNUNET_CRYPTO_eddsa_public_key_to_string (
1198 1198
1199 1199
1200/** 1200/**
1201 * Convert a string representing a private key to a private key.
1202 *
1203 * @param enc encoded private key
1204 * @param enclen number of bytes in @a enc (without 0-terminator)
1205 * @param priv where to store the private key
1206 * @return #GNUNET_OK on success
1207 */
1208int
1209GNUNET_CRYPTO_ecdsa_private_key_from_string (
1210 const char *enc,
1211 size_t enclen,
1212 struct GNUNET_CRYPTO_EcdsaPrivateKey *pub);
1213
1214
1215/**
1201 * Convert a string representing a public key to a public key. 1216 * Convert a string representing a public key to a public key.
1202 * 1217 *
1203 * @param enc encoded public key 1218 * @param enc encoded public key
@@ -1215,7 +1230,7 @@ GNUNET_CRYPTO_ecdsa_public_key_from_string (
1215/** 1230/**
1216 * Convert a string representing a private key to a private key. 1231 * Convert a string representing a private key to a private key.
1217 * 1232 *
1218 * @param enc encoded public key 1233 * @param enc encoded private key
1219 * @param enclen number of bytes in @a enc (without 0-terminator) 1234 * @param enclen number of bytes in @a enc (without 0-terminator)
1220 * @param priv where to store the private key 1235 * @param priv where to store the private key
1221 * @return #GNUNET_OK on success 1236 * @return #GNUNET_OK on success
diff --git a/src/include/gnunet_escrow_lib.h b/src/include/gnunet_escrow_lib.h
new file mode 100644
index 000000000..546fdfeb9
--- /dev/null
+++ b/src/include/gnunet_escrow_lib.h
@@ -0,0 +1,437 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Johannes Späth
23 *
24 * @file
25 * Escrow definitions
26 *
27 * @defgroup escrow escrow component
28 * @{
29 */
30#ifndef GNUNET_ESCROW_LIB_H
31#define GNUNET_ESCROW_LIB_H
32
33#ifdef __cplusplus
34extern "C" {
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "gnunet_util_lib.h"
41#include "gnunet_identity_service.h"
42
43
44/**
45 * Enum for the different key escrow methods
46 */
47enum GNUNET_ESCROW_Key_Escrow_Method
48{
49 GNUNET_ESCROW_KEY_NONE, // error value
50 GNUNET_ESCROW_KEY_PLAINTEXT,
51 GNUNET_ESCROW_KEY_GNS,
52 GNUNET_ESCROW_KEY_ANASTASIS
53};
54
55
56/**
57 * Enum for the different verification results
58 */
59enum GNUNET_ESCROW_Verification_Result
60{
61 GNUNET_ESCROW_VALID,
62 GNUNET_ESCROW_INVALID,
63 GNUNET_ESCROW_SHARES_MISSING
64};
65
66
67/**
68 * Struct for the escrow anchor
69 */
70struct GNUNET_ESCROW_Anchor
71{
72 /**
73 * The escrow method.
74 */
75 enum GNUNET_ESCROW_Key_Escrow_Method method;
76
77 /**
78 * The name of the ego that was put in escrow.
79 */
80 const char *egoName;
81
82 /**
83 * The size of the anchor data.
84 */
85 uint32_t size;
86};
87
88
89/**
90 * Struct for the escrow status
91 */
92struct GNUNET_ESCROW_Status
93{
94 /**
95 * The time of the last successful verification.
96 */
97 struct GNUNET_TIME_Absolute last_successful_verification_time;
98
99 /**
100 * The time of the next recommended verification.
101 */
102 struct GNUNET_TIME_Absolute next_recommended_verification_time;
103
104 /**
105 * The escrow method used for the last escrow of the identity,
106 * GNUNET_ESCROW_KEY_NONE if no escrow has been performed.
107 */
108 enum GNUNET_ESCROW_Key_Escrow_Method last_method;
109};
110
111
112/**
113 * Function called after the initialization of the identity service.
114 * Passed via cls to the callback of GNUNET_IDENTITY_connect
115 */
116typedef void (*GNUNET_ESCROW_IdentityInitContinuation) ();
117
118/**
119 * Function called after the creation of an ego in case that happened
120 * because of an escrow GET operation.
121 */
122typedef void (*GNUNET_ESCROW_EgoCreateContinuation) (
123 struct GNUNET_IDENTITY_Ego *ego);
124
125/**
126 * Continuation for PUT operations.
127 *
128 * @param cls closure
129 * @param anchor the escrow anchor needed to get the data back
130 * @param emsg error message, NULL on success
131 */
132typedef void (*GNUNET_ESCROW_AnchorContinuation) (
133 void *cls,
134 struct GNUNET_ESCROW_Anchor *anchor,
135 const char *emsg);
136
137/**
138 * Continuation for a GET operation.
139 *
140 * @param cls closure
141 * @param ego a new identity ego restored from the escrow
142 * @param emsg error message, NULL on success
143 */
144typedef void (*GNUNET_ESCROW_EgoContinuation) (
145 void *cls,
146 struct GNUNET_IDENTITY_Ego *ego,
147 const char *emsg);
148
149/**
150 * Continuation for a VERIFY operation.
151 *
152 * @param cls closure
153 * @param verificationResult the result of the verification, i.e.
154 * GNUNET_ESCROW_VALID if the escrow could successfully by restored,
155 * GNUNET_ESCROW_SHARES_MISSING if it could be restored, but some of
156 * the shares are missing
157 * GNUNET_ESCROW_INVALID otherwise
158 * @param emsg error message, NULL on success
159 */
160typedef void (*GNUNET_ESCROW_VerifyContinuation) (
161 void *cls,
162 int verificationResult,
163 const char *emsg);
164
165
166/**
167 * Handle for the escrow component.
168 */
169struct GNUNET_ESCROW_Handle
170{
171 /**
172 * Configuration to use.
173 */
174 struct GNUNET_CONFIGURATION_Handle *cfg;
175
176 /**
177 * Head of active operations.
178 */
179 struct GNUNET_ESCROW_Operation *op_head;
180
181 /**
182 * Tail of active operations.
183 */
184 struct GNUNET_ESCROW_Operation *op_tail;
185
186 /**
187 * The last operation id used for an ESCROW operation.
188 */
189 uint32_t last_op_id_used;
190};
191
192
193/**
194 * Handle for an operation with the escrow component.
195 */
196struct GNUNET_ESCROW_Operation
197{
198 /**
199 * Main escrow handle.
200 */
201 struct GNUNET_ESCROW_Handle *h;
202
203 /**
204 * ID of the operation.
205 */
206 uint32_t id;
207
208 /**
209 * We keep operations in a DLL.
210 */
211 struct GNUNET_ESCROW_Operation *next;
212
213 /**
214 * We keep operations in a DLL.
215 */
216 struct GNUNET_ESCROW_Operation *prev;
217
218 /**
219 * The used escrow method.
220 */
221 enum GNUNET_ESCROW_Key_Escrow_Method method;
222
223 /**
224 * The respective plugin operation
225 */
226 struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
227
228 /**
229 * The ego.
230 */
231 const struct GNUNET_IDENTITY_Ego *ego;
232
233 /**
234 * The verification result.
235 */
236 enum GNUNET_ESCROW_Verification_Result verification_result;
237
238 /**
239 * Continuation for a PUT operation.
240 */
241 GNUNET_ESCROW_AnchorContinuation cb_put;
242
243 /**
244 * Continuation for a GET operation.
245 */
246 GNUNET_ESCROW_EgoContinuation cb_get;
247
248 /**
249 * Continuation for a VERIFY operation.
250 */
251 GNUNET_ESCROW_VerifyContinuation cb_verify;
252
253 /**
254 * Closure for the callback
255 */
256 void *cb_cls;
257};
258
259
260/**
261 * Initialize the escrow component.
262 *
263 * @param cfg the configuration to use
264 *
265 * @return handle to use
266 */
267struct GNUNET_ESCROW_Handle *
268GNUNET_ESCROW_init (
269 const struct GNUNET_CONFIGURATION_Handle *cfg);
270
271
272/**
273 * Unload all loaded plugins on destruction.
274 *
275 * @param h the escrow handle
276 */
277void
278GNUNET_ESCROW_fini (
279 struct GNUNET_ESCROW_Handle *h);
280
281
282/**
283 * Put some data in escrow using the specified escrow method
284 *
285 * @param h the handle for the escrow component
286 * @param ego the identity ego to put in escrow
287 * @param userSecret the user secret (e.g. for derivation of escrow identities)
288 * for GNS escrow, this has to be UNIQUE in the whole network!
289 * @param method the escrow method to use
290 * @param cb function to call with the escrow anchor on completion
291 * @param cb_cls closure for @a cb
292 *
293 * @return handle to abort the operation
294 */
295struct GNUNET_ESCROW_Operation *
296GNUNET_ESCROW_put (
297 struct GNUNET_ESCROW_Handle *h,
298 struct GNUNET_IDENTITY_Ego *ego,
299 const char *userSecret,
300 enum GNUNET_ESCROW_Key_Escrow_Method method,
301 GNUNET_ESCROW_AnchorContinuation cb,
302 void *cb_cls);
303
304
305/**
306 * Get the escrowed data back
307 *
308 * @param h the handle for the escrow component
309 * @param anchor the escrow anchor returned by the GNUNET_ESCROW_put method
310 * @param cb function to call with the restored ego on completion
311 * @param cb_cls closure for @a cb
312 *
313 * @return handle to abort the operation
314 */
315struct GNUNET_ESCROW_Operation *
316GNUNET_ESCROW_get (
317 struct GNUNET_ESCROW_Handle *h,
318 const struct GNUNET_ESCROW_Anchor *anchor,
319 GNUNET_ESCROW_EgoContinuation cb,
320 void *cb_cls);
321
322
323/**
324 * Verify the escrowed data
325 *
326 * @param h the handle for the escrow component
327 * @param ego the identity ego that was put into escrow
328 * @param anchor the escrow anchor returned by the GNUNET_ESCROW_put method
329 * @param method the escrow method to use
330 * @param cb function to call with the verification result on completion
331 * @param cb_cls closure for @a cb
332 *
333 * @return handle to abort the operation
334 */
335struct GNUNET_ESCROW_Operation *
336GNUNET_ESCROW_verify (
337 struct GNUNET_ESCROW_Handle *h,
338 struct GNUNET_IDENTITY_Ego *ego,
339 const struct GNUNET_ESCROW_Anchor *anchor,
340 enum GNUNET_ESCROW_Key_Escrow_Method method,
341 GNUNET_ESCROW_VerifyContinuation cb,
342 void *cb_cls);
343
344
345/**
346 * Get the status of an escrow, i.e.
347 * -> when the last escrow was
348 * -> when the next escrow is recommended
349 *
350 * @param h the handle for the escrow component
351 * @param ego the identity ego of which the escrow status has to be determined
352 * @param method the escrow method to use
353 *
354 * @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
355 */
356struct GNUNET_ESCROW_Status *
357GNUNET_ESCROW_get_status (
358 struct GNUNET_ESCROW_Handle *h,
359 struct GNUNET_IDENTITY_Ego *ego,
360 enum GNUNET_ESCROW_Key_Escrow_Method method);
361
362
363/**
364 * Deserialize an escrow anchor string (e.g. from command line) into a
365 * GNUNET_ESCROW_Anchor struct
366 * The anchor string is expected to have the following form:
367 * <method>:<egoName>:<anchorData>
368 * with <method>, <egoName> and <anchorData> being URL-encoded
369 *
370 * @param anchorString the encoded escrow anchor string
371 *
372 * @return the deserialized data packed into a GNUNET_ESCROW_Anchor struct,
373 * NULL if we failed to parse the string
374 */
375struct GNUNET_ESCROW_Anchor *
376GNUNET_ESCROW_anchor_string_to_data (
377 const char *anchorString);
378
379
380/**
381 * Serialize an escrow anchor (struct GNUNET_ESCROW_Anchor) into a string
382 *
383 * @param anchor the escrow anchor struct
384 *
385 * @return the encoded escrow anchor string
386 */
387char *
388GNUNET_ESCROW_anchor_data_to_string (
389 const struct GNUNET_ESCROW_Anchor *anchor);
390
391
392/**
393 * Convert a method name string to the respective enum number
394 *
395 * @param methodString the method name string
396 *
397 * @return the enum number
398 */
399enum GNUNET_ESCROW_Key_Escrow_Method
400GNUNET_ESCROW_method_string_to_number (const char *methodString);
401
402
403/**
404 * Convert a method enum number to the respective method string
405 *
406 * @param method the method enum number
407 *
408 * @return the method string
409 */
410const char *
411GNUNET_ESCROW_method_number_to_string (enum GNUNET_ESCROW_Key_Escrow_Method method);
412
413
414/**
415 * Cancel an escrow operation. Note that the operation MAY still
416 * be executed; this merely cancels the continuation.
417 *
418 * @param op operation to cancel
419 */
420void
421GNUNET_ESCROW_cancel (struct GNUNET_ESCROW_Operation *op);
422
423
424#if 0 /* keep Emacsens' auto-indent happy */
425{
426#endif
427#ifdef __cplusplus
428}
429#endif
430
431
432/* ifndef GNUNET_ESCROW_LIB_H */
433#endif
434
435/** @} */ /* end of group escrow */
436
437/* end of gnunet_escrow_lib.h */
diff --git a/src/include/gnunet_escrow_plugin.h b/src/include/gnunet_escrow_plugin.h
new file mode 100644
index 000000000..ec0bbdcdb
--- /dev/null
+++ b/src/include/gnunet_escrow_plugin.h
@@ -0,0 +1,171 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Johannes Späth
23 *
24 * @file
25 * Plugin API for escrow methods
26 *
27 * @defgroup escrow-plugin escrow plugin API for escrow methods
28 * @{
29 */
30#ifndef GNUNET_ESCROW_PLUGIN_H
31#define GNUNET_ESCROW_PLUGIN_H
32
33#include "gnunet_util_lib.h"
34#include "gnunet_escrow_lib.h"
35#include "gnunet_identity_service.h"
36#include "gnunet_scheduler_lib.h"
37
38#ifdef __cplusplus
39extern "C" {
40#if 0 /* keep Emacsens' auto-indent happy */
41}
42#endif
43#endif
44
45
46/**
47 * Function called to start the escrow of the key
48 *
49 * @param h the handle for the escrow component
50 * @param ego the identity ego containing the private key
51 * @param userSecret the user secret (e.g. for derivation of escrow identities)
52 * for GNS escrow, this has to be UNIQUE in the whole network!
53 * @param cb the function called upon completion
54 * @param op_id unique ID of the respective ESCROW_Operation
55 *
56 * @return a wrapper for the plugin operation
57 */
58typedef struct ESCROW_PluginOperationWrapper *(*GNUNET_ESCROW_StartKeyEscrowFunction) (
59 struct GNUNET_ESCROW_Handle *h,
60 struct GNUNET_IDENTITY_Ego *ego,
61 const char *userSecret,
62 GNUNET_SCHEDULER_TaskCallback cb,
63 uint32_t op_id);
64
65/**
66 * Function called to verify the escrow of the key
67 *
68 * @param h the handle for the escrow component
69 * @param ego the identity ego containing the private key
70 * @param anchor the escrow anchor needed to restore the key
71 * @param cb the function called upon completion
72 * @param op_id unique ID of the respective ESCROW_Operation
73 *
74 * @return a wrapper for the plugin operation
75 */
76typedef struct ESCROW_PluginOperationWrapper *(*GNUNET_ESCROW_VerifyKeyEscrowFunction) (
77 struct GNUNET_ESCROW_Handle *h,
78 struct GNUNET_IDENTITY_Ego *ego,
79 const struct GNUNET_ESCROW_Anchor *anchor,
80 GNUNET_SCHEDULER_TaskCallback cb,
81 uint32_t op_id);
82
83/**
84 * Function called to restore a key from an escrow
85 *
86 * @param h the handle for the escrow component
87 * @param anchor the escrow anchor needed to restore the key
88 * @param cb the function called upon completion
89 * @param op_id unique ID of the respective ESCROW_Operation
90 *
91 * @return a wrapper for the plugin operation
92 */
93typedef struct ESCROW_PluginOperationWrapper *(*GNUNET_ESCROW_RestoreKeyFunction) (
94 struct GNUNET_ESCROW_Handle *h,
95 const struct GNUNET_ESCROW_Anchor *anchor,
96 GNUNET_SCHEDULER_TaskCallback cb,
97 uint32_t op_id);
98
99
100/**
101 * Function called to get the status of an escrow, i.e.
102 * -> when the last successful escrow was
103 * -> when the next recommended escrow is
104 *
105 * @param h the handle for the escrow component
106 * @param ego the identity ego of which the status has to be obtained
107 *
108 * @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
109 */
110typedef struct GNUNET_ESCROW_Status *(*GNUNET_ESCROW_GetEscrowStatusFunction) (
111 struct GNUNET_ESCROW_Handle *h,
112 struct GNUNET_IDENTITY_Ego *ego);
113
114
115/**
116 * Function called to cancel a plugin operation
117 *
118 * @param plugin_op_wrap plugin operation wrapper containing the plugin operation
119 */
120typedef void (*GNUNET_ESCROW_CancelPluginOperationFunction) (
121 struct ESCROW_PluginOperationWrapper *plugin_op_wrap);
122
123
124/**
125 * Each plugin is required to return a pointer to a struct of this
126 * type as the return value from its entry point.
127 */
128struct GNUNET_ESCROW_KeyPluginFunctions
129{
130 /**
131 * Closure for all of the callbacks.
132 */
133 void *cls;
134
135 /**
136 * Start key escrow
137 */
138 GNUNET_ESCROW_StartKeyEscrowFunction start_key_escrow;
139
140 /**
141 * Verify key escrow
142 */
143 GNUNET_ESCROW_VerifyKeyEscrowFunction verify_key_escrow;
144
145 /**
146 * Restore key escrow
147 */
148 GNUNET_ESCROW_RestoreKeyFunction restore_key;
149
150 /**
151 * Get the status of an escrow
152 */
153 GNUNET_ESCROW_GetEscrowStatusFunction get_status;
154
155 /**
156 * Cancel plugin operation
157 */
158 GNUNET_ESCROW_CancelPluginOperationFunction cancel_plugin_operation;
159};
160
161
162#if 0 /* keep Emacsens' auto-indent happy */
163{
164#endif
165#ifdef __cplusplus
166}
167#endif
168
169#endif
170
171/** @} */ /* end of group */
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h
index 960203fb1..db524ec5b 100644
--- a/src/include/gnunet_gnsrecord_lib.h
+++ b/src/include/gnunet_gnsrecord_lib.h
@@ -151,6 +151,11 @@ extern "C" {
151 */ 151 */
152#define GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION 65555 152#define GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION 65555
153 153
154/**
155 * Record type for an escrow key share (escrow component)
156 */
157#define GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE 65556
158
154 159
155/** 160/**
156 * Flags that can be set for a record. 161 * Flags that can be set for a record.
diff --git a/src/include/gnunet_reclaim_plugin.h b/src/include/gnunet_reclaim_plugin.h
index 2ba8fc8a0..ed6663bb5 100644
--- a/src/include/gnunet_reclaim_plugin.h
+++ b/src/include/gnunet_reclaim_plugin.h
@@ -32,6 +32,7 @@
32 32
33#include "gnunet_util_lib.h" 33#include "gnunet_util_lib.h"
34#include "gnunet_reclaim_lib.h" 34#include "gnunet_reclaim_lib.h"
35#include "gnunet_identity_service.h"
35 36
36#ifdef __cplusplus 37#ifdef __cplusplus
37extern "C" { 38extern "C" {
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index 019dbe94e..ef52d9588 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -388,6 +388,39 @@ GNUNET_CRYPTO_ecdsa_public_key_from_string (
388 388
389 389
390/** 390/**
391 * Convert a string representing a private key to a private key.
392 *
393 * @param enc encoded private key
394 * @param enclen number of bytes in @a enc (without 0-terminator)
395 * @param priv where to store the private key
396 * @return #GNUNET_OK on success
397 */
398int
399GNUNET_CRYPTO_ecdsa_private_key_from_string (
400 const char *enc,
401 size_t enclen,
402 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
403{
404 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
405
406 if (keylen % 5 > 0)
407 keylen += 5 - keylen % 5;
408 keylen /= 5;
409 if (enclen != keylen)
410 return GNUNET_SYSERR;
411
412 if (GNUNET_OK !=
413 GNUNET_STRINGS_string_to_data (enc,
414 enclen,
415 priv,
416 sizeof(
417 struct GNUNET_CRYPTO_EcdsaPrivateKey)))
418 return GNUNET_SYSERR;
419 return GNUNET_OK;
420}
421
422
423/**
391 * Convert a string representing a public key to a public key. 424 * Convert a string representing a public key to a public key.
392 * 425 *
393 * @param enc encoded public key 426 * @param enc encoded public key
@@ -423,7 +456,7 @@ GNUNET_CRYPTO_eddsa_public_key_from_string (
423/** 456/**
424 * Convert a string representing a private key to a private key. 457 * Convert a string representing a private key to a private key.
425 * 458 *
426 * @param enc encoded public key 459 * @param enc encoded private key
427 * @param enclen number of bytes in @a enc (without 0-terminator) 460 * @param enclen number of bytes in @a enc (without 0-terminator)
428 * @param priv where to store the private key 461 * @param priv where to store the private key
429 * @return #GNUNET_OK on success 462 * @return #GNUNET_OK on success
diff --git a/src/util/strings.c b/src/util/strings.c
index 9d6f4039e..014302c01 100644
--- a/src/util/strings.c
+++ b/src/util/strings.c
@@ -2148,7 +2148,7 @@ GNUNET_STRINGS_urlencode (const char *data, size_t len, char **out)
2148 struct GNUNET_Buffer buf = { 0 }; 2148 struct GNUNET_Buffer buf = { 0 };
2149 const uint8_t *i8 = (uint8_t *) data; 2149 const uint8_t *i8 = (uint8_t *) data;
2150 2150
2151 while (0 != *i8) 2151 while ((i8 - (uint8_t *) data) < len && 0 != *i8)
2152 { 2152 {
2153 if (0 == (0x80 & *i8)) 2153 if (0 == (0x80 & *i8))
2154 { 2154 {