Reimplement the KEEPALIVE status message.
[pwmd.git] / src / convert.c
blob1272733e71021d5af2e568d1488ac741313a902f
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include <zlib.h>
28 #include "pwmd-error.h"
29 #include <gcrypt.h>
30 #include "convert.h"
31 #include "xml.h"
32 #include "mem.h"
33 #include "util-misc.h"
34 #include "cache.h"
35 #include "crypto.h"
36 #include "pinentry.h"
38 #ifndef _
39 #include "gettext.h"
40 #define _(msgid) gettext(msgid)
41 #endif
43 #define KEYSIZE 32
45 typedef struct
47 uint8_t magic[5];
48 uint16_t version;
49 uint64_t iter;
50 uint64_t flags;
51 uint8_t iv[16];
52 uint8_t salt[8];
53 } v2_file_header_t;
55 struct gz_s
57 z_stream z;
58 void *out;
59 int done;
62 static unsigned char crypto_magic[5] = "\177PWMD";
64 static void
65 gz_cleanup (void *arg)
67 struct gz_s **gz = (struct gz_s **) arg;
69 if (!gz)
70 return;
72 if (!(*gz)->done && (*gz)->out)
73 gcry_free ((*gz)->out);
75 if ((*gz)->z.zalloc)
76 inflateEnd (&(*gz)->z);
78 xfree (*gz);
79 *gz = NULL;
82 static void *
83 z_alloc (void *data, unsigned items, unsigned size)
85 return gcry_calloc (items, size);
88 static void
89 z_free (void *data, void *p)
91 gcry_free (p);
94 #define ZLIB_BUFSIZE 65536
96 static gpg_error_t
97 decompress (void *in, unsigned long insize, void * *out,
98 unsigned long *outsize)
100 struct gz_s *gz;
101 gz_header h;
102 char buf[17];
103 gpg_error_t rc;
104 int zrc;
106 gz = xcalloc (1, sizeof (struct gz_s));
107 if (!gz)
108 return GPG_ERR_ENOMEM;
110 gz->z.zalloc = z_alloc;
111 gz->z.zfree = z_free;
112 gz->z.next_in = in;
113 gz->z.avail_in = (uInt) insize;
114 gz->z.avail_out = ZLIB_BUFSIZE;
115 gz->z.next_out = gz->out = gcry_malloc (ZLIB_BUFSIZE);
116 if (!gz->out)
118 gz_cleanup (&gz);
119 return GPG_ERR_ENOMEM;
122 zrc = inflateInit2 (&gz->z, 47);
123 if (zrc != Z_OK)
125 gz_cleanup (&gz);
126 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
129 memset (&h, 0, sizeof (gz_header));
130 h.comment = (unsigned char *) buf;
131 h.comm_max = sizeof (buf);
132 zrc = inflateGetHeader (&gz->z, &h);
133 if (zrc != Z_OK)
135 gz_cleanup (&gz);
136 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
139 zrc = inflate (&gz->z, Z_BLOCK);
140 if (zrc != Z_OK)
142 gz_cleanup (&gz);
143 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
146 if (h.comment)
147 insize = strtoul ((char *) h.comment, NULL, 10);
151 void *p;
153 zrc = inflate (&gz->z, Z_FINISH);
154 switch (zrc)
156 case Z_OK:
157 break;
158 case Z_BUF_ERROR:
159 if (!gz->z.avail_out)
161 p = gcry_realloc (gz->out, gz->z.total_out + ZLIB_BUFSIZE);
162 if (!p)
164 rc = GPG_ERR_ENOMEM;
165 goto fail;
168 gz->out = p;
169 gz->z.next_out = (unsigned char *) gz->out + gz->z.total_out;
170 gz->z.avail_out = ZLIB_BUFSIZE;
172 else
174 rc = GPG_ERR_COMPR_ALGO;
175 goto fail;
178 break;
179 case Z_STREAM_END:
180 break;
181 default:
182 rc = GPG_ERR_COMPR_ALGO;
183 goto fail;
184 break;
187 while (zrc != Z_STREAM_END);
189 *out = gz->out;
190 *outsize = gz->z.total_out;
191 gz->done = 1;
192 gz_cleanup (&gz);
193 return 0;
195 fail:
196 gz_cleanup (&gz);
197 return rc;
200 static gpg_error_t
201 decrypt (v2_file_header_t * fh, unsigned char *key,
202 unsigned char **ciphertext, size_t datalen, void * *result,
203 size_t * result_len)
205 gpg_error_t rc;
206 size_t blocksize, keysize, len;
207 int algo = cipher_to_gcrypt (fh->flags);
208 gcry_cipher_hd_t gh = NULL;
209 uint64_t iter = 0ULL;
210 unsigned char *data = *ciphertext;
212 *result = NULL;
213 *result_len = 0;
215 /* No encryption iterations. This is a plain (gzipped) file. */
216 if (!fh->iter)
217 goto decompress;
219 if (algo == -1)
220 return GPG_ERR_CIPHER_ALGO;
222 rc = gcry_cipher_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, NULL);
223 if (rc)
224 return rc;
226 rc = gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &keysize);
227 if (rc)
228 return rc;
230 rc = gcry_cipher_algo_info (algo, GCRYCTL_GET_BLKLEN, NULL, &blocksize);
231 if (rc)
232 return rc;
234 rc = gcry_cipher_open (&gh, algo, GCRY_CIPHER_MODE_CBC, 0);
235 if (rc)
236 return rc;
238 if ((rc = gcry_cipher_setiv (gh, fh->iv, blocksize)))
239 goto fail;
241 if ((rc = gcry_cipher_setkey (gh, key, keysize)))
242 goto fail;
244 rc = gcry_cipher_decrypt (gh, data, datalen, NULL, 0);
245 if (rc)
246 goto fail;
248 key[0] ^= 1;
249 if ((rc = gcry_cipher_setkey (gh, key, keysize)))
250 goto fail;
252 while (++iter < fh->iter)
254 if ((rc = gcry_cipher_setiv (gh, fh->iv, blocksize)))
255 goto fail;
257 rc = gcry_cipher_decrypt (gh, data, datalen, NULL, 0);
258 if (rc)
259 goto fail;
262 decompress:
263 len = 0;
264 if (fh->version >= 0x218 && fh->iter > 0ULL)
266 if (memcmp (data, crypto_magic, sizeof (crypto_magic)))
268 rc = GPG_ERR_BAD_PASSPHRASE;
269 goto fail;
272 len = sizeof (crypto_magic);
275 rc =
276 decompress (data + len, datalen - len, result,
277 (unsigned long *) result_len);
278 if (rc)
280 if (fh->version < 0x218 && rc == GPG_ERR_COMPR_ALGO)
281 rc = GPG_ERR_BAD_PASSPHRASE;
282 goto fail;
285 if (strncasecmp ((char *) *result, "<?xml ", 6) != 0)
287 gcry_free (*result);
288 *result = NULL;
289 *result_len = 0;
290 rc = GPG_ERR_BAD_PASSPHRASE;
291 goto fail;
294 fail:
295 if (gh)
296 gcry_cipher_close (gh);
298 return rc;
301 gpg_error_t
302 read_v2_datafile (const char *filename, const char *keyfile,
303 void * *result, size_t * result_len, uint16_t * ver,
304 int *algo)
306 gpg_error_t rc;
307 int fd;
308 v2_file_header_t fh;
309 size_t len, passphraselen, datalen;
310 #ifdef WITH_AGENT
311 struct agent_s *agent = NULL;
312 #endif
313 char *passphrase = NULL;
314 unsigned char *data = NULL;
315 struct stat st;
316 unsigned char *key = NULL;
317 FILE *fp;
319 if (stat (filename, &st) == -1)
320 return gpg_error_from_syserror ();
322 fd = open (filename, O_RDONLY);
323 if (fd == -1)
324 return gpg_error_from_syserror ();
326 len = read (fd, &fh, sizeof (fh) - 8);
327 if (len != sizeof (fh) - 8)
329 rc = GPG_ERR_INV_LENGTH;
330 goto fail;
333 if (fh.version >= 0x221)
335 len = read (fd, &fh.salt, 8);
336 if (len != 8)
338 rc = GPG_ERR_INV_LENGTH;
339 goto fail;
343 *ver = fh.version;
344 *algo = cipher_to_gcrypt (fh.flags);
346 #ifdef WITH_AGENT
347 if (use_agent && !keyfile && fh.iter > 0)
349 char *desc;
351 rc = agent_init (&agent);
352 if (rc)
353 goto fail;
355 desc = plus_escape (_
356 ("A passphrase is required to decrypt the file for "
357 "converting. Please enter the passphrase below."));
358 rc = agent_set_pinentry_options (agent);
359 if (rc)
360 goto fail;
362 assuan_begin_confidential (agent->ctx);
363 rc = send_to_agent (agent, &passphrase, &passphraselen,
364 "GET_PASSPHRASE --data pwmd:convert + %s %s",
365 _("Passphrase:"), desc);
366 assuan_end_confidential (agent->ctx);
367 xfree (desc);
368 if (rc)
369 goto fail;
371 passphraselen--; // null byte
372 send_to_agent (agent, NULL, NULL, "CLEAR_PASSPHRASE pwmd:convert");
373 cleanup_agent (agent);
374 agent = NULL;
376 else if (keyfile && fh.iter > 0)
377 #else
378 if (keyfile && fh.iter > 0)
379 #endif
381 struct stat pst;
382 int pfd = open (keyfile, O_RDONLY);
384 if (pfd == -1)
386 rc = gpg_error_from_syserror ();
387 goto fail;
390 if (stat (keyfile, &pst) == -1)
392 rc = gpg_error_from_syserror ();
393 close (pfd);
394 goto fail;
397 passphrase = xmalloc (pst.st_size);
398 if (!passphrase)
400 rc = GPG_ERR_ENOMEM;
401 close (pfd);
402 goto fail;
405 passphraselen = read (pfd, passphrase, pst.st_size);
406 close (pfd);
407 if (passphraselen != pst.st_size)
409 rc = GPG_ERR_INV_LENGTH;
410 goto fail;
413 else if (fh.iter > 0)
415 rc = getpin_common (NULL, filename, PINENTRY_OPEN, &passphrase,
416 &passphraselen);
417 if (rc)
418 goto fail;
421 key = gcry_malloc (KEYSIZE);
422 if (!key)
424 rc = GPG_ERR_ENOMEM;
425 goto fail;
428 fp = fdopen (fd, "r");
429 len = st.st_size - ftell (fp);
431 if (fh.version >= 0x221 && fh.version < 0x0300)
433 rc = gcry_kdf_derive (passphrase, passphraselen, GCRY_KDF_ITERSALTED_S2K,
434 GCRY_MD_SHA1, fh.salt, 8, 1000, KEYSIZE, key);
435 if (rc)
436 goto fail;
438 else
439 gcry_md_hash_buffer (GCRY_MD_SHA256, key, passphrase, passphraselen);
441 data = gcry_malloc (len);
442 if (!data)
444 rc = GPG_ERR_ENOMEM;
445 goto fail;
448 datalen = read (fd, data, len);
449 if (datalen != len)
451 rc = GPG_ERR_INV_LENGTH;
452 goto fail;
455 fprintf (stderr, _("Decrypting ...\n"));
456 rc = decrypt (&fh, key, &data, datalen, result, result_len);
458 fail:
459 gcry_free (key);
460 gcry_free (data);
461 xfree (passphrase);
463 #ifdef WITH_AGENT
464 if (agent)
465 cleanup_agent (agent);
466 #endif
468 if (fd != -1)
469 close (fd);
470 return rc;