aboutsummaryrefslogtreecommitdiff
path: root/src/lib/util/crypto_ecc_setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/crypto_ecc_setup.c')
-rw-r--r--src/lib/util/crypto_ecc_setup.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/src/lib/util/crypto_ecc_setup.c b/src/lib/util/crypto_ecc_setup.c
new file mode 100644
index 000000000..e07d1e448
--- /dev/null
+++ b/src/lib/util/crypto_ecc_setup.c
@@ -0,0 +1,315 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015, 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 util/crypto_ecc_setup.c
23 * @brief helper function for easy EdDSA key setup
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include <gcrypt.h>
29#include "gnunet_util_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
32
33#define LOG_STRERROR(kind, syscall) \
34 GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
38
39/**
40 * Log an error message at log-level 'level' that indicates
41 * a failure of the command 'cmd' with the message given
42 * by gcry_strerror(rc).
43 */
44#define LOG_GCRY(level, cmd, rc) \
45 do \
46 { \
47 LOG (level, \
48 _ ("`%s' failed at %s:%d with error: %s\n"), \
49 cmd, \
50 __FILE__, \
51 __LINE__, \
52 gcry_strerror (rc)); \
53 } while (0)
54
55
56/**
57 * Read file to @a buf. Fails if the file does not exist or
58 * does not have precisely @a buf_size bytes.
59 *
60 * @param filename file to read
61 * @param[out] buf where to write the file contents
62 * @param buf_size number of bytes in @a buf
63 * @return #GNUNET_OK on success
64 */
65static enum GNUNET_GenericReturnValue
66read_from_file (const char *filename,
67 void *buf,
68 size_t buf_size)
69{
70 int fd;
71 struct stat sb;
72
73 fd = open (filename,
74 O_RDONLY);
75 if (-1 == fd)
76 {
77 memset (buf,
78 0,
79 buf_size);
80 return GNUNET_SYSERR;
81 }
82 if (0 != fstat (fd,
83 &sb))
84 {
85 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
86 "stat",
87 filename);
88 GNUNET_assert (0 == close (fd));
89 memset (buf,
90 0,
91 buf_size);
92 return GNUNET_SYSERR;
93 }
94 if (sb.st_size != buf_size)
95 {
96 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
97 "File `%s' has wrong size (%llu), expected %llu bytes\n",
98 filename,
99 (unsigned long long) sb.st_size,
100 (unsigned long long) buf_size);
101 GNUNET_assert (0 == close (fd));
102 memset (buf,
103 0,
104 buf_size);
105 return GNUNET_SYSERR;
106 }
107 if (buf_size !=
108 read (fd,
109 buf,
110 buf_size))
111 {
112 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
113 "read",
114 filename);
115 GNUNET_assert (0 == close (fd));
116 memset (buf,
117 0,
118 buf_size);
119 return GNUNET_SYSERR;
120 }
121 GNUNET_assert (0 == close (fd));
122 return GNUNET_OK;
123}
124
125
126/**
127 * @ingroup crypto
128 * @brief Create a new private key by reading it from a file.
129 *
130 * If the files does not exist and @a do_create is set, creates a new key and
131 * write it to the file.
132 *
133 * If the contents of the file are invalid, an error is returned.
134 *
135 * @param filename name of file to use to store the key
136 * @param do_create should a file be created?
137 * @param[out] pkey set to the private key from @a filename on success
138 * @return - #GNUNET_OK on success,
139 * - #GNUNET_NO if @a do_create was set but we found an existing file,
140 * - #GNUNET_SYSERR on failure _or_ if the file didn't exist and @a
141 * do_create was not set
142 */
143enum GNUNET_GenericReturnValue
144GNUNET_CRYPTO_eddsa_key_from_file (const char *filename,
145 int do_create,
146 struct GNUNET_CRYPTO_EddsaPrivateKey *pkey)
147{
148 enum GNUNET_GenericReturnValue ret;
149
150 if (GNUNET_OK ==
151 read_from_file (filename,
152 pkey,
153 sizeof (*pkey)))
154 {
155 /* file existed, report that we didn't create it... */
156 return (do_create) ? GNUNET_NO : GNUNET_OK;
157 }
158 else if (! do_create)
159 {
160 return GNUNET_SYSERR;
161 }
162
163 GNUNET_CRYPTO_eddsa_key_create (pkey);
164 ret = GNUNET_DISK_fn_write (filename,
165 pkey,
166 sizeof (*pkey),
167 GNUNET_DISK_PERM_USER_READ);
168 if ( (GNUNET_OK == ret) ||
169 (GNUNET_SYSERR == ret) )
170 return ret;
171 /* maybe another process succeeded in the meantime, try reading one more time */
172 if (GNUNET_OK ==
173 read_from_file (filename,
174 pkey,
175 sizeof (*pkey)))
176 {
177 /* file existed, report that *we* didn't create it... */
178 return GNUNET_NO;
179 }
180 /* give up */
181 return GNUNET_SYSERR;
182}
183
184
185/**
186 * @ingroup crypto
187 * @brief Create a new private key by reading it from a file.
188 *
189 * If the files does not exist and @a do_create is set, creates a new key and
190 * write it to the file.
191 *
192 * If the contents of the file are invalid, an error is returned.
193 *
194 * @param filename name of file to use to store the key
195 * @param do_create should a file be created?
196 * @param[out] pkey set to the private key from @a filename on success
197 * @return #GNUNET_OK on success, #GNUNET_NO if @a do_create was set but
198 * we found an existing file, #GNUNET_SYSERR on failure
199 */
200enum GNUNET_GenericReturnValue
201GNUNET_CRYPTO_ecdsa_key_from_file (const char *filename,
202 int do_create,
203 struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey)
204{
205 if (GNUNET_OK ==
206 read_from_file (filename,
207 pkey,
208 sizeof (*pkey)))
209 {
210 /* file existed, report that we didn't create it... */
211 return (do_create) ? GNUNET_NO : GNUNET_OK;
212 }
213 else if (! do_create)
214 {
215 return GNUNET_SYSERR;
216 }
217 GNUNET_CRYPTO_ecdsa_key_create (pkey);
218 if (GNUNET_OK ==
219 GNUNET_DISK_fn_write (filename,
220 pkey,
221 sizeof (*pkey),
222 GNUNET_DISK_PERM_USER_READ))
223 return GNUNET_OK;
224 /* maybe another process succeeded in the meantime, try reading one more time */
225 if (GNUNET_OK ==
226 read_from_file (filename,
227 pkey,
228 sizeof (*pkey)))
229 {
230 /* file existed, report that *we* didn't create it... */
231 return GNUNET_NO;
232 }
233 /* give up */
234 return GNUNET_SYSERR;
235}
236
237
238/**
239 * Create a new private key by reading our peer's key from
240 * the file specified in the configuration.
241 *
242 * @param cfg the configuration to use
243 * @return new private key, NULL on error (for example,
244 * permission denied)
245 */
246struct GNUNET_CRYPTO_EddsaPrivateKey *
247GNUNET_CRYPTO_eddsa_key_create_from_configuration (
248 const struct GNUNET_CONFIGURATION_Handle *cfg)
249{
250 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
251 char *fn;
252
253 if (GNUNET_OK !=
254 GNUNET_CONFIGURATION_get_value_filename (cfg,
255 "PEER",
256 "PRIVATE_KEY",
257 &fn))
258 return NULL;
259 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
260 if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_key_from_file (fn,
261 GNUNET_YES,
262 priv))
263 {
264 GNUNET_free (fn);
265 GNUNET_free (priv);
266 return NULL;
267 }
268 GNUNET_free (fn);
269 return priv;
270}
271
272
273enum GNUNET_GenericReturnValue
274GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
275 struct GNUNET_PeerIdentity *dst)
276{
277 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
278
279 if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
280 {
281 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
282 _ ("Could not load peer's private key\n"));
283 return GNUNET_SYSERR;
284 }
285 GNUNET_CRYPTO_eddsa_key_get_public (priv,
286 &dst->public_key);
287 GNUNET_free (priv);
288 return GNUNET_OK;
289}
290
291
292/**
293 * Setup a key file for a peer given the name of the
294 * configuration file (!). This function is used so that
295 * at a later point code can be certain that reading a
296 * key is fast (for example in time-dependent testcases).
297 *
298 * @param cfg_name name of the configuration file to use
299 */
300void
301GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
302{
303 struct GNUNET_CONFIGURATION_Handle *cfg;
304 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
305
306 cfg = GNUNET_CONFIGURATION_create ();
307 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
308 priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
309 if (NULL != priv)
310 GNUNET_free (priv);
311 GNUNET_CONFIGURATION_destroy (cfg);
312}
313
314
315/* end of crypto_ecc_setup.c */