aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/https/opencdk
diff options
context:
space:
mode:
authorlv-426 <oxcafebaby@yahoo.com>2008-06-22 18:20:35 +0000
committerlv-426 <oxcafebaby@yahoo.com>2008-06-22 18:20:35 +0000
commita0339d2458867dbe9485499265641ff205063445 (patch)
tree055b38828b3696520408a32edf81df5bb37400f0 /src/daemon/https/opencdk
parent97c026da05495b83f1511906c2ca027e12ef6cf7 (diff)
downloadlibmicrohttpd-a0339d2458867dbe9485499265641ff205063445.tar.gz
libmicrohttpd-a0339d2458867dbe9485499265641ff205063445.zip
initial GNU TLS import - this should reduce in size considerable
Diffstat (limited to 'src/daemon/https/opencdk')
-rw-r--r--src/daemon/https/opencdk/Makefile.am12
-rw-r--r--src/daemon/https/opencdk/README5
-rw-r--r--src/daemon/https/opencdk/armor.c763
-rw-r--r--src/daemon/https/opencdk/cipher.c528
-rw-r--r--src/daemon/https/opencdk/compress.c238
-rw-r--r--src/daemon/https/opencdk/context.h120
-rw-r--r--src/daemon/https/opencdk/dummy.c15
-rw-r--r--src/daemon/https/opencdk/filters.h95
-rw-r--r--src/daemon/https/opencdk/kbnode.c581
-rw-r--r--src/daemon/https/opencdk/keydb.c2303
-rw-r--r--src/daemon/https/opencdk/literal.c307
-rw-r--r--src/daemon/https/opencdk/main.c779
-rw-r--r--src/daemon/https/opencdk/main.h183
-rw-r--r--src/daemon/https/opencdk/misc.c571
-rw-r--r--src/daemon/https/opencdk/new-packet.c874
-rw-r--r--src/daemon/https/opencdk/opencdk.h1169
-rw-r--r--src/daemon/https/opencdk/packet.h40
-rw-r--r--src/daemon/https/opencdk/pubkey.c1380
-rw-r--r--src/daemon/https/opencdk/read-packet.c1179
-rw-r--r--src/daemon/https/opencdk/seskey.c717
-rw-r--r--src/daemon/https/opencdk/sig-check.c489
-rw-r--r--src/daemon/https/opencdk/stream.c1446
-rw-r--r--src/daemon/https/opencdk/stream.h88
-rw-r--r--src/daemon/https/opencdk/types.h44
-rw-r--r--src/daemon/https/opencdk/verify.c306
-rw-r--r--src/daemon/https/opencdk/write-packet.c947
26 files changed, 15179 insertions, 0 deletions
diff --git a/src/daemon/https/opencdk/Makefile.am b/src/daemon/https/opencdk/Makefile.am
new file mode 100644
index 00000000..b69a151f
--- /dev/null
+++ b/src/daemon/https/opencdk/Makefile.am
@@ -0,0 +1,12 @@
1AM_CPPFLAGS = -I$(top_srcdir)/lib \
2-I$(top_srcdir)/lgl \
3-I$(GCRYPT_CPPFLAGS)
4
5noinst_LTLIBRARIES = libopencdk.la
6
7libopencdk_la_LDFLAGS = -lgcrypt
8
9libopencdk_la_SOURCES = armor.c filters.h main.c seskey.c types.h \
10 cipher.c kbnode.c main.h packet.h dummy.c sig-check.c verify.c \
11 compress.c keydb.c misc.c pubkey.c stream.c write-packet.c \
12 context.h literal.c new-packet.c read-packet.c stream.h opencdk.h
diff --git a/src/daemon/https/opencdk/README b/src/daemon/https/opencdk/README
new file mode 100644
index 00000000..2cf780e0
--- /dev/null
+++ b/src/daemon/https/opencdk/README
@@ -0,0 +1,5 @@
1This is a stripped down mirror of the files in OpenCDK
2src/. To avoid to link proc-packets.c, dummy.c is included.
3
4In Makefile.am libminiopencdk_la_SOURCES contains the list
5of all needed files.
diff --git a/src/daemon/https/opencdk/armor.c b/src/daemon/https/opencdk/armor.c
new file mode 100644
index 00000000..e95f7eb1
--- /dev/null
+++ b/src/daemon/https/opencdk/armor.c
@@ -0,0 +1,763 @@
1/* armor.c - Armor filters
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 *
17 * ChangeLog for basic BASE64 code (base64_encode, base64_decode):
18 * Original author: Eric S. Raymond (Fetchmail)
19 * Heavily modified by Brendan Cully <brendan@kublai.com> (Mutt)
20 * Modify the code for generic use by Timo Schulz <twoaday@freakmail.de>
21 */
22
23#ifdef HAVE_CONFIG_H
24# include <config.h>
25#endif
26#include <stdio.h>
27#include <string.h>
28#include <assert.h>
29#include <sys/stat.h>
30
31#include "opencdk.h"
32#include "main.h"
33#include "filters.h"
34
35#ifdef __MINGW32__
36# define LF "\r\n"
37#else
38# define LF "\n"
39#endif
40
41#define CRCINIT 0xB704CE
42
43#define BAD -1
44#define b64val(c) index64[(unsigned int)(c)]
45
46static u32 crc_table[] = {
47 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC,
48 0x9F7F17,
49 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5,
50 0x3EFE2E,
51 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65,
52 0x5A319E,
53 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C,
54 0xFBB0A7,
55 0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205,
56 0x93AEFE,
57 0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C,
58 0x322FC7,
59 0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C,
60 0x56E077,
61 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5,
62 0xF7614E,
63 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E,
64 0x86DCC5,
65 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107,
66 0x275DFC,
67 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7,
68 0x43924C,
69 0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E,
70 0xE21375,
71 0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7,
72 0x8A0D2C,
73 0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE,
74 0x2B8C15,
75 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E,
76 0x4F43A5,
77 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67,
78 0xEEC29C,
79 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448,
80 0xAC38B3,
81 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571,
82 0x0DB98A,
83 0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1,
84 0x69763A,
85 0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8,
86 0xC8F703,
87 0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1,
88 0xA0E95A,
89 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498,
90 0x016863,
91 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28,
92 0x65A7D3,
93 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11,
94 0xC426EA,
95 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A,
96 0xB59B61,
97 0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3,
98 0x141A58,
99 0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913,
100 0x70D5E8,
101 0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A,
102 0xD154D1,
103 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673,
104 0xB94A88,
105 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A,
106 0x18CBB1,
107 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA,
108 0x7C0401,
109 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3,
110 0xDD8538
111};
112
113static const char *armor_begin[] = {
114 "BEGIN PGP MESSAGE",
115 "BEGIN PGP PUBLIC KEY BLOCK",
116 "BEGIN PGP PRIVATE KEY BLOCK",
117 "BEGIN PGP SIGNATURE",
118 NULL
119};
120
121static const char *armor_end[] = {
122 "END PGP MESSAGE",
123 "END PGP PUBLIC KEY BLOCK",
124 "END PGP PRIVATE KEY BLOCK",
125 "END PGP SIGNATURE",
126 NULL
127};
128
129static const char *valid_headers[] = {
130 "Comment",
131 "Version",
132 "MessageID",
133 "Hash",
134 "Charset",
135 NULL
136};
137
138static char b64chars[] =
139 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
140
141static int index64[128] = {
142 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
143 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
144 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
145 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
146 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
147 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
148 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
149 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
150};
151
152
153/* encode a raw binary buffer to a null-terminated base64 strings */
154static int
155base64_encode (char *out, const byte * in, size_t len, size_t olen)
156{
157 if (!out || !in)
158 return CDK_Inv_Value;
159
160 while (len >= 3 && olen > 10)
161 {
162 *out++ = b64chars[in[0] >> 2];
163 *out++ = b64chars[((in[0] << 4) & 0x30) | (in[1] >> 4)];
164 *out++ = b64chars[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
165 *out++ = b64chars[in[2] & 0x3f];
166 olen -= 4;
167 len -= 3;
168 in += 3;
169 }
170
171 /* clean up remainder */
172 if (len > 0 && olen > 4)
173 {
174 byte fragment = 0;
175 *out++ = b64chars[in[0] >> 2];
176 fragment = (in[0] << 4) & 0x30;
177 if (len > 1)
178 fragment |= in[1] >> 4;
179 *out++ = b64chars[fragment];
180 *out++ = (len < 2) ? '=' : b64chars[(in[1] << 2) & 0x3c];
181 *out++ = '=';
182 }
183 *out = '\0';
184 return 0;
185}
186
187
188/* Convert '\0'-terminated base64 string to raw byte buffer.
189 Returns length of returned buffer, or -1 on error. */
190static int
191base64_decode (byte * out, const char *in)
192{
193 size_t len;
194 byte digit1, digit2, digit3, digit4;
195
196 if (!out || !in)
197 return -1;
198
199 len = 0;
200 do
201 {
202 digit1 = in[0];
203 if (digit1 > 127 || b64val (digit1) == BAD)
204 return -1;
205 digit2 = in[1];
206 if (digit2 > 127 || b64val (digit2) == BAD)
207 return -1;
208 digit3 = in[2];
209 if (digit3 > 127 || ((digit3 != '=') && (b64val (digit3) == BAD)))
210 return -1;
211 digit4 = in[3];
212 if (digit4 > 127 || ((digit4 != '=') && (b64val (digit4) == BAD)))
213 return -1;
214 in += 4;
215
216 /* digits are already sanity-checked */
217 *out++ = (b64val (digit1) << 2) | (b64val (digit2) >> 4);
218 len++;
219 if (digit3 != '=')
220 {
221 *out++ = ((b64val (digit2) << 4) & 0xf0) | (b64val (digit3) >> 2);
222 len++;
223 if (digit4 != '=')
224 {
225 *out++ = ((b64val (digit3) << 6) & 0xc0) | b64val (digit4);
226 len++;
227 }
228 }
229 }
230 while (*in && digit4 != '=');
231
232 return len;
233}
234
235
236/* Return the compression algorithm in @r_zipalgo.
237 If the parameter is not set after execution,
238 the stream is not compressed. */
239static int
240compress_get_algo (cdk_stream_t inp, int *r_zipalgo)
241{
242 byte plain[512];
243 char buf[128];
244 int nread, pkttype;
245
246 *r_zipalgo = 0;
247 cdk_stream_seek (inp, 0);
248 while (!cdk_stream_eof (inp))
249 {
250 nread = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
251 if (!nread || nread == -1)
252 break;
253 if (nread == 1 && !cdk_stream_eof (inp)
254 && (nread = _cdk_stream_gets (inp, buf, DIM (buf) - 1)) > 0)
255 {
256 base64_decode (plain, buf);
257 if (!(*plain & 0x80))
258 break;
259 pkttype = *plain & 0x40 ? (*plain & 0x3f) : ((*plain >> 2) & 0xf);
260 if (pkttype == CDK_PKT_COMPRESSED && r_zipalgo)
261 {
262 _cdk_log_debug ("armor compressed (algo=%d)\n", *(plain + 1));
263 *r_zipalgo = *(plain + 1);
264 }
265 break;
266 }
267 }
268 return 0;
269}
270
271
272static int
273check_armor (cdk_stream_t inp, int *r_zipalgo)
274{
275 char buf[4096];
276 size_t nread;
277 int check;
278
279 check = 0;
280 nread = cdk_stream_read (inp, buf, DIM (buf) - 1);
281 if (nread > 0)
282 {
283 buf[nread] = '\0';
284 if (strstr (buf, "-----BEGIN PGP"))
285 {
286 compress_get_algo (inp, r_zipalgo);
287 check = 1;
288 }
289 cdk_stream_seek (inp, 0);
290 }
291 return check;
292}
293
294
295static int
296is_armored (int ctb)
297{
298 int pkttype = 0;
299
300 if (!(ctb & 0x80))
301 return 1; /* invalid packet: assume it is armored */
302 pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb >> 2) & 0xf);
303 switch (pkttype)
304 {
305 case CDK_PKT_MARKER:
306 case CDK_PKT_SYMKEY_ENC:
307 case CDK_PKT_ONEPASS_SIG:
308 case CDK_PKT_PUBLIC_KEY:
309 case CDK_PKT_SECRET_KEY:
310 case CDK_PKT_PUBKEY_ENC:
311 case CDK_PKT_SIGNATURE:
312 case CDK_PKT_LITERAL:
313 case CDK_PKT_COMPRESSED:
314 case CDK_PKT_ENCRYPTED:
315 return 0; /* seems to be a regular packet: not armored */
316 }
317 return 1;
318}
319
320
321static u32
322update_crc (u32 crc, const byte * buf, size_t buflen)
323{
324 int j;
325
326 if (!crc)
327 crc = CRCINIT;
328
329 for (j = 0; j < buflen; j++)
330 crc = (crc << 8) ^ crc_table[0xff & ((crc >> 16) ^ buf[j])];
331 crc &= 0xffffff;
332 return crc;
333}
334
335
336static cdk_error_t
337armor_encode (void *opaque, FILE * in, FILE * out)
338{
339 armor_filter_t *afx = opaque;
340 struct stat statbuf;
341 char crcbuf[5], buf[128], raw[49];
342 byte crcbuf2[3];
343 size_t nread = 0;
344 const char *lf;
345
346 if (!afx)
347 return CDK_Inv_Value;
348 if (afx->idx < 0 || afx->idx > DIM (armor_begin) ||
349 afx->idx2 < 0 || afx->idx2 > DIM (armor_end))
350 return CDK_Inv_Value;
351
352 _cdk_log_debug ("armor filter: encode\n");
353
354 memset (crcbuf, 0, sizeof (crcbuf));
355
356 lf = afx->le ? afx->le : LF;
357 fprintf (out, "-----%s-----%s", armor_begin[afx->idx], lf);
358 fprintf (out, "Version: OpenPrivacy " PACKAGE_VERSION "%s", lf);
359 if (afx->hdrlines)
360 fwrite (afx->hdrlines, 1, strlen (afx->hdrlines), out);
361 fprintf (out, "%s", lf);
362
363 if (fstat (fileno (in), &statbuf))
364 return CDK_General_Error;
365
366 while (!feof (in))
367 {
368 nread = fread (raw, 1, DIM (raw) - 1, in);
369 if (!nread)
370 break;
371 if (ferror (in))
372 return CDK_File_Error;
373 afx->crc = update_crc (afx->crc, (byte *) raw, nread);
374 base64_encode (buf, (byte *) raw, nread, DIM (buf) - 1);
375 fprintf (out, "%s%s", buf, lf);
376 }
377
378 crcbuf2[0] = afx->crc >> 16;
379 crcbuf2[1] = afx->crc >> 8;
380 crcbuf2[2] = afx->crc;
381 crcbuf[0] = b64chars[crcbuf2[0] >> 2];
382 crcbuf[1] = b64chars[((crcbuf2[0] << 4) & 0x30) | (crcbuf2[1] >> 4)];
383 crcbuf[2] = b64chars[((crcbuf2[1] << 2) & 0x3c) | (crcbuf2[2] >> 6)];
384 crcbuf[3] = b64chars[crcbuf2[2] & 0x3f];
385 fprintf (out, "=%s%s", crcbuf, lf);
386 fprintf (out, "-----%s-----%s", armor_end[afx->idx2], lf);
387
388 return 0;
389}
390
391
392/**
393 * cdk_armor_filter_use:
394 * @inp: the stream to check
395 *
396 * Check if the stream contains armored data.
397 **/
398int
399cdk_armor_filter_use (cdk_stream_t inp)
400{
401 int c, check;
402 int zipalgo;
403
404 zipalgo = 0;
405 c = cdk_stream_getc (inp);
406 if (c == EOF)
407 return 0; /* EOF, doesn't matter whether armored or not */
408 cdk_stream_seek (inp, 0);
409 check = is_armored (c);
410 if (check)
411 {
412 check = check_armor (inp, &zipalgo);
413 if (zipalgo)
414 _cdk_stream_set_compress_algo (inp, zipalgo);
415 }
416 return check;
417}
418
419
420static int
421search_header (const char *buf, const char **array)
422{
423 const char *s;
424 int i;
425
426 if (strlen (buf) < 5 || strncmp (buf, "-----", 5))
427 return -1;
428 for (i = 0; (s = array[i]); i++)
429 {
430 if (!strncmp (s, buf + 5, strlen (s)))
431 return i;
432 }
433 return -1;
434}
435
436
437const char *
438_cdk_armor_get_lineend (void)
439{
440 return LF;
441}
442
443
444static cdk_error_t
445armor_decode (void *opaque, FILE * in, FILE * out)
446{
447 armor_filter_t *afx = opaque;
448 const char *s;
449 char buf[127];
450 byte raw[128], crcbuf[4];
451 u32 crc2 = 0;
452 size_t nread = 0;
453 int i, pgp_data = 0;
454 cdk_error_t rc = 0;
455
456 if (!afx)
457 return CDK_Inv_Value;
458
459 _cdk_log_debug ("armor filter: decode\n");
460
461 fseek (in, 0, SEEK_SET);
462 /* Search the begin of the message */
463 while (!feof (in) && !pgp_data)
464 {
465 s = fgets (buf, DIM (buf) - 1, in);
466 if (!s)
467 break;
468 afx->idx = search_header (buf, armor_begin);
469 if (afx->idx >= 0)
470 pgp_data = 1;
471 }
472
473 if (feof (in) || !pgp_data)
474 return CDK_Armor_Error; /* no data found */
475
476 /* Parse header until the empty line is reached */
477 while (!feof (in))
478 {
479 s = fgets (buf, DIM (buf) - 1, in);
480 if (!s)
481 return CDK_EOF;
482 if (strlen (s) == strlen (LF))
483 {
484 rc = 0;
485 break; /* empty line */
486 }
487 /* From RFC2440: OpenPGP should consider improperly formatted Armor
488 Headers to be corruption of the ASCII Armor. A colon and a single
489 space separate the key and value. */
490 if (!strstr (buf, ": "))
491 return CDK_Armor_Error;
492 rc = CDK_General_Error;
493 for (i = 0; (s = valid_headers[i]); i++)
494 {
495 if (!strncmp (s, buf, strlen (s)))
496 rc = 0;
497 }
498 if (rc)
499 {
500 /* From RFC2440: Unknown keys should be reported to the user,
501 but OpenPGP should continue to process the message. */
502 _cdk_log_info ("unknown header: `%s'\n", buf);
503 rc = 0;
504 }
505 }
506
507 /* Read the data body */
508 while (!feof (in))
509 {
510 s = fgets (buf, DIM (buf) - 1, in);
511 if (!s)
512 break;
513 buf[strlen (buf) - strlen (LF)] = '\0';
514 if (buf[0] == '=' && strlen (s) == 5)
515 { /* CRC */
516 memset (crcbuf, 0, sizeof (crcbuf));
517 base64_decode (crcbuf, buf + 1);
518 crc2 = (crcbuf[0] << 16) | (crcbuf[1] << 8) | crcbuf[2];
519 break; /* stop here */
520 }
521 else
522 {
523 nread = base64_decode (raw, buf);
524 if (nread == -1 || nread == 0)
525 break;
526 afx->crc = update_crc (afx->crc, raw, nread);
527 fwrite (raw, 1, nread, out);
528 }
529 }
530
531 /* Search the tail of the message */
532 s = fgets (buf, DIM (buf) - 1, in);
533 if (s)
534 {
535 buf[strlen (buf) - strlen (LF)] = '\0';
536 rc = CDK_General_Error;
537 afx->idx2 = search_header (buf, armor_end);
538 if (afx->idx2 >= 0)
539 rc = 0;
540 }
541
542 /* This catches error when no tail was found or the header is
543 different then the tail line. */
544 if (rc || afx->idx != afx->idx2)
545 rc = CDK_Armor_Error;
546
547 afx->crc_okay = (afx->crc == crc2) ? 1 : 0;
548 if (!afx->crc_okay && !rc)
549 {
550 _cdk_log_debug ("file crc=%08lX afx_crc=%08lX\n", crc2, afx->crc);
551 rc = CDK_Armor_CRC_Error;
552 }
553
554 return rc;
555}
556
557
558/**
559 * cdk_file_armor:
560 * @hd: Handle
561 * @file: Name of the file to protect.
562 * @output: Output filename.
563 *
564 * Protect a file with ASCII armor.
565 **/
566cdk_error_t
567cdk_file_armor (cdk_ctx_t hd, const char *file, const char *output)
568{
569 cdk_stream_t inp, out;
570 cdk_error_t rc;
571
572 rc = _cdk_check_args (hd->opt.overwrite, file, output);
573 if (rc)
574 return rc;
575
576 rc = cdk_stream_open (file, &inp);
577 if (rc)
578 return rc;
579
580 rc = cdk_stream_new (output, &out);
581 if (rc)
582 {
583 cdk_stream_close (inp);
584 return rc;
585 }
586
587 cdk_stream_set_armor_flag (out, CDK_ARMOR_MESSAGE);
588 if (hd->opt.compress)
589 rc = cdk_stream_set_compress_flag (out, hd->compress.algo,
590 hd->compress.level);
591 if (!rc)
592 rc = cdk_stream_set_literal_flag (out, 0, file);
593 if (!rc)
594 rc = cdk_stream_kick_off (inp, out);
595 if (!rc)
596 rc = _cdk_stream_get_errno (out);
597
598 cdk_stream_close (out);
599 cdk_stream_close (inp);
600 return rc;
601}
602
603
604/**
605 * cdk_file_dearmor:
606 * @file: Name of the file to unprotect.
607 * @output: Output filename.
608 *
609 * Remove ASCII armor from a file.
610 **/
611cdk_error_t
612cdk_file_dearmor (const char *file, const char *output)
613{
614 cdk_stream_t inp, out;
615 cdk_error_t rc;
616 int zipalgo;
617
618 rc = _cdk_check_args (1, file, output);
619 if (rc)
620 return rc;
621
622 rc = cdk_stream_open (file, &inp);
623 if (rc)
624 return rc;
625
626 rc = cdk_stream_create (output, &out);
627 if (rc)
628 {
629 cdk_stream_close (inp);
630 return rc;
631 }
632
633 if (cdk_armor_filter_use (inp))
634 {
635 rc = cdk_stream_set_literal_flag (inp, 0, NULL);
636 zipalgo = cdk_stream_is_compressed (inp);
637 if (zipalgo)
638 rc = cdk_stream_set_compress_flag (inp, zipalgo, 0);
639 if (!rc)
640 rc = cdk_stream_set_armor_flag (inp, 0);
641 if (!rc)
642 rc = cdk_stream_kick_off (inp, out);
643 if (!rc)
644 rc = _cdk_stream_get_errno (inp);
645 }
646
647 cdk_stream_close (inp);
648 cdk_stream_close (out);
649 return rc;
650}
651
652
653int
654_cdk_filter_armor (void *opaque, int ctl, FILE * in, FILE * out)
655{
656 if (ctl == STREAMCTL_READ)
657 return armor_decode (opaque, in, out);
658 else if (ctl == STREAMCTL_WRITE)
659 return armor_encode (opaque, in, out);
660 else if (ctl == STREAMCTL_FREE)
661 {
662 armor_filter_t *afx = opaque;
663 if (afx)
664 {
665 _cdk_log_debug ("free armor filter\n");
666 afx->idx = afx->idx2 = 0;
667 afx->crc = afx->crc_okay = 0;
668 return 0;
669 }
670 }
671 return CDK_Inv_Mode;
672}
673
674
675/**
676 * cdk_armor_encode_buffer:
677 * @inbuf: the raw input buffer
678 * @inlen: raw buffer len
679 * @outbuf: the destination buffer for the base64 output
680 * @outlen: destination buffer len
681 * @nwritten: actual length of the base64 data
682 * @type: the base64 file type.
683 *
684 * Encode the given buffer into base64 format.
685 **/
686cdk_error_t
687cdk_armor_encode_buffer (const byte * inbuf, size_t inlen,
688 char *outbuf, size_t outlen,
689 size_t * nwritten, int type)
690{
691 const char *head, *tail, *le;
692 byte tempbuf[48];
693 char tempout[128];
694 size_t pos, off, len, rest;
695
696 if (!inbuf || !nwritten)
697 return CDK_Inv_Value;
698 if (type > CDK_ARMOR_SIGNATURE)
699 return CDK_Inv_Mode;
700
701 head = armor_begin[type];
702 tail = armor_end[type];
703 le = _cdk_armor_get_lineend ();
704 pos = strlen (head) + 10 + 2 + 2 + strlen (tail) + 10 + 2 + 5 + 2;
705 /* The output data is 4/3 times larger, plus a line end for each line. */
706 pos += (4 * inlen / 3) + 2 * (4 * inlen / 3 / 64);
707
708 if (outbuf && outlen < pos)
709 return CDK_Too_Short;
710
711 /* Only return the size of the output. */
712 if (!outbuf)
713 {
714 *nwritten = pos;
715 return 0;
716 }
717
718 pos = 0;
719 memset (outbuf, 0, outlen);
720 memcpy (outbuf + pos, "-----", 5);
721 pos += 5;
722 memcpy (outbuf + pos, head, strlen (head));
723 pos += strlen (head);
724 memcpy (outbuf + pos, "-----", 5);
725 pos += 5;
726 memcpy (outbuf + pos, le, strlen (le));
727 pos += strlen (le);
728 memcpy (outbuf + pos, le, strlen (le));
729 pos += strlen (le);
730 rest = inlen;
731 for (off = 0; off < inlen;)
732 {
733 if (rest > 48)
734 {
735 memcpy (tempbuf, inbuf + off, 48);
736 off += 48;
737 len = 48;
738 }
739 else
740 {
741 memcpy (tempbuf, inbuf + off, rest);
742 off += rest;
743 len = rest;
744 }
745 rest -= len;
746 base64_encode (tempout, tempbuf, len, DIM (tempout) - 1);
747 memcpy (outbuf + pos, tempout, strlen (tempout));
748 pos += strlen (tempout);
749 memcpy (outbuf + pos, le, strlen (le));
750 pos += strlen (le);
751 }
752
753 memcpy (outbuf + pos, "-----", 5);
754 pos += 5;
755 memcpy (outbuf + pos, tail, strlen (tail));
756 pos += strlen (tail);
757 memcpy (outbuf + pos, "-----", 5);
758 pos += 5;
759 memcpy (outbuf + pos, le, strlen (le));
760 pos += strlen (le);
761 *nwritten = pos;
762 return 0;
763}
diff --git a/src/daemon/https/opencdk/cipher.c b/src/daemon/https/opencdk/cipher.c
new file mode 100644
index 00000000..2ce22eb3
--- /dev/null
+++ b/src/daemon/https/opencdk/cipher.c
@@ -0,0 +1,528 @@
1/* cipher.c - Cipher filters
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdio.h>
21#include <assert.h>
22#include <sys/stat.h>
23
24#include "opencdk.h"
25#include "main.h"
26#include "filters.h"
27
28
29/* The maximal cipher block size in octets. */
30#define MAX_CIPHER_BLKSIZE 16
31
32
33static off_t
34fp_get_length (FILE * fp)
35{
36 struct stat statbuf;
37
38 if (fstat (fileno (fp), &statbuf))
39 return (off_t) - 1;
40 return statbuf.st_size;
41}
42
43
44static cdk_error_t
45hash_encode (void *opaque, FILE * in, FILE * out)
46{
47 md_filter_t *mfx = opaque;
48 byte buf[BUFSIZE];
49 gcry_error_t err;
50 int nread;
51
52 if (!mfx)
53 return CDK_Inv_Value;
54
55 _cdk_log_debug ("hash filter: encode algo=%d\n", mfx->digest_algo);
56
57 if (!mfx->md)
58 {
59 err = gcry_md_open (&mfx->md, mfx->digest_algo, 0);
60 if (err)
61 return map_gcry_error (err);
62 }
63
64 while (!feof (in))
65 {
66 nread = fread (buf, 1, BUFSIZE, in);
67 if (!nread)
68 break;
69 gcry_md_write (mfx->md, buf, nread);
70 }
71
72 wipemem (buf, sizeof (buf));
73 return 0;
74}
75
76
77cdk_error_t
78_cdk_filter_hash (void *opaque, int ctl, FILE * in, FILE * out)
79{
80 if (ctl == STREAMCTL_READ)
81 return hash_encode (opaque, in, out);
82 else if (ctl == STREAMCTL_FREE)
83 {
84 md_filter_t *mfx = opaque;
85 if (mfx)
86 {
87 _cdk_log_debug ("free hash filter\n");
88 gcry_md_close (mfx->md);
89 mfx->md = NULL;
90 return 0;
91 }
92 }
93 return CDK_Inv_Mode;
94}
95
96
97static cdk_error_t
98write_header (cipher_filter_t * cfx, FILE * out)
99{
100 cdk_pkt_encrypted_t ed;
101 cdk_packet_t pkt;
102 cdk_error_t rc;
103 cdk_dek_t dek = cfx->dek;
104 byte temp[MAX_CIPHER_BLKSIZE + 2];
105 size_t blocksize;
106 int use_mdc, nprefix;
107 gcry_error_t err;
108
109 blocksize = gcry_cipher_get_algo_blklen (dek->algo);
110 if (blocksize < 8 || blocksize > 16)
111 return CDK_Inv_Algo;
112
113 /* It might be possible the receiver does not understand the MDC
114 output and thus we offer to supress the MDC packet. */
115 use_mdc = dek->use_mdc;
116 if (blocksize == 8)
117 use_mdc = 0;
118
119 /* We need to increase the data length because the MDC packet will
120 be also included. It has a fixed length of 22 octets. */
121 if (use_mdc && cfx->datalen)
122 cfx->datalen += 22;
123
124 cdk_pkt_alloc (&pkt, CDK_PKT_ENCRYPTED_MDC);
125 ed = pkt->pkt.encrypted;
126 if (!cfx->blkmode.on)
127 {
128 ed->len = cfx->datalen;
129 ed->extralen = blocksize + 2;
130 }
131 else
132 cfx->blkmode.nleft = DEF_BLOCKSIZE;
133
134 if (use_mdc)
135 {
136 ed->mdc_method = GCRY_MD_SHA1;
137 err = gcry_md_open (&cfx->mdc, GCRY_MD_SHA1, 0);
138 if (err)
139 return map_gcry_error (err);
140 }
141
142 /* When we use partial bodies, the MDC feature or a blocksize
143 larger than 8, we force the use of the new packet format. */
144 if (cfx->blkmode.on || use_mdc || blocksize != 8)
145 pkt->old_ctb = 0;
146 else
147 pkt->old_ctb = 1;
148 pkt->pkttype = use_mdc ? CDK_PKT_ENCRYPTED_MDC : CDK_PKT_ENCRYPTED;
149 rc = _cdk_pkt_write_fp (out, pkt);
150 cdk_pkt_release (pkt);
151 if (rc)
152 return rc;
153
154 nprefix = blocksize;
155 gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM);
156 temp[nprefix] = temp[nprefix - 2];
157 temp[nprefix + 1] = temp[nprefix - 1];
158 err = gcry_cipher_open (&cfx->hd, dek->algo, GCRY_CIPHER_MODE_CFB,
159 use_mdc ? 0 : GCRY_CIPHER_ENABLE_SYNC);
160 if (err)
161 return map_gcry_error (err);
162 err = gcry_cipher_setiv (cfx->hd, NULL, 0);
163 if (err)
164 return map_gcry_error (err);
165 err = gcry_cipher_setkey (cfx->hd, dek->key, dek->keylen);
166 if (err)
167 return map_gcry_error (err);
168 if (cfx->mdc)
169 gcry_md_write (cfx->mdc, temp, nprefix + 2);
170 gcry_cipher_encrypt (cfx->hd, temp, nprefix + 2, NULL, 0);
171 gcry_cipher_sync (cfx->hd);
172 fwrite (temp, 1, nprefix + 2, out);
173 if (cfx->blkmode.on)
174 {
175 cfx->blkmode.nleft -= (nprefix + 2);
176 if (use_mdc)
177 cfx->blkmode.nleft--; /* 1 byte version */
178 }
179 return rc;
180}
181
182
183static cdk_error_t
184write_mdc_packet (FILE * out, cipher_filter_t * cfx)
185{
186 byte pktdata[22];
187 int dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
188
189 if (!out || !cfx)
190 return CDK_Inv_Value;
191 if (dlen != 20)
192 return CDK_Inv_Algo;
193
194 /* We must hash the prefix of the MDC packet here */
195 pktdata[0] = 0xD3;
196 pktdata[1] = 0x14;
197 gcry_md_write (cfx->mdc, pktdata, 2);
198 gcry_md_final (cfx->mdc);
199 memcpy (pktdata + 2, gcry_md_read (cfx->mdc, GCRY_MD_SHA1), dlen);
200 gcry_cipher_encrypt (cfx->hd, pktdata, dlen + 2, NULL, 0);
201 fwrite (pktdata, 1, dlen + 2, out);
202 wipemem (pktdata, sizeof (pktdata));
203 return 0;
204}
205
206
207static inline int
208num2bits (size_t n)
209{
210 size_t i;
211
212 for (i = 0; n > 1; i++)
213 n >>= 1;
214 return i;
215}
216
217
218static cdk_error_t
219write_partial_block (FILE * in, FILE * out, off_t * r_len,
220 cipher_filter_t * cfx)
221{
222 gcry_error_t err;
223 byte buf[DEF_BLOCKSIZE];
224 size_t n;
225 int nread;
226
227 if (!out || !cfx)
228 return CDK_Inv_Value;
229
230 if (!cfx->blkmode.nleft && *r_len > 0)
231 {
232 if (*r_len > DEF_BLOCKSIZE)
233 {
234 /*_cdk_log_debug ("write_partial_block: size %lu block %d\n",
235 *r_len, DEF_BLOCKSIZE);*/
236 fputc ((0xE0 | DEF_BLOCKBITS), out);
237 cfx->blkmode.nleft = DEF_BLOCKSIZE;
238 (*r_len) -= DEF_BLOCKSIZE;
239 }
240 else if (*r_len > 512)
241 {
242 n = num2bits (*r_len);
243 cfx->blkmode.nleft = (1 << n);
244 /*_cdk_log_debug ("write_partial_block: size %lu bits %d block %d\n",
245 *r_len, n, (1<<n));*/
246 fputc ((0xE0 | n), out);
247 (*r_len) -= cfx->blkmode.nleft;
248 }
249 else
250 {
251 size_t pktlen = *r_len;
252
253 /* If we use the MDC mode, we need to increase the final
254 partial body length to hold the mdc packet itself. */
255 if (cfx->mdc)
256 pktlen += 22;
257
258 if (pktlen < 192)
259 fputc (pktlen, out);
260 else if (pktlen < 8384)
261 {
262 pktlen -= 192;
263 fputc ((pktlen / 256) + 192, out);
264 fputc ((pktlen % 256), out);
265 }
266 cfx->blkmode.nleft = pktlen;
267 /*_cdk_log_debug ("write_partial_block: end %d block\n", pktlen);*/
268 (*r_len) -= pktlen;
269 }
270 }
271 else
272 (*r_len) -= cfx->blkmode.nleft;
273
274 n = cfx->blkmode.nleft < DIM (buf) ? cfx->blkmode.nleft : DIM (buf);
275 nread = fread (buf, 1, n, in);
276 if (!nread)
277 return CDK_EOF;
278 if (cfx->mdc)
279 gcry_md_write (cfx->mdc, buf, nread);
280 err = gcry_cipher_encrypt (cfx->hd, buf, nread, NULL, 0);
281 if (err)
282 return map_gcry_error (err);
283 fwrite (buf, 1, nread, out);
284 cfx->blkmode.nleft -= nread;
285 return 0;
286}
287
288
289static cdk_error_t
290cipher_encode_file (void *opaque, FILE * in, FILE * out)
291{
292 cipher_filter_t *cfx = opaque;
293 byte buf[BUFSIZE];
294 off_t len, len2;
295 int nread;
296 cdk_error_t rc;
297
298 if (!cfx || !in || !out)
299 return CDK_Inv_Value;
300
301 len = len2 = fp_get_length (in);
302 if (len == (off_t) - 1)
303 return CDK_File_Error;
304 while (!feof (in))
305 {
306 if (cfx->blkmode.on)
307 {
308 rc = write_partial_block (in, out, &len2, cfx);
309 if (rc == CDK_EOF)
310 break;
311 if (rc)
312 {
313 wipemem (buf, sizeof (buf));
314 return rc;
315 }
316 continue;
317 }
318 nread = fread (buf, 1, DIM (buf), in);
319 if (!nread)
320 break;
321 if (cfx->mdc)
322 gcry_md_write (cfx->mdc, buf, nread);
323 gcry_cipher_encrypt (cfx->hd, buf, nread, NULL, 0);
324 fwrite (buf, 1, nread, out);
325 }
326 if (cfx->mdc)
327 rc = write_mdc_packet (out, cfx);
328 else
329 rc = 0;
330
331 wipemem (buf, sizeof (buf));
332 return rc;
333}
334
335
336static cdk_error_t
337read_header (cipher_filter_t * cfx, FILE * in)
338{
339 cdk_dek_t dek;
340 byte temp[32];
341 int blocksize, nprefix;
342 int i, c;
343 gcry_error_t err;
344
345 if (!cfx || !in)
346 return CDK_Inv_Value;
347
348 dek = cfx->dek;
349 blocksize = gcry_cipher_get_algo_blklen (dek->algo);
350 if (blocksize < 8 || blocksize > 16)
351 return CDK_Inv_Algo;
352
353 nprefix = blocksize;
354 if (cfx->datalen > 0 && cfx->datalen < (nprefix + 2))
355 return CDK_Inv_Value;
356 if (cfx->mdc_method)
357 {
358 err = gcry_md_open (&cfx->mdc, cfx->mdc_method, 0);
359 if (err)
360 return map_gcry_error (err);
361 }
362 err = gcry_cipher_open (&cfx->hd, dek->algo, GCRY_CIPHER_MODE_CFB,
363 cfx->mdc_method ? 0 : GCRY_CIPHER_ENABLE_SYNC);
364 if (err)
365 return map_gcry_error (err);
366 err = gcry_cipher_setiv (cfx->hd, NULL, 0);
367 if (err)
368 return map_gcry_error (err);
369 err = gcry_cipher_setkey (cfx->hd, dek->key, dek->keylen);
370 if (err)
371 return map_gcry_error (err);
372
373 for (i = 0; i < (nprefix + 2); i++)
374 {
375 c = fgetc (in);
376 if (c == EOF)
377 return CDK_File_Error;
378 temp[i] = c;
379 }
380 gcry_cipher_decrypt (cfx->hd, temp, nprefix + 2, NULL, 0);
381 gcry_cipher_sync (cfx->hd);
382 i = nprefix;
383 if (temp[i - 2] != temp[i] || temp[i - 1] != temp[i + 1])
384 return CDK_Chksum_Error;
385 if (cfx->mdc)
386 gcry_md_write (cfx->mdc, temp, nprefix + 2);
387 if (cfx->blkmode.on)
388 cfx->blkmode.size -= (nprefix + 2);
389 return 0;
390}
391
392
393static cdk_error_t
394finalize_mdc (gcry_md_hd_t md, const byte * buf, size_t nread)
395{
396 byte mdcbuf[20];
397 int dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
398 cdk_error_t rc;
399
400 if (dlen != 20)
401 return CDK_Inv_Algo;
402
403 if (buf[nread - dlen - 2] == 0xD3 && buf[nread - dlen - 1] == 0x14)
404 {
405 gcry_md_write (md, buf, nread - dlen);
406 gcry_md_final (md);
407 memcpy (mdcbuf, gcry_md_read (md, GCRY_MD_SHA1), dlen);
408 if (memcmp (mdcbuf, buf + nread - dlen, dlen))
409 rc = CDK_Bad_MDC;
410 else
411 rc = CDK_Success;
412 wipemem (mdcbuf, sizeof (mdcbuf));
413 return rc;
414 }
415
416 return CDK_Inv_Packet;
417}
418
419
420static cdk_error_t
421cipher_decode_file (void *opaque, FILE * in, FILE * out)
422{
423 cipher_filter_t *cfx = opaque;
424 cdk_error_t rc;
425 byte buf[BUFSIZE];
426 int nread, nreq;
427
428 if (!cfx || !in || !out)
429 return CDK_Inv_Value;
430
431 while (!feof (in))
432 {
433 /*_cdk_log_debug ("partial on=%d size=%lu\n",
434 cfx->blkmode.on, cfx->blkmode.size);*/
435 nreq = cfx->blkmode.on ? cfx->blkmode.size : DIM (buf);
436 nread = fread (buf, 1, nreq, in);
437 if (!nread)
438 break;
439 gcry_cipher_decrypt (cfx->hd, buf, nread, NULL, 0);
440 if (feof (in) && cfx->mdc)
441 {
442 rc = finalize_mdc (cfx->mdc, buf, nread);
443 if (rc)
444 {
445 wipemem (buf, sizeof (buf));
446 return rc;
447 }
448 /* We need to correct the size here to avoid the MDC
449 packet will be written to the output. */
450 nread -= 22;
451 }
452 else if (cfx->mdc)
453 gcry_md_write (cfx->mdc, buf, nread);
454 fwrite (buf, 1, nread, out);
455 if (cfx->blkmode.on)
456 {
457 cfx->blkmode.size = _cdk_pkt_read_len (in, &cfx->blkmode.on);
458 if (cfx->blkmode.size == (size_t) EOF)
459 return CDK_Inv_Packet;
460 }
461 }
462
463 wipemem (buf, sizeof (buf));
464 return 0;
465}
466
467
468static cdk_error_t
469cipher_decode (void *opaque, FILE * in, FILE * out)
470{
471 cipher_filter_t *cfx = opaque;
472 cdk_error_t rc;
473
474 _cdk_log_debug ("cipher filter: decode\n");
475
476 if (!cfx || !in || !out)
477 return CDK_Inv_Value;
478
479 rc = read_header (cfx, in);
480 if (!rc)
481 rc = cipher_decode_file (cfx, in, out);
482 return rc;
483}
484
485
486static cdk_error_t
487cipher_encode (void *opaque, FILE * in, FILE * out)
488{
489 cipher_filter_t *cfx = opaque;
490 cdk_error_t rc;
491
492 _cdk_log_debug ("cipher filter: encode\n");
493
494 if (!cfx || !in || !out)
495 return CDK_Inv_Value;
496
497 cfx->datalen = fp_get_length (in);
498 if (cfx->datalen < BUFSIZE && cfx->blkmode.on)
499 cfx->blkmode.on = 0;
500 rc = write_header (cfx, out);
501 if (!rc)
502 rc = cipher_encode_file (cfx, in, out);
503 return rc;
504}
505
506
507cdk_error_t
508_cdk_filter_cipher (void *opaque, int ctl, FILE * in, FILE * out)
509{
510 if (ctl == STREAMCTL_READ)
511 return cipher_decode (opaque, in, out);
512 else if (ctl == STREAMCTL_WRITE)
513 return cipher_encode (opaque, in, out);
514 else if (ctl == STREAMCTL_FREE)
515 {
516 cipher_filter_t *cfx = opaque;
517 if (cfx)
518 {
519 _cdk_log_debug ("free cipher filter\n");
520 gcry_md_close (cfx->mdc);
521 cfx->mdc = NULL;
522 gcry_cipher_close (cfx->hd);
523 cfx->hd = NULL;
524 return 0;
525 }
526 }
527 return CDK_Inv_Mode;
528}
diff --git a/src/daemon/https/opencdk/compress.c b/src/daemon/https/opencdk/compress.c
new file mode 100644
index 00000000..a984f38d
--- /dev/null
+++ b/src/daemon/https/opencdk/compress.c
@@ -0,0 +1,238 @@
1/* compress.c - Compression filters
2 * Copyright (C) 2002, 2003 Timo Schulz
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdio.h>
21#include <time.h>
22#ifdef HAVE_LIBZ
23# include <zlib.h>
24#endif
25
26#include "opencdk.h"
27#include "main.h"
28#include "filters.h"
29
30#ifdef HAVE_LIBZ
31static int
32compress_data (z_stream * zs, int flush, byte * inbuf, size_t insize,
33 FILE * out)
34{
35 int nbytes, zrc;
36 byte buf[4096];
37
38 zs->next_in = inbuf;
39 zs->avail_in = insize;
40
41 do
42 {
43 zs->next_out = buf;
44 zs->avail_out = DIM (buf);
45
46 zrc = deflate (zs, flush);
47 if (zrc == Z_STREAM_END && flush == Z_FINISH)
48 ;
49 else if (zrc != Z_OK)
50 break;
51 nbytes = DIM (buf) - zs->avail_out;
52 fwrite (buf, 1, nbytes, out);
53 }
54 while (zs->avail_out == 0 || (flush == Z_FINISH && zrc != Z_STREAM_END));
55 return zrc;
56}
57
58
59static int
60decompress_data (compress_filter_t * zfx, z_stream * zs,
61 FILE * in, size_t * ret_len)
62{
63 int nread, nold;
64 int rc, zrc;
65
66 rc = 0;
67 nread = 0;
68 while (zs->avail_out != 0)
69 {
70 if (!zs->avail_in)
71 {
72 nread = fread (zfx->inbuf, 1, zfx->inbufsize, in);
73 zs->next_in = zfx->inbuf;
74 zs->avail_in = nread;
75 }
76 nold = zs->avail_out;
77 zrc = inflate (zs, Z_SYNC_FLUSH);
78 if (zrc != Z_OK && zrc != Z_STREAM_END)
79 {
80 rc = CDK_Zlib_Error;
81 break;
82 }
83 *ret_len = zfx->outbufsize - zs->avail_out;
84 if (nold == zs->avail_out)
85 break;
86 if (zrc == Z_STREAM_END)
87 {
88 rc = EOF; /* eof */
89 break;
90 }
91 }
92 if (!nread && feof (in))
93 rc = -1;
94 return rc;
95}
96
97
98static cdk_error_t
99compress_decode (void *opaque, FILE * in, FILE * out)
100{
101 compress_filter_t *zfx = opaque;
102 z_stream *zs;
103 size_t nbytes;
104 int zrc;
105 cdk_error_t rc = 0;
106
107 _cdk_log_debug ("compress filter: decode (algo=%d)\n", zfx->algo);
108
109 if (!zfx || !in || !out)
110 return CDK_Inv_Value;
111
112 zs = cdk_calloc (1, sizeof *zs);
113 if (!zs)
114 return CDK_Out_Of_Core;
115 if (zfx->algo == CDK_COMPRESS_ZIP)
116 zrc = inflateInit2 (zs, -13);
117 else
118 zrc = inflateInit (zs);
119 if (zrc != Z_OK)
120 return CDK_Zlib_Error;
121
122 zfx->outbufsize = 8192;
123 zfx->inbufsize = 2048;
124 memset (zfx->inbuf, 0, sizeof zfx->inbuf);
125 zs->avail_in = 0;
126
127 nbytes = 0;
128 while (rc != -1)
129 {
130 zs->next_out = zfx->outbuf;
131 zs->avail_out = 8192;
132 rc = decompress_data (zfx, zs, in, &nbytes);
133 fwrite (zfx->outbuf, 1, nbytes, out);
134 }
135 inflateEnd (zs);
136 cdk_free (zs);
137 if (rc == CDK_EOF)
138 rc = 0;
139 return rc;
140}
141
142
143static cdk_error_t
144compress_encode (void *opaque, FILE * in, FILE * out)
145{
146 compress_filter_t *zfx = opaque;
147 z_stream *zs;
148 struct cdk_pkt_compressed_s cd;
149 struct cdk_packet_s pkt;
150 int zrc, nread;
151 cdk_error_t rc;
152
153 _cdk_log_debug ("compress filter: encode\n");
154
155 if (!zfx || !in || !out)
156 return CDK_Inv_Value;
157
158 if (!zfx->algo)
159 zfx->algo = CDK_COMPRESS_ZIP;
160
161 memset (&cd, 0, sizeof (cd));
162 cd.len = 0;
163 cd.algorithm = zfx->algo;
164 pkt.pkttype = CDK_PKT_COMPRESSED;
165 pkt.pkt.compressed = &cd;
166 rc = _cdk_pkt_write_fp (out, &pkt);
167 if (rc)
168 return rc;
169
170 zs = cdk_calloc (1, sizeof *zs);
171 if (!zs)
172 return CDK_Out_Of_Core;
173 if (zfx->algo == CDK_COMPRESS_ZIP)
174 rc = deflateInit2 (zs, zfx->level, Z_DEFLATED, -13, 8,
175 Z_DEFAULT_STRATEGY);
176 else
177 rc = deflateInit (zs, zfx->level);
178 if (rc != Z_OK)
179 {
180 cdk_free (zs);
181 return CDK_Zlib_Error;
182 }
183 zfx->outbufsize = 8192;
184 memset (zfx->outbuf, 0, sizeof zfx->outbuf);
185
186 while (!feof (in))
187 {
188 nread = fread (zfx->outbuf, 1, zfx->outbufsize, in);
189 if (!nread)
190 break;
191 zrc = compress_data (zs, Z_NO_FLUSH, zfx->outbuf, nread, out);
192 if (zrc)
193 {
194 rc = CDK_Zlib_Error;
195 break;
196 }
197 }
198 if (!rc)
199 {
200 nread = 0;
201 zrc = compress_data (zs, Z_FINISH, zfx->outbuf, nread, out);
202 if (zrc != Z_STREAM_END)
203 rc = CDK_Zlib_Error;
204 }
205 deflateEnd (zs);
206 cdk_free (zs);
207 return rc;
208}
209
210
211cdk_error_t
212_cdk_filter_compress (void *opaque, int ctl, FILE * in, FILE * out)
213{
214 if (ctl == STREAMCTL_READ)
215 return compress_decode (opaque, in, out);
216 else if (ctl == STREAMCTL_WRITE)
217 return compress_encode (opaque, in, out);
218 else if (ctl == STREAMCTL_FREE)
219 {
220 compress_filter_t *zfx = opaque;
221 if (zfx)
222 {
223 _cdk_log_debug ("free compress filter\n");
224 zfx->level = 0;
225 zfx->algo = 0;
226 return 0;
227 }
228 }
229 return CDK_Inv_Mode;
230}
231
232#else
233cdk_error_t
234_cdk_filter_compress (void *opaque, int ctl, FILE * in, FILE * out)
235{
236 return CDK_Not_Implemented;
237}
238#endif /* HAVE_LIBZ */
diff --git a/src/daemon/https/opencdk/context.h b/src/daemon/https/opencdk/context.h
new file mode 100644
index 00000000..e6569523
--- /dev/null
+++ b/src/daemon/https/opencdk/context.h
@@ -0,0 +1,120 @@
1/* context.h
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifndef CDK_CONTEXT_H
17#define CDK_CONTEXT_H
18
19#include "types.h"
20
21struct cdk_listkey_s {
22 unsigned init:1;
23 cdk_stream_t inp;
24 cdk_keydb_hd_t db;
25 int type;
26 union {
27 char *patt;
28 cdk_strlist_t fpatt;
29 } u;
30 cdk_strlist_t t;
31};
32
33
34struct cdk_s2k_s {
35 int mode;
36 byte hash_algo;
37 byte salt[8];
38 u32 count;
39};
40
41
42struct cdk_ctx_s {
43 int cipher_algo;
44 int digest_algo;
45 struct {
46 int algo;
47 int level;
48 } compress;
49 struct {
50 int mode;
51 int digest_algo;
52 } _s2k;
53 struct {
54 unsigned blockmode:1;
55 unsigned armor:1;
56 unsigned textmode:1;
57 unsigned compress:1;
58 unsigned mdc:1;
59 unsigned overwrite;
60 unsigned force_digest:1;
61 } opt;
62 struct {
63 cdk_verify_result_t verify;
64 } result;
65 struct {
66 cdk_pkt_seckey_t sk;
67 unsigned on:1;
68 } cache;
69 cdk_dek_t dek;
70 struct {
71 cdk_keydb_hd_t sec;
72 cdk_keydb_hd_t pub;
73 unsigned int close_db:1;
74 } db;
75 char *(*passphrase_cb) (void *opaque, const char *prompt);
76 void * passphrase_cb_value;
77};
78
79struct cdk_prefitem_s {
80 byte type;
81 byte value;
82};
83
84struct cdk_desig_revoker_s {
85 struct cdk_desig_revoker_s * next;
86 byte r_class;
87 byte algid;
88 byte fpr[KEY_FPR_LEN];
89};
90
91struct cdk_subpkt_s {
92 struct cdk_subpkt_s * next;
93 u32 size;
94 byte type;
95 byte d[1];
96};
97
98struct cdk_keylist_s {
99 struct cdk_keylist_s * next;
100 union {
101 cdk_pkt_pubkey_t pk;
102 cdk_pkt_seckey_t sk;
103 } key;
104 int version;
105 int type;
106};
107
108struct cdk_dek_s {
109 int algo;
110 int keylen;
111 int use_mdc;
112 byte key[32]; /* 256-bit */
113};
114
115struct cdk_strlist_s {
116 struct cdk_strlist_s * next;
117 char d[1];
118};
119
120#endif /* CDK_CONTEXT_H */
diff --git a/src/daemon/https/opencdk/dummy.c b/src/daemon/https/opencdk/dummy.c
new file mode 100644
index 00000000..2132f2d9
--- /dev/null
+++ b/src/daemon/https/opencdk/dummy.c
@@ -0,0 +1,15 @@
1#include <stdio.h>
2#include <string.h>
3
4#include "opencdk.h"
5#include "main.h"
6#include "filters.h"
7#include "packet.h"
8
9cdk_error_t
10_cdk_proc_packets (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t data,
11 const char *output, cdk_stream_t outstream,
12 gcry_md_hd_t md)
13{
14 return 0;
15}
diff --git a/src/daemon/https/opencdk/filters.h b/src/daemon/https/opencdk/filters.h
new file mode 100644
index 00000000..a60881ed
--- /dev/null
+++ b/src/daemon/https/opencdk/filters.h
@@ -0,0 +1,95 @@
1/* filters.h - Filter structs
2 * Copyright (C) 2002, 2003 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifndef CDK_FILTERS_H
17#define CDK_FILTERS_H
18
19enum {
20 STREAMCTL_READ = 0,
21 STREAMCTL_WRITE = 1,
22 STREAMCTL_FREE = 2
23};
24
25typedef struct {
26 gcry_cipher_hd_t hd;
27 gcry_md_hd_t mdc;
28 int mdc_method;
29 cdk_dek_t dek;
30 u32 datalen;
31 struct {
32 size_t on;
33 off_t size;
34 off_t nleft;
35 } blkmode;
36 cdk_stream_t s;
37} cipher_filter_t;
38
39typedef struct {
40 int digest_algo;
41 gcry_md_hd_t md;
42} md_filter_t;
43
44typedef struct {
45 const char *le; /* line endings */
46 const char *hdrlines;
47 u32 crc;
48 int crc_okay;
49 int idx, idx2;
50} armor_filter_t;
51
52typedef struct {
53 cdk_lit_format_t mode;
54 char *orig_filename; /* This original name of the input file. */
55 char *filename;
56 gcry_md_hd_t md;
57 struct {
58 size_t on;
59 off_t size;
60 } blkmode;
61} literal_filter_t;
62
63typedef struct {
64 size_t inbufsize;
65 byte inbuf[8192];
66 size_t outbufsize;
67 byte outbuf[8192];
68 int algo; /* compress algo */
69 int level;
70} compress_filter_t;
71
72typedef struct {
73 const char * lf;
74} text_filter_t;
75
76
77/*-- armor.c -*/
78int _cdk_filter_armor( void * opaque, int ctl, FILE * in, FILE * out );
79
80/*-- cipher.c --*/
81cdk_error_t _cdk_filter_hash( void * opaque, int ctl, FILE * in, FILE * out );
82cdk_error_t _cdk_filter_cipher( void * opaque, int ctl,
83 FILE * in, FILE * out );
84
85/*-- literal.c --*/
86int _cdk_filter_literal( void * opaque, int ctl, FILE * in, FILE * out );
87int _cdk_filter_text( void * opaque, int ctl, FILE * in, FILE * out );
88
89/*-- compress.c --*/
90cdk_error_t _cdk_filter_compress( void * opaque, int ctl,
91 FILE * in, FILE * out );
92
93#endif /* CDK_FILTERS_H */
94
95
diff --git a/src/daemon/https/opencdk/kbnode.c b/src/daemon/https/opencdk/kbnode.c
new file mode 100644
index 00000000..9028c24b
--- /dev/null
+++ b/src/daemon/https/opencdk/kbnode.c
@@ -0,0 +1,581 @@
1/* kbnode.c - keyblock node utility functions
2 * Copyright (C) 1998-2001 Free Software Foundation, Inc.
3 * Copyright (C) 2002, 2003, 2007 Timo Schulz
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <assert.h>
24
25#include "opencdk.h"
26#include "main.h"
27#include "packet.h"
28
29
30/**
31 * cdk_kbnode_new:
32 * @pkt: the packet to add
33 *
34 * Allocate a new key node and add the packet.
35 **/
36cdk_kbnode_t
37cdk_kbnode_new (cdk_packet_t pkt)
38{
39 cdk_kbnode_t n;
40
41 n = cdk_calloc (1, sizeof *n);
42 if (!n)
43 return NULL;
44 n->pkt = pkt;
45 return n;
46}
47
48
49void
50_cdk_kbnode_clone (cdk_kbnode_t node)
51{
52 /* Mark the node as clone which means that the packet
53 will not be freed, just the node itself. */
54 if (node)
55 node->is_cloned = 1;
56}
57
58
59/**
60 * cdk_kbnode_release:
61 * @n: the key node
62 *
63 * Release the memory of the node.
64 **/
65void
66cdk_kbnode_release (cdk_kbnode_t node)
67{
68 cdk_kbnode_t n2;
69
70 while (node)
71 {
72 n2 = node->next;
73 if (!node->is_cloned)
74 cdk_pkt_release (node->pkt);
75 cdk_free (node);
76 node = n2;
77 }
78}
79
80
81/**
82 * cdk_kbnode_delete:
83 * @node: the key node
84 *
85 * Mark the given node as deleted.
86 **/
87void
88cdk_kbnode_delete (cdk_kbnode_t node)
89{
90 if (node)
91 node->is_deleted = 1;
92}
93
94
95/* Append NODE to ROOT. ROOT must exist! */
96void
97_cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node)
98{
99 cdk_kbnode_t n1;
100
101 for (n1 = root; n1->next; n1 = n1->next)
102 ;
103 n1->next = node;
104}
105
106
107/**
108 * cdk_kbnode_insert:
109 * @root: the root key node
110 * @node: the node to add
111 * @pkttype: packet type
112 *
113 * Insert @node into the list after @root but before a packet which is not of
114 * type @pkttype (only if @pkttype != 0).
115 **/
116void
117cdk_kbnode_insert (cdk_kbnode_t root, cdk_kbnode_t node, int pkttype)
118{
119 if (!pkttype)
120 {
121 node->next = root->next;
122 root->next = node;
123 }
124 else
125 {
126 cdk_kbnode_t n1;
127
128 for (n1 = root; n1->next; n1 = n1->next)
129 if (pkttype != n1->next->pkt->pkttype)
130 {
131 node->next = n1->next;
132 n1->next = node;
133 return;
134 }
135 /* No such packet, append */
136 node->next = NULL;
137 n1->next = node;
138 }
139}
140
141
142/**
143 * cdk_kbnode_find_prev:
144 * @root: the root key node
145 * @node: the key node
146 * @pkttype: packet type
147 *
148 * Find the previous node (if @pkttype = 0) or the previous node
149 * with pkttype @pkttype in the list starting with @root of @node.
150 **/
151cdk_kbnode_t
152cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node, int pkttype)
153{
154 cdk_kbnode_t n1;
155
156 for (n1 = NULL; root && root != node; root = root->next)
157 {
158 if (!pkttype || root->pkt->pkttype == pkttype)
159 n1 = root;
160 }
161 return n1;
162}
163
164
165/**
166 * cdk_kbnode_find_next:
167 * @node: the key node
168 * @pkttype: packet type
169 *
170 * Ditto, but find the next packet. The behaviour is trivial if
171 * @pkttype is 0 but if it is specified, the next node with a packet
172 * of this type is returned. The function has some knowledge about
173 * the valid ordering of packets: e.g. if the next signature packet
174 * is requested, the function will not return one if it encounters
175 * a user-id.
176 **/
177cdk_kbnode_t
178cdk_kbnode_find_next (cdk_kbnode_t node, int pkttype)
179{
180 for (node = node->next; node; node = node->next)
181 {
182 if (!pkttype)
183 return node;
184 else if (pkttype == CDK_PKT_USER_ID &&
185 (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
186 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
187 return NULL;
188 else if (pkttype == CDK_PKT_SIGNATURE &&
189 (node->pkt->pkttype == CDK_PKT_USER_ID ||
190 node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
191 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
192 return NULL;
193 else if (node->pkt->pkttype == pkttype)
194 return node;
195 }
196 return NULL;
197}
198
199
200/**
201 * cdk_kbnode_find:
202 * @node: the key node
203 * @pkttype: packet type
204 *
205 * Try to find the next node with the packettype @pkttype.
206 **/
207cdk_kbnode_t
208cdk_kbnode_find (cdk_kbnode_t node, int pkttype)
209{
210 for (; node; node = node->next)
211 {
212 if (node->pkt->pkttype == pkttype)
213 return node;
214 }
215 return NULL;
216}
217
218
219/**
220 * cdk_kbnode_find_packet:
221 * @node: the key node
222 * @pkttype: packet type
223 *
224 * Same as cdk_kbnode_find but it returns the packet instead of the node.
225 **/
226cdk_packet_t
227cdk_kbnode_find_packet (cdk_kbnode_t node, int pkttype)
228{
229 cdk_kbnode_t res;
230
231 res = cdk_kbnode_find (node, pkttype);
232 return res ? res->pkt : NULL;
233}
234
235
236/****************
237 * Walk through a list of kbnodes. This function returns
238 * the next kbnode for each call; before using the function the first
239 * time, the caller must set CONTEXT to NULL (This has simply the effect
240 * to start with ROOT).
241 */
242cdk_kbnode_t
243cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * context, int all)
244{
245 cdk_kbnode_t n;
246
247 do
248 {
249 if (!*context)
250 {
251 *context = root;
252 n = root;
253 }
254 else
255 {
256 n = (*context)->next;
257 *context = n;
258 }
259 }
260 while (!all && n && n->is_deleted);
261 return n;
262}
263
264
265/**
266 * cdk_kbnode_commit:
267 * @root: the nodes
268 *
269 * Commit changes made to the kblist at ROOT. Note that ROOT my change,
270 * and it is therefore passed by reference.
271 * The function has the effect of removing all nodes marked as deleted.
272 * returns true if any node has been changed
273 */
274int
275cdk_kbnode_commit (cdk_kbnode_t * root)
276{
277 cdk_kbnode_t n, nl;
278 int changed = 0;
279
280 for (n = *root, nl = NULL; n; n = nl->next)
281 {
282 if (n->is_deleted)
283 {
284 if (n == *root)
285 *root = nl = n->next;
286 else
287 nl->next = n->next;
288 if (!n->is_cloned)
289 cdk_pkt_release (n->pkt);
290 cdk_free (n);
291 changed = 1;
292 }
293 else
294 nl = n;
295 }
296 return changed;
297}
298
299
300/**
301 * cdk_kbnode_remove:
302 * @root: the root node
303 * @node: the node to delete
304 *
305 * Remove a node from the root node.
306 */
307void
308cdk_kbnode_remove (cdk_kbnode_t * root, cdk_kbnode_t node)
309{
310 cdk_kbnode_t n, nl;
311
312 for (n = *root, nl = NULL; n; n = nl->next)
313 {
314 if (n == node)
315 {
316 if (n == *root)
317 *root = nl = n->next;
318 else
319 nl->next = n->next;
320 if (!n->is_cloned)
321 cdk_pkt_release (n->pkt);
322 cdk_free (n);
323 }
324 else
325 nl = n;
326 }
327}
328
329
330
331/**
332 * cdk_cdknode_move:
333 * @root: root node
334 * @node: the node to move
335 * @where: destination place where to move the node.
336 *
337 * Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
338 */
339void
340cdk_kbnode_move (cdk_kbnode_t * root, cdk_kbnode_t node, cdk_kbnode_t where)
341{
342 cdk_kbnode_t tmp, prev;
343
344 if (!root || !*root || !node)
345 return;
346 for (prev = *root; prev && prev->next != node; prev = prev->next)
347 ;
348 if (!prev)
349 return; /* Node is not in the list */
350
351 if (!where)
352 { /* Move node before root */
353 if (node == *root)
354 return;
355 prev->next = node->next;
356 node->next = *root;
357 *root = node;
358 return;
359 }
360 if (node == where) /* Move it after where. */
361 return;
362 tmp = node->next;
363 node->next = where->next;
364 where->next = node;
365 prev->next = tmp;
366}
367
368
369/**
370 * cdk_kbnode_get_packet:
371 * @node: the key node
372 *
373 * Return the packet which is stored inside the node in @node.
374 **/
375cdk_packet_t
376cdk_kbnode_get_packet (cdk_kbnode_t node)
377{
378 if (node)
379 return node->pkt;
380 return NULL;
381}
382
383
384/**
385 * cdk_kbnode_read_from_mem:
386 * @ret_node: the new key node
387 * @buf: the buffer which stores the key sequence
388 * @buflen: the length of the buffer
389 *
390 * Try to read a key node from the memory buffer @buf.
391 **/
392cdk_error_t
393cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
394 const byte * buf, size_t buflen)
395{
396 cdk_stream_t inp;
397 cdk_error_t rc;
398
399 if (!buflen || !ret_node || !buf)
400 return CDK_Inv_Value;
401
402 *ret_node = NULL;
403 rc = cdk_stream_tmp_from_mem (buf, buflen, &inp);
404 if (rc)
405 return rc;
406 rc = cdk_keydb_get_keyblock (inp, ret_node);
407 cdk_stream_close (inp);
408 return rc;
409}
410
411/**
412 * cdk_kbnode_write_to_mem_alloc:
413 * @node: the key node
414 * @r_buf: buffer to hold the raw data
415 * @r_buflen: buffer length of the allocated raw data.
416 *
417 * The function acts similar to cdk_kbnode_write_to_mem but
418 * it allocates the buffer to avoid the lengthy second run.
419 */
420cdk_error_t
421cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
422 byte ** r_buf, size_t * r_buflen)
423{
424 cdk_kbnode_t n;
425 cdk_stream_t s;
426 cdk_error_t rc;
427 size_t len;
428
429 if (!node)
430 return CDK_Inv_Value;
431
432 *r_buf = NULL;
433 *r_buflen = 0;
434
435 rc = cdk_stream_tmp_new (&s);
436 if (rc)
437 return rc;
438
439 for (n = node; n; n = n->next)
440 {
441 /* Skip all packets which cannot occur in a key composition. */
442 if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
443 n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
444 n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
445 n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
446 n->pkt->pkttype != CDK_PKT_SIGNATURE &&
447 n->pkt->pkttype != CDK_PKT_USER_ID &&
448 n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
449 continue;
450 rc = cdk_pkt_write (s, n->pkt);
451 if (rc)
452 {
453 cdk_stream_close (s);
454 return rc;
455 }
456 }
457
458 cdk_stream_seek (s, 0);
459 len = cdk_stream_get_length (s);
460 *r_buf = cdk_calloc (1, len);
461 *r_buflen = cdk_stream_read (s, *r_buf, len);
462 cdk_stream_close (s);
463 return 0;
464}
465
466
467/**
468 * cdk_kbnode_write_to_mem:
469 * @node: the key node
470 * @buf: the buffer to store the node data
471 * @r_nbytes: the new length of the buffer.
472 *
473 * Try to write the contents of the key node to the buffer @buf and
474 * return the length of it in @r_nbytes. If buf is zero, only the
475 * length of the node is calculated and returned in @r_nbytes.
476 * Whenever it is possible, the cdk_kbnode_write_to_mem_alloc should be used.
477 **/
478cdk_error_t
479cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes)
480{
481 cdk_kbnode_t n;
482 cdk_stream_t s;
483 size_t len;
484 cdk_error_t rc;
485
486 if (!node)
487 return CDK_Inv_Value;
488
489 rc = cdk_stream_tmp_new (&s);
490 if (rc)
491 return rc;
492
493 for (n = node; n; n = n->next)
494 {
495 /* Skip all packets which cannot occur in a key composition. */
496 if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
497 n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
498 n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
499 n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
500 n->pkt->pkttype != CDK_PKT_SIGNATURE &&
501 n->pkt->pkttype != CDK_PKT_USER_ID &&
502 n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
503 continue;
504 rc = cdk_pkt_write (s, n->pkt);
505 if (rc)
506 {
507 cdk_stream_close (s);
508 return rc;
509 }
510 }
511
512 cdk_stream_seek (s, 0);
513 len = cdk_stream_get_length (s);
514 if (!buf)
515 {
516 *r_nbytes = len; /* Only return the length of the buffer */
517 cdk_stream_close (s);
518 return 0;
519 }
520 if (*r_nbytes < len)
521 rc = CDK_Too_Short;
522 if (!rc)
523 *r_nbytes = cdk_stream_read (s, buf, len);
524 cdk_stream_close (s);
525 return rc;
526}
527
528
529/**
530 * cdk_kbnode_hash:
531 * @node: the key node
532 * @hashctx: opaque pointer to the hash context
533 * @is_v4: OpenPGP signature (yes=1, no=0)
534 * @pkttype: packet type to hash (if zero use the packet type from the node)
535 * @flags: flags which depend on the operation
536 *
537 * Hash the key node contents. Two modes are supported. If the packet
538 * type is used (!= 0) then the function searches the first node with
539 * this type. Otherwise the node is seen as a single node and the type
540 * is extracted from it.
541 **/
542cdk_error_t
543cdk_kbnode_hash (cdk_kbnode_t node, gcry_md_hd_t md, int is_v4,
544 int pkttype, int flags)
545{
546 cdk_packet_t pkt;
547
548 if (!node || !md)
549 return CDK_Inv_Value;
550 if (!pkttype)
551 {
552 pkt = cdk_kbnode_get_packet (node);
553 pkttype = pkt->pkttype;
554 }
555 else
556 {
557 pkt = cdk_kbnode_find_packet (node, pkttype);
558 if (!pkt)
559 return CDK_Inv_Packet;
560 }
561
562 switch (pkttype)
563 {
564 case CDK_PKT_PUBLIC_KEY:
565 case CDK_PKT_PUBLIC_SUBKEY:
566 _cdk_hash_pubkey (pkt->pkt.public_key, md, flags & 1);
567 break;
568
569 case CDK_PKT_USER_ID:
570 _cdk_hash_userid (pkt->pkt.user_id, is_v4, md);
571 break;
572
573 case CDK_PKT_SIGNATURE:
574 _cdk_hash_sig_data (pkt->pkt.signature, md);
575 break;
576
577 default:
578 return CDK_Inv_Mode;
579 }
580 return 0;
581}
diff --git a/src/daemon/https/opencdk/keydb.c b/src/daemon/https/opencdk/keydb.c
new file mode 100644
index 00000000..0553d3c3
--- /dev/null
+++ b/src/daemon/https/opencdk/keydb.c
@@ -0,0 +1,2303 @@
1/* keydb.c - Key database routines
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17# include <config.h>
18#endif
19#include <sys/stat.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <time.h>
24#include <ctype.h>
25
26#include "opencdk.h"
27#include "main.h"
28#include "packet.h"
29#include "filters.h"
30#include "stream.h"
31
32
33#define KEYID_CMP(a, b) ((a[0]) == (b[0]) && (a[1]) == (b[1]))
34#define KEYDB_CACHE_ENTRIES 8
35
36
37/* Internal key index structure. */
38struct key_idx_s
39{
40 off_t offset;
41 u32 keyid[2];
42 byte fpr[KEY_FPR_LEN];
43};
44typedef struct key_idx_s *key_idx_t;
45
46
47/* Internal handle for the search operation. */
48struct cdk_dbsearch_s
49{
50 union
51 {
52 char *pattern; /* A search is performed by pattern. */
53 u32 keyid[2]; /* A search by keyid. */
54 byte fpr[KEY_FPR_LEN]; /* A search by fingerprint. */
55 } u;
56 int type;
57};
58typedef struct cdk_dbsearch_s *cdk_dbsearch_t;
59
60/* Internal key cache to associate a key with an file offset. */
61struct key_table_s
62{
63 struct key_table_s *next;
64 off_t offset;
65 cdk_dbsearch_t desc;
66};
67typedef struct key_table_s *key_table_t;
68
69/* Internal key database handle. */
70struct cdk_keydb_hd_s
71{
72 int type; /* type of the key db handle. */
73 int fp_ref; /* 1=means it is a reference and shall not be closed. */
74 cdk_stream_t fp;
75 cdk_stream_t idx;
76 cdk_dbsearch_t dbs;
77 char *name; /* name of the underlying file or NULL. */
78 char *idx_name; /* name of the index file or NULL. */
79 struct key_table_s *cache;
80 size_t ncache;
81 unsigned int secret:1; /* contain secret keys. */
82 unsigned int isopen:1; /* the underlying stream is opened. */
83 unsigned int no_cache:1; /* disable the index cache. */
84 unsigned int search:1; /* handle is in search mode. */
85
86 /* structure to store some stats about the keydb. */
87 struct
88 {
89 size_t new_keys; /* amount of new keys that were imported. */
90 } stats;
91};
92
93
94static void keydb_cache_free (key_table_t cache);
95static int keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src);
96static void keydb_search_free (cdk_dbsearch_t dbs);
97static int classify_data (const byte * buf, size_t len);
98static cdk_kbnode_t find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk);
99
100
101static char *
102keydb_idx_mkname (const char *file)
103{
104 char *fname, *fmt;
105
106 fmt = "%s.idx";
107 fname = cdk_calloc (1, strlen (file) + strlen (fmt) + 1);
108 if (!fname)
109 return NULL;
110 sprintf (fname, fmt, file);
111 return fname;
112}
113
114
115/* This functions builds an index of the keyring into a separate file
116 with the name keyring.ext.idx. It contains the offset of all public-
117 and public subkeys. The format of the file is:
118 --------
119 4 octets offset of the packet
120 8 octets keyid
121 20 octets fingerprint
122 --------
123 We store the keyid and the fingerprint due to the fact we can't get
124 the keyid from a v3 fingerprint directly.
125*/
126static cdk_error_t
127keydb_idx_build (const char *file)
128{
129 cdk_packet_t pkt;
130 cdk_stream_t inp, out = NULL;
131 byte buf[4 + 8 + KEY_FPR_LEN];
132 char *idx_name;
133 u32 keyid[2];
134 cdk_error_t rc;
135
136 if (!file)
137 return CDK_Inv_Value;
138
139 rc = cdk_stream_open (file, &inp);
140 if (rc)
141 return rc;
142
143 idx_name = keydb_idx_mkname (file);
144 if (!idx_name)
145 {
146 cdk_stream_close (inp);
147 return CDK_Out_Of_Core;
148 }
149 rc = cdk_stream_create (idx_name, &out);
150 cdk_free (idx_name);
151 if (rc)
152 {
153 cdk_stream_close (inp);
154 return rc;
155 }
156
157 cdk_pkt_new (&pkt);
158 while (!cdk_stream_eof (inp))
159 {
160 off_t pos = cdk_stream_tell (inp);
161
162 rc = cdk_pkt_read (inp, pkt);
163 if (rc)
164 {
165 _cdk_log_debug ("index build failed packet off=%lu\n", pos);
166 /* FIXME: The index is incomplete */
167 break;
168 }
169 if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
170 pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
171 {
172 _cdk_u32tobuf (pos, buf);
173 cdk_pk_get_keyid (pkt->pkt.public_key, keyid);
174 _cdk_u32tobuf (keyid[0], buf + 4);
175 _cdk_u32tobuf (keyid[1], buf + 8);
176 cdk_pk_get_fingerprint (pkt->pkt.public_key, buf + 12);
177 cdk_stream_write (out, buf, 4 + 8 + KEY_FPR_LEN);
178 }
179 cdk_pkt_free (pkt);
180 }
181
182 cdk_pkt_release (pkt);
183
184 cdk_stream_close (out);
185 cdk_stream_close (inp);
186 return rc;
187}
188
189
190/**
191 * cdk_keydb_idx_rebuild:
192 * @hd: key database handle
193 *
194 * Rebuild the key index files for the given key database.
195 **/
196cdk_error_t
197cdk_keydb_idx_rebuild (cdk_keydb_hd_t db)
198{
199 struct stat stbuf;
200 char *tmp_idx_name;
201 cdk_error_t rc;
202 int err;
203
204 if (!db || !db->name)
205 return CDK_Inv_Value;
206 if (db->secret)
207 return 0;
208
209 tmp_idx_name = keydb_idx_mkname (db->name);
210 if (!tmp_idx_name)
211 return CDK_Out_Of_Core;
212 err = stat (tmp_idx_name, &stbuf);
213 cdk_free (tmp_idx_name);
214 /* This function expects an existing index which can be rebuild,
215 if no index exists we do not build one and just return. */
216 if (err)
217 return 0;
218
219 cdk_stream_close (db->idx);
220 db->idx = NULL;
221 if (!db->idx_name)
222 {
223 db->idx_name = keydb_idx_mkname (db->name);
224 if (!db->idx_name)
225 return CDK_Out_Of_Core;
226 }
227 rc = keydb_idx_build (db->name);
228 if (!rc)
229 rc = cdk_stream_open (db->idx_name, &db->idx);
230 return rc;
231}
232
233
234static cdk_error_t
235keydb_idx_parse (cdk_stream_t inp, key_idx_t * r_idx)
236{
237 key_idx_t idx;
238 byte buf[4];
239
240 if (!inp || !r_idx)
241 return CDK_Inv_Value;
242
243 idx = cdk_calloc (1, sizeof *idx);
244 if (!idx)
245 return CDK_Out_Of_Core;
246
247 while (!cdk_stream_eof (inp))
248 {
249 if (cdk_stream_read (inp, buf, 4) == CDK_EOF)
250 break;
251 idx->offset = _cdk_buftou32 (buf);
252 cdk_stream_read (inp, buf, 4);
253 idx->keyid[0] = _cdk_buftou32 (buf);
254 cdk_stream_read (inp, buf, 4);
255 idx->keyid[1] = _cdk_buftou32 (buf);
256 cdk_stream_read (inp, idx->fpr, KEY_FPR_LEN);
257 break;
258 }
259 *r_idx = idx;
260 return cdk_stream_eof (inp) ? CDK_EOF : 0;
261}
262
263
264static cdk_error_t
265keydb_idx_search (cdk_stream_t inp, u32 * keyid, const byte * fpr,
266 off_t * r_off)
267{
268 key_idx_t idx;
269
270 if (!inp || !r_off)
271 return CDK_Inv_Value;
272 if ((keyid && fpr) || (!keyid && !fpr))
273 return CDK_Inv_Mode;
274
275 /* We need an initialize the offset var with a value
276 because it might be possible the returned offset will
277 be 0 and then we cannot differ between the begin and an EOF. */
278 *r_off = 0xFFFFFFFF;
279 cdk_stream_seek (inp, 0);
280 while (keydb_idx_parse (inp, &idx) != CDK_EOF)
281 {
282 if (keyid && KEYID_CMP (keyid, idx->keyid))
283 {
284 *r_off = idx->offset;
285 break;
286 }
287 else if (fpr && !memcmp (idx->fpr, fpr, KEY_FPR_LEN))
288 {
289 *r_off = idx->offset;
290 break;
291 }
292 cdk_free (idx);
293 idx = NULL;
294 }
295 cdk_free (idx);
296 return *r_off != 0xFFFFFFFF ? 0 : CDK_EOF;
297}
298
299
300/**
301 * cdk_keydb_new_from_mem:
302 * @r_hd: The keydb output handle.
303 * @data: The raw key data.
304 * @datlen: The length of the raw data.
305 *
306 * Create a new keyring db handle from the contents of a buffer.
307 */
308cdk_error_t
309cdk_keydb_new_from_mem (cdk_keydb_hd_t * r_db, int secret,
310 const void *data, size_t datlen)
311{
312 cdk_keydb_hd_t db;
313 cdk_error_t rc;
314
315 if (!r_db)
316 return CDK_Inv_Value;
317 *r_db = NULL;
318 db = calloc (1, sizeof *db);
319 rc = cdk_stream_tmp_from_mem (data, datlen, &db->fp);
320 if (!db->fp)
321 {
322 cdk_free (db);
323 return rc;
324 }
325 if (cdk_armor_filter_use (db->fp))
326 cdk_stream_set_armor_flag (db->fp, 0);
327 db->type = CDK_DBTYPE_DATA;
328 db->secret = secret;
329 *r_db = db;
330 return 0;
331}
332
333
334/**
335 * cdk_keydb_new_from_stream:
336 * @r_hd: the output keydb handle
337 * @secret: does the stream contain secret key data
338 * @in: the input stream to use
339 *
340 * This function creates a new keydb handle based on the given
341 * stream. The stream is not closed in cdk_keydb_free() and it
342 * is up to the caller to close it. No decoding is done.
343 */
344cdk_error_t
345cdk_keydb_new_from_stream (cdk_keydb_hd_t * r_hd, int secret, cdk_stream_t in)
346{
347 cdk_keydb_hd_t hd;
348
349 if (!r_hd)
350 return CDK_Inv_Value;
351 *r_hd = NULL;
352
353 hd = calloc (1, sizeof *hd);
354 hd->fp = in;
355 hd->fp_ref = 1;
356 hd->type = CDK_DBTYPE_STREAM;
357 hd->secret = secret;
358 *r_hd = hd;
359
360 /* We do not push any filters and thus we expect that the format
361 of the stream has the format the user wanted. */
362
363 return 0;
364}
365
366
367cdk_error_t
368cdk_keydb_new_from_file (cdk_keydb_hd_t * r_hd, int secret, const char *fname)
369{
370 cdk_keydb_hd_t hd;
371
372 if (!r_hd)
373 return CDK_Inv_Value;
374 *r_hd = NULL;
375 hd = calloc (1, sizeof *hd);
376 hd->name = cdk_strdup (fname);
377 if (!hd->name)
378 {
379 cdk_free (hd);
380 return CDK_Out_Of_Core;
381 }
382 hd->type = secret ? CDK_DBTYPE_SK_KEYRING : CDK_DBTYPE_PK_KEYRING;
383 hd->secret = secret;
384 *r_hd = hd;
385 return 0;
386}
387
388
389
390/**
391 * cdk_keydb_new:
392 * @r_hd: handle to store the new keydb object
393 * @type: type of the keyring
394 * @data: data which depends on the keyring type
395 * @count: length of the data
396 *
397 * Create a new keydb object
398 **/
399cdk_error_t
400cdk_keydb_new (cdk_keydb_hd_t * r_hd, int type, void *data, size_t count)
401{
402 switch (type)
403 {
404 case CDK_DBTYPE_PK_KEYRING:
405 case CDK_DBTYPE_SK_KEYRING:
406 return cdk_keydb_new_from_file (r_hd, type == CDK_DBTYPE_SK_KEYRING,
407 (const char *) data);
408
409 case CDK_DBTYPE_DATA:
410 return cdk_keydb_new_from_mem (r_hd, 0, data, count);
411
412 case CDK_DBTYPE_STREAM:
413 return cdk_keydb_new_from_stream (r_hd, 0, (cdk_stream_t) data);
414
415 default:
416 return CDK_Inv_Mode;
417 }
418 return CDK_Inv_Mode;
419}
420
421
422/**
423 * cdk_keydb_free:
424 * @hd: the keydb object
425 *
426 * Free the keydb object.
427 **/
428void
429cdk_keydb_free (cdk_keydb_hd_t hd)
430{
431 if (!hd)
432 return;
433
434 if (hd->name)
435 {
436 cdk_free (hd->name);
437 hd->name = NULL;
438 }
439
440 if (hd->fp && !hd->fp_ref)
441 {
442 cdk_stream_close (hd->fp);
443 hd->fp = NULL;
444 }
445
446 if (hd->idx)
447 {
448 cdk_stream_close (hd->idx);
449 hd->idx = NULL;
450 }
451
452 hd->isopen = 0;
453 hd->no_cache = 0;
454 hd->secret = 0;
455 keydb_cache_free (hd->cache);
456 hd->cache = NULL;
457 keydb_search_free (hd->dbs);
458 hd->dbs = NULL;
459 cdk_free (hd);
460}
461
462
463cdk_error_t
464_cdk_keydb_open (cdk_keydb_hd_t hd, cdk_stream_t * ret_kr)
465{
466 cdk_error_t rc, ec;
467
468 if (!hd || !ret_kr)
469 return CDK_Inv_Value;
470
471 rc = 0;
472 if ((hd->type == CDK_DBTYPE_DATA || hd->type == CDK_DBTYPE_STREAM)
473 && hd->fp)
474 cdk_stream_seek (hd->fp, 0);
475 else if (hd->type == CDK_DBTYPE_PK_KEYRING ||
476 hd->type == CDK_DBTYPE_SK_KEYRING)
477 {
478 if (!hd->isopen && hd->name)
479 {
480 rc = cdk_stream_open (hd->name, &hd->fp);
481 if (rc)
482 goto leave;
483 if (cdk_armor_filter_use (hd->fp))
484 cdk_stream_set_armor_flag (hd->fp, 0);
485 hd->isopen = 1;
486 /* We disable the index cache for smaller keyrings. */
487 if (cdk_stream_get_length (hd->fp) < 524288)
488 {
489 hd->no_cache = 1;
490 goto leave;
491 }
492 cdk_free (hd->idx_name);
493 hd->idx_name = keydb_idx_mkname (hd->name);
494 if (!hd->idx_name)
495 {
496 rc = CDK_Out_Of_Core;
497 goto leave;
498 }
499 ec = cdk_stream_open (hd->idx_name, &hd->idx);
500 if (ec && !hd->secret)
501 {
502 rc = keydb_idx_build (hd->name);
503 if (!rc)
504 rc = cdk_stream_open (hd->idx_name, &hd->idx);
505 if (!rc)
506 _cdk_log_debug ("create key index table\n");
507 else
508 {
509 /* This is no real error, it just means we can't create
510 the index at the given directory. maybe we've no write
511 access. in this case, we simply disable the index. */
512 _cdk_log_debug ("disable key index table err=%d\n", rc);
513 rc = 0;
514 hd->no_cache = 1;
515 }
516 }
517 }
518 else
519 {
520 /* We use the cache to search keys, so we always rewind the
521 STREAM. Except when the _NEXT search mode is used because
522 this mode is an enumeration and no seeking is needed. */
523 if (!hd->search ||
524 (hd->search && hd->dbs->type != CDK_DBSEARCH_NEXT))
525 cdk_stream_seek (hd->fp, 0);
526 }
527 }
528 else
529 return CDK_Inv_Mode;
530
531leave:
532 if (rc)
533 {
534 cdk_stream_close (hd->fp);
535 hd->fp = NULL;
536 }
537 *ret_kr = hd->fp;
538 return rc;
539}
540
541
542static int
543find_by_keyid (cdk_kbnode_t knode, cdk_dbsearch_t ks)
544{
545 cdk_kbnode_t node;
546 u32 keyid[2];
547
548 for (node = knode; node; node = node->next)
549 {
550 if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
551 node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
552 node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
553 node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
554 {
555 _cdk_pkt_get_keyid (node->pkt, keyid);
556 switch (ks->type)
557 {
558 case CDK_DBSEARCH_SHORT_KEYID:
559 if (keyid[1] == ks->u.keyid[1])
560 return 1;
561 break;
562
563 case CDK_DBSEARCH_KEYID:
564 if (KEYID_CMP (keyid, ks->u.keyid))
565 return 1;
566 break;
567
568 default:
569 _cdk_log_debug ("find_by_keyid: invalid mode = %d\n", ks->type);
570 return 0;
571 }
572 }
573 }
574 return 0;
575}
576
577
578static int
579find_by_fpr (cdk_kbnode_t knode, cdk_dbsearch_t ks)
580{
581 cdk_kbnode_t node;
582 byte fpr[KEY_FPR_LEN];
583
584 if (ks->type != CDK_DBSEARCH_FPR)
585 return 0;
586
587 for (node = knode; node; node = node->next)
588 {
589 if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
590 node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
591 node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
592 node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
593 {
594 _cdk_pkt_get_fingerprint (node->pkt, fpr);
595 if (!memcmp (ks->u.fpr, fpr, KEY_FPR_LEN))
596 return 1;
597 break;
598 }
599 }
600
601 return 0;
602}
603
604
605static int
606find_by_pattern (cdk_kbnode_t knode, cdk_dbsearch_t ks)
607{
608 cdk_kbnode_t node;
609 size_t uidlen;
610 char *name;
611
612 for (node = knode; node; node = node->next)
613 {
614 if (node->pkt->pkttype != CDK_PKT_USER_ID)
615 continue;
616 if (node->pkt->pkt.user_id->attrib_img != NULL)
617 continue; /* Skip attribute packets. */
618 uidlen = node->pkt->pkt.user_id->len;
619 name = node->pkt->pkt.user_id->name;
620 switch (ks->type)
621 {
622 case CDK_DBSEARCH_EXACT:
623 if (name &&
624 (strlen (ks->u.pattern) == uidlen &&
625 !strncmp (ks->u.pattern, name, uidlen)))
626 return 1;
627 break;
628
629 case CDK_DBSEARCH_SUBSTR:
630 if (uidlen > 65536)
631 break;
632 if (name && strlen (ks->u.pattern) > uidlen)
633 break;
634 if (name && _cdk_memistr (name, uidlen, ks->u.pattern))
635 return 1;
636 break;
637
638 default: /* Invalid mode */
639 return 0;
640 }
641 }
642 return 0;
643}
644
645
646static void
647keydb_search_free (cdk_dbsearch_t dbs)
648{
649 if (!dbs)
650 return;
651 if (dbs->type == CDK_DBSEARCH_EXACT || dbs->type == CDK_DBSEARCH_SUBSTR)
652 cdk_free (dbs->u.pattern);
653 dbs->type = 0;
654 cdk_free (dbs);
655}
656
657
658static void
659keydb_cache_free (key_table_t cache)
660{
661 key_table_t c2;
662
663 while (cache)
664 {
665 c2 = cache->next;
666 cache->offset = 0;
667 keydb_search_free (cache->desc);
668 cdk_free (cache);
669 cache = c2;
670 }
671}
672
673
674static key_table_t
675keydb_cache_find (key_table_t cache, cdk_dbsearch_t desc)
676{
677 key_table_t t;
678
679 for (t = cache; t; t = t->next)
680 {
681 if (t->desc->type != desc->type)
682 continue;
683 switch (t->desc->type)
684 {
685 case CDK_DBSEARCH_SHORT_KEYID:
686 case CDK_DBSEARCH_KEYID:
687 if (KEYID_CMP (t->desc->u.keyid, desc->u.keyid))
688 return t;
689 break;
690
691 case CDK_DBSEARCH_EXACT:
692 if (strlen (t->desc->u.pattern) == strlen (desc->u.pattern) &&
693 !strcmp (t->desc->u.pattern, desc->u.pattern))
694 return t;
695 break;
696
697 case CDK_DBSEARCH_SUBSTR:
698 if (strstr (t->desc->u.pattern, desc->u.pattern))
699 return t;
700 break;
701
702 case CDK_DBSEARCH_FPR:
703 if (!memcmp (t->desc->u.fpr, desc->u.fpr, KEY_FPR_LEN))
704 return t;
705 break;
706 }
707 }
708
709 return NULL;
710}
711
712
713static cdk_error_t
714keydb_cache_add (cdk_keydb_hd_t hd, cdk_dbsearch_t dbs, off_t offset)
715{
716 key_table_t k;
717
718 if (!hd)
719 return CDK_Inv_Value;
720
721 if (hd->ncache > KEYDB_CACHE_ENTRIES)
722 return 0; /* FIXME: we should replace the last entry. */
723 k = cdk_calloc (1, sizeof *k);
724 if (!k)
725 return CDK_Out_Of_Core;
726 k->offset = offset;
727 keydb_search_copy (&k->desc, dbs);
728 k->next = hd->cache;
729 hd->cache = k;
730 hd->ncache++;
731 _cdk_log_debug ("cache: add entry off=%d type=%d\n", offset, dbs->type);
732 return 0;
733}
734
735
736static cdk_error_t
737keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src)
738{
739 cdk_dbsearch_t dst;
740
741 if (!r_dst || !src)
742 return CDK_Inv_Value;
743
744 *r_dst = NULL;
745 dst = cdk_calloc (1, sizeof *dst);
746 if (!dst)
747 return CDK_Out_Of_Core;
748 dst->type = src->type;
749 switch (src->type)
750 {
751 case CDK_DBSEARCH_EXACT:
752 case CDK_DBSEARCH_SUBSTR:
753 dst->u.pattern = cdk_strdup (src->u.pattern);
754 if (!dst->u.pattern)
755 return CDK_Out_Of_Core;
756 break;
757
758 case CDK_DBSEARCH_SHORT_KEYID:
759 case CDK_DBSEARCH_KEYID:
760 dst->u.keyid[0] = src->u.keyid[0];
761 dst->u.keyid[1] = src->u.keyid[1];
762 break;
763
764 case CDK_DBSEARCH_FPR:
765 memcpy (dst->u.fpr, src->u.fpr, KEY_FPR_LEN);
766 break;
767 }
768 *r_dst = dst;
769 return 0;
770}
771
772
773/**
774 * cdk_keydb_search_start:
775 * @db: key database handle
776 * @type: specifies the search type
777 * @desc: description which depends on the type
778 *
779 * Create a new keydb search object.
780 **/
781cdk_error_t
782cdk_keydb_search_start (cdk_keydb_hd_t db, int type, void *desc)
783{
784 cdk_dbsearch_t dbs;
785 u32 *keyid;
786 char *p, tmp[3];
787 int i;
788
789 if (!db)
790 return CDK_Inv_Value;
791 if (type != CDK_DBSEARCH_NEXT && !desc)
792 return CDK_Inv_Mode;
793
794 dbs = cdk_calloc (1, sizeof *dbs);
795 if (!dbs)
796 return CDK_Out_Of_Core;
797 dbs->type = type;
798 switch (type)
799 {
800 case CDK_DBSEARCH_EXACT:
801 case CDK_DBSEARCH_SUBSTR:
802 cdk_free (dbs->u.pattern);
803 dbs->u.pattern = cdk_strdup (desc);
804 if (!dbs->u.pattern)
805 {
806 cdk_free (dbs);
807 return CDK_Out_Of_Core;
808 }
809 break;
810
811 case CDK_DBSEARCH_SHORT_KEYID:
812 keyid = desc;
813 dbs->u.keyid[1] = keyid[0];
814 break;
815
816 case CDK_DBSEARCH_KEYID:
817 keyid = desc;
818 dbs->u.keyid[0] = keyid[0];
819 dbs->u.keyid[1] = keyid[1];
820 break;
821
822 case CDK_DBSEARCH_FPR:
823 memcpy (dbs->u.fpr, desc, KEY_FPR_LEN);
824 break;
825
826 case CDK_DBSEARCH_NEXT:
827 break;
828
829 case CDK_DBSEARCH_AUTO:
830 /* Override the type with the actual db search type. */
831 dbs->type = classify_data (desc, strlen (desc));
832 switch (dbs->type)
833 {
834 case CDK_DBSEARCH_SUBSTR:
835 case CDK_DBSEARCH_EXACT:
836 cdk_free (dbs->u.pattern);
837 p = dbs->u.pattern = cdk_strdup (desc);
838 if (!p)
839 {
840 cdk_free (dbs);
841 return CDK_Out_Of_Core;
842 }
843 break;
844
845 case CDK_DBSEARCH_SHORT_KEYID:
846 case CDK_DBSEARCH_KEYID:
847 p = desc;
848 if (!strncmp (p, "0x", 2))
849 p += 2;
850 if (strlen (p) == 8)
851 {
852 dbs->u.keyid[0] = 0;
853 dbs->u.keyid[1] = strtoul (p, NULL, 16);
854 }
855 else if (strlen (p) == 16)
856 {
857 dbs->u.keyid[0] = strtoul (p, NULL, 16);
858 dbs->u.keyid[1] = strtoul (p + 8, NULL, 16);
859 }
860 else
861 { /* Invalid key ID object. */
862 cdk_free (dbs);
863 return CDK_Inv_Mode;
864 }
865 break;
866
867 case CDK_DBSEARCH_FPR:
868 p = desc;
869 if (strlen (p) != 2 * KEY_FPR_LEN)
870 {
871 cdk_free (dbs);
872 return CDK_Inv_Mode;
873 }
874 for (i = 0; i < KEY_FPR_LEN; i++)
875 {
876 tmp[0] = p[2 * i];
877 tmp[1] = p[2 * i + 1];
878 tmp[2] = 0x00;
879 dbs->u.fpr[i] = strtoul (tmp, NULL, 16);
880 }
881 break;
882 }
883 break;
884
885 default:
886 cdk_free (dbs);
887 _cdk_log_debug ("cdk_keydb_search_start: invalid mode = %d\n", type);
888 return CDK_Inv_Mode;
889 }
890
891 keydb_search_free (db->dbs);
892 db->dbs = dbs;
893 return 0;
894}
895
896
897static cdk_error_t
898keydb_pos_from_cache (cdk_keydb_hd_t hd, cdk_dbsearch_t ks,
899 int *r_cache_hit, off_t * r_off)
900{
901 key_table_t c;
902
903 if (!hd || !r_cache_hit || !r_off)
904 return CDK_Inv_Value;
905
906 /* Reset the values. */
907 *r_cache_hit = 0;
908 *r_off = 0;
909
910 c = keydb_cache_find (hd->cache, ks);
911 if (c != NULL)
912 {
913 _cdk_log_debug ("cache: found entry in cache.\n");
914 *r_cache_hit = 1;
915 *r_off = c->offset;
916 return 0;
917 }
918
919 /* No index cache available so we just return here. */
920 if (!hd->idx)
921 return 0;
922
923 if (hd->idx)
924 {
925 if (ks->type == CDK_DBSEARCH_KEYID)
926 {
927 if (keydb_idx_search (hd->idx, ks->u.keyid, NULL, r_off))
928 return CDK_Error_No_Key;
929 _cdk_log_debug ("cache: found keyid entry in idx table.\n");
930 *r_cache_hit = 1;
931 }
932 else if (ks->type == CDK_DBSEARCH_FPR)
933 {
934 if (keydb_idx_search (hd->idx, NULL, ks->u.fpr, r_off))
935 return CDK_Error_No_Key;
936 _cdk_log_debug ("cache: found fpr entry in idx table.\n");
937 *r_cache_hit = 1;
938 }
939 }
940
941 return 0;
942}
943
944
945/**
946 * cdk_keydb_search:
947 * @hd: the keydb object
948 * @ks: the keydb search object
949 * @ret_key: kbnode object to store the key
950 *
951 * Search for a key in the given keyring. The search mode is handled
952 * via @ks. If the key was found, @ret_key contains the key data.
953 **/
954cdk_error_t
955cdk_keydb_search (cdk_keydb_hd_t hd, cdk_kbnode_t * ret_key)
956{
957 cdk_stream_t kr;
958 cdk_kbnode_t knode;
959 cdk_dbsearch_t ks;
960 cdk_error_t rc = 0;
961 off_t pos = 0, off = 0;
962 int key_found = 0, cache_hit = 0;
963
964 if (!hd || !ret_key)
965 return CDK_Inv_Value;
966
967 *ret_key = NULL;
968 kr = NULL;
969 hd->search = 1;
970 rc = _cdk_keydb_open (hd, &kr);
971 if (rc)
972 return rc;
973
974 if (!hd->no_cache)
975 {
976 /* It is possible the index is not up-to-date and thus we do
977 not find the requesed key. In this case, we reset cache hit
978 and continue our normal search procedure. */
979 rc = keydb_pos_from_cache (hd, hd->dbs, &cache_hit, &off);
980 if (rc)
981 cache_hit = 0;
982 }
983
984 knode = NULL;
985 ks = hd->dbs;
986 while (!key_found && !rc)
987 {
988 if (cache_hit && ks->type != CDK_DBSEARCH_NEXT)
989 cdk_stream_seek (kr, off);
990 pos = cdk_stream_tell (kr);
991 rc = cdk_keydb_get_keyblock (kr, &knode);
992 if (rc)
993 {
994 if (rc == CDK_EOF)
995 break;
996 else
997 return rc;
998 }
999
1000 switch (ks->type)
1001 {
1002 case CDK_DBSEARCH_SHORT_KEYID:
1003 case CDK_DBSEARCH_KEYID:
1004 key_found = find_by_keyid (knode, ks);
1005 break;
1006
1007 case CDK_DBSEARCH_FPR:
1008 key_found = find_by_fpr (knode, ks);
1009 break;
1010
1011 case CDK_DBSEARCH_EXACT:
1012 case CDK_DBSEARCH_SUBSTR:
1013 key_found = find_by_pattern (knode, ks);
1014 break;
1015
1016 case CDK_DBSEARCH_NEXT:
1017 key_found = knode ? 1 : 0;
1018 break;
1019 }
1020
1021 if (key_found)
1022 {
1023 if (!keydb_cache_find (hd->cache, ks))
1024 keydb_cache_add (hd, ks, pos);
1025 break;
1026 }
1027
1028 cdk_kbnode_release (knode);
1029 knode = NULL;
1030 }
1031
1032 hd->search = 0;
1033 if (key_found && rc == CDK_EOF)
1034 rc = 0;
1035 else if (rc == CDK_EOF && !key_found)
1036 rc = CDK_Error_No_Key;
1037 *ret_key = key_found ? knode : NULL;
1038 return rc;
1039}
1040
1041
1042cdk_error_t
1043cdk_keydb_get_bykeyid (cdk_keydb_hd_t hd, u32 * keyid, cdk_kbnode_t * ret_key)
1044{
1045 cdk_error_t rc;
1046
1047 if (!hd || !keyid || !ret_key)
1048 return CDK_Inv_Value;
1049
1050 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
1051 if (!rc)
1052 rc = cdk_keydb_search (hd, ret_key);
1053 return rc;
1054}
1055
1056
1057cdk_error_t
1058cdk_keydb_get_byfpr (cdk_keydb_hd_t hd, const byte * fpr,
1059 cdk_kbnode_t * r_key)
1060{
1061 cdk_error_t rc;
1062
1063 if (!hd || !fpr || !r_key)
1064 return CDK_Inv_Value;
1065
1066 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_FPR, (byte *) fpr);
1067 if (!rc)
1068 rc = cdk_keydb_search (hd, r_key);
1069 return rc;
1070}
1071
1072
1073cdk_error_t
1074cdk_keydb_get_bypattern (cdk_keydb_hd_t hd, const char *patt,
1075 cdk_kbnode_t * ret_key)
1076{
1077 cdk_error_t rc;
1078
1079 if (!hd || !patt || !ret_key)
1080 return CDK_Inv_Value;
1081
1082 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_SUBSTR, (char *) patt);
1083 if (!rc)
1084 rc = cdk_keydb_search (hd, ret_key);
1085 return rc;
1086}
1087
1088
1089static int
1090keydb_check_key (cdk_packet_t pkt)
1091{
1092 cdk_pkt_pubkey_t pk;
1093 int is_sk, valid;
1094
1095 if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
1096 pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
1097 {
1098 pk = pkt->pkt.public_key;
1099 is_sk = 0;
1100 }
1101 else if (pkt->pkttype == CDK_PKT_SECRET_KEY ||
1102 pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
1103 {
1104 pk = pkt->pkt.secret_key->pk;
1105 is_sk = 1;
1106 }
1107 else /* No key object. */
1108 return 0;
1109 valid = !pk->is_revoked && !pk->has_expired;
1110 if (is_sk)
1111 return valid;
1112 return valid && !pk->is_invalid;
1113}
1114
1115
1116/* Find the first kbnode with the requested packet type
1117 that represents a valid key. */
1118static cdk_kbnode_t
1119kbnode_find_valid (cdk_kbnode_t root, int pkttype)
1120{
1121 cdk_kbnode_t n;
1122
1123 for (n = root; n; n = n->next)
1124 {
1125 if (n->pkt->pkttype != pkttype)
1126 continue;
1127 if (keydb_check_key (n->pkt))
1128 return n;
1129 }
1130
1131 return NULL;
1132}
1133
1134
1135static cdk_kbnode_t
1136keydb_find_byusage (cdk_kbnode_t root, int req_usage, int is_pk)
1137{
1138 cdk_kbnode_t node, key;
1139 int req_type;
1140 long timestamp;
1141
1142 req_type = is_pk ? CDK_PKT_PUBLIC_KEY : CDK_PKT_SECRET_KEY;
1143 if (!req_usage)
1144 return kbnode_find_valid (root, req_type);
1145
1146 node = cdk_kbnode_find (root, req_type);
1147 if (node && !keydb_check_key (node->pkt))
1148 return NULL;
1149
1150 key = NULL;
1151 timestamp = 0;
1152 /* We iteratre over the all nodes and search for keys or
1153 subkeys which match the usage and which are not invalid.
1154 A timestamp is used to figure out the newest valid key. */
1155 for (node = root; node; node = node->next)
1156 {
1157 if (is_pk && (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
1158 node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
1159 && keydb_check_key (node->pkt)
1160 && (node->pkt->pkt.public_key->pubkey_usage & req_usage))
1161 {
1162 if (node->pkt->pkt.public_key->timestamp > timestamp)
1163 key = node;
1164 }
1165 if (!is_pk && (node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
1166 node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
1167 && keydb_check_key (node->pkt)
1168 && (node->pkt->pkt.secret_key->pk->pubkey_usage & req_usage))
1169 {
1170 if (node->pkt->pkt.secret_key->pk->timestamp > timestamp)
1171 key = node;
1172 }
1173
1174 }
1175 return key;
1176}
1177
1178
1179static cdk_kbnode_t
1180keydb_find_bykeyid (cdk_kbnode_t root, const u32 * keyid, int search_mode)
1181{
1182 cdk_kbnode_t node;
1183 u32 kid[2];
1184
1185 for (node = root; node; node = node->next)
1186 {
1187 if (!_cdk_pkt_get_keyid (node->pkt, kid))
1188 continue;
1189 if (search_mode == CDK_DBSEARCH_SHORT_KEYID && kid[1] == keyid[1])
1190 return node;
1191 else if (kid[0] == keyid[0] && kid[1] == keyid[1])
1192 return node;
1193 }
1194 return NULL;
1195}
1196
1197
1198cdk_error_t
1199_cdk_keydb_get_sk_byusage (cdk_keydb_hd_t hd, const char *name,
1200 cdk_seckey_t * ret_sk, int usage)
1201{
1202 cdk_kbnode_t knode = NULL;
1203 cdk_kbnode_t node, sk_node, pk_node;
1204 cdk_pkt_seckey_t sk;
1205 cdk_error_t rc;
1206 const char *s;
1207 int pkttype;
1208
1209 if (!ret_sk || !usage)
1210 return CDK_Inv_Value;
1211 if (!hd)
1212 return CDK_Error_No_Keyring;
1213
1214 *ret_sk = NULL;
1215 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, (char *) name);
1216 if (rc)
1217 return rc;
1218
1219 rc = cdk_keydb_search (hd, &knode);
1220 if (rc)
1221 return rc;
1222
1223 sk_node = keydb_find_byusage (knode, usage, 0);
1224 if (!sk_node)
1225 {
1226 cdk_kbnode_release (knode);
1227 return CDK_Unusable_Key;
1228 }
1229
1230 /* We clone the node with the secret key to avoid that the
1231 packet will be released. */
1232 _cdk_kbnode_clone (sk_node);
1233 sk = sk_node->pkt->pkt.secret_key;
1234
1235 for (node = knode; node; node = node->next)
1236 {
1237 if (node->pkt->pkttype == CDK_PKT_USER_ID)
1238 {
1239 s = node->pkt->pkt.user_id->name;
1240 if (sk && !sk->pk->uid && _cdk_memistr (s, strlen (s), name))
1241 {
1242 _cdk_copy_userid (&sk->pk->uid, node->pkt->pkt.user_id);
1243 break;
1244 }
1245 }
1246 }
1247
1248 /* To find the self signature, we need the primary public key because
1249 the selected secret key might be different from the primary key. */
1250 pk_node = cdk_kbnode_find (knode, CDK_PKT_SECRET_KEY);
1251 if (!pk_node)
1252 {
1253 cdk_kbnode_release (knode);
1254 return CDK_Unusable_Key;
1255 }
1256 node = find_selfsig_node (knode, pk_node->pkt->pkt.secret_key->pk);
1257 if (sk->pk->uid && node)
1258 _cdk_copy_signature (&sk->pk->uid->selfsig, node->pkt->pkt.signature);
1259
1260 /* We only release the outer packet. */
1261 _cdk_pkt_detach_free (sk_node->pkt, &pkttype, (void *) &sk);
1262 cdk_kbnode_release (knode);
1263 *ret_sk = sk;
1264 return rc;
1265}
1266
1267
1268cdk_error_t
1269_cdk_keydb_get_pk_byusage (cdk_keydb_hd_t hd, const char *name,
1270 cdk_pubkey_t * ret_pk, int usage)
1271{
1272 cdk_kbnode_t knode, node, pk_node;
1273 cdk_pkt_pubkey_t pk;
1274 const char *s;
1275 cdk_error_t rc;
1276
1277 if (!ret_pk || !usage)
1278 return CDK_Inv_Value;
1279 if (!hd)
1280 return CDK_Error_No_Keyring;
1281
1282 *ret_pk = NULL;
1283 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, (char *) name);
1284 if (!rc)
1285 rc = cdk_keydb_search (hd, &knode);
1286 if (rc)
1287 return rc;
1288
1289 node = keydb_find_byusage (knode, usage, 1);
1290 if (!node)
1291 {
1292 cdk_kbnode_release (knode);
1293 return CDK_Unusable_Key;
1294 }
1295
1296 pk = NULL;
1297 _cdk_copy_pubkey (&pk, node->pkt->pkt.public_key);
1298 for (node = knode; node; node = node->next)
1299 {
1300 if (node->pkt->pkttype == CDK_PKT_USER_ID)
1301 {
1302 s = node->pkt->pkt.user_id->name;
1303 if (pk && !pk->uid && _cdk_memistr (s, strlen (s), name))
1304 {
1305 _cdk_copy_userid (&pk->uid, node->pkt->pkt.user_id);
1306 break;
1307 }
1308 }
1309 }
1310
1311 /* Same as in the sk code, the selected key can be a sub key
1312 and thus we need the primary key to find the self sig. */
1313 pk_node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
1314 if (!pk_node)
1315 {
1316 cdk_kbnode_release (knode);
1317 return CDK_Unusable_Key;
1318 }
1319 node = find_selfsig_node (knode, pk_node->pkt->pkt.public_key);
1320 if (pk->uid && node)
1321 _cdk_copy_signature (&pk->uid->selfsig, node->pkt->pkt.signature);
1322 cdk_kbnode_release (knode);
1323
1324 *ret_pk = pk;
1325 return rc;
1326}
1327
1328
1329/**
1330 * cdk_keydb_get_pk:
1331 * @hd: key db handle
1332 * @keyid: keyid of the key
1333 * @r_pk: the allocated public key
1334 *
1335 * Perform a key database search by keyid and return the raw public
1336 * key without any signatures or user id's.
1337 **/
1338cdk_error_t
1339cdk_keydb_get_pk (cdk_keydb_hd_t hd, u32 * keyid, cdk_pubkey_t * r_pk)
1340{
1341 cdk_kbnode_t knode = NULL, node;
1342 cdk_pubkey_t pk;
1343 cdk_error_t rc;
1344 size_t s_type;
1345 int pkttype;
1346
1347 if (!keyid || !r_pk)
1348 return CDK_Inv_Value;
1349 if (!hd)
1350 return CDK_Error_No_Keyring;
1351
1352 *r_pk = NULL;
1353 s_type = !keyid[0] ? CDK_DBSEARCH_SHORT_KEYID : CDK_DBSEARCH_KEYID;
1354 rc = cdk_keydb_search_start (hd, s_type, keyid);
1355 if (rc)
1356 return rc;
1357 rc = cdk_keydb_search (hd, &knode);
1358 if (rc)
1359 return rc;
1360
1361 node = keydb_find_bykeyid (knode, keyid, s_type);
1362 if (!node)
1363 {
1364 cdk_kbnode_release (knode);
1365 return CDK_Error_No_Key;
1366 }
1367
1368 /* See comment in cdk_keydb_get_sk() */
1369 _cdk_pkt_detach_free (node->pkt, &pkttype, (void *) &pk);
1370 *r_pk = pk;
1371 _cdk_kbnode_clone (node);
1372 cdk_kbnode_release (knode);
1373
1374 return rc;
1375}
1376
1377
1378/**
1379 * cdk_keydb_get_sk:
1380 * @hd: key db handle
1381 * @keyid: the keyid of the key
1382 * @ret_sk: the allocated secret key
1383 *
1384 * Perform a key database search by keyid and return
1385 * only the raw secret key without the additional nodes,
1386 * like the user id or the signatures.
1387 **/
1388cdk_error_t
1389cdk_keydb_get_sk (cdk_keydb_hd_t hd, u32 * keyid, cdk_seckey_t * ret_sk)
1390{
1391 cdk_kbnode_t snode, node;
1392 cdk_seckey_t sk;
1393 cdk_error_t rc;
1394 int pkttype;
1395
1396 if (!keyid || !ret_sk)
1397 return CDK_Inv_Value;
1398 if (!hd)
1399 return CDK_Error_No_Keyring;
1400
1401 *ret_sk = NULL;
1402 rc = cdk_keydb_get_bykeyid (hd, keyid, &snode);
1403 if (rc)
1404 return rc;
1405
1406 node = keydb_find_bykeyid (snode, keyid, CDK_DBSEARCH_KEYID);
1407 if (!node)
1408 {
1409 cdk_kbnode_release (snode);
1410 return CDK_Error_No_Key;
1411 }
1412
1413 /* We need to release the packet itself but not its contents
1414 and thus we detach the openpgp packet and release the structure. */
1415 _cdk_pkt_detach_free (node->pkt, &pkttype, (void *) &sk);
1416 _cdk_kbnode_clone (node);
1417 cdk_kbnode_release (snode);
1418
1419 *ret_sk = sk;
1420 return 0;
1421}
1422
1423
1424static int
1425is_selfsig (cdk_kbnode_t node, const u32 * keyid)
1426{
1427 cdk_pkt_signature_t sig;
1428
1429 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
1430 return 0;
1431 sig = node->pkt->pkt.signature;
1432 if ((sig->sig_class >= 0x10 && sig->sig_class <= 0x13) &&
1433 sig->keyid[0] == keyid[0] && sig->keyid[1] == keyid[1])
1434 return 1;
1435
1436 return 0;
1437}
1438
1439
1440/* Find the newest self signature for the public key @pk
1441 and return the signature node. */
1442static cdk_kbnode_t
1443find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk)
1444{
1445 cdk_kbnode_t n, sig;
1446 unsigned int ts;
1447 u32 keyid[2];
1448
1449 cdk_pk_get_keyid (pk, keyid);
1450 sig = NULL;
1451 ts = 0;
1452 for (n = key; n; n = n->next)
1453 {
1454 if (is_selfsig (n, keyid) && n->pkt->pkt.signature->timestamp > ts)
1455 {
1456 ts = n->pkt->pkt.signature->timestamp;
1457 sig = n;
1458 }
1459 }
1460
1461 return sig;
1462}
1463
1464
1465
1466static cdk_error_t
1467keydb_merge_selfsig (cdk_kbnode_t key, u32 * keyid)
1468{
1469 cdk_kbnode_t node, kbnode, unode;
1470 cdk_subpkt_t s = NULL;
1471 cdk_pkt_signature_t sig = NULL;
1472 cdk_pkt_userid_t uid = NULL;
1473 const byte *symalg = NULL, *hashalg = NULL, *compalg = NULL;
1474 size_t nsymalg = 0, nhashalg = 0, ncompalg = 0, n = 0;
1475 size_t key_usage = 0, key_expire = 0;
1476
1477 if (!key)
1478 return CDK_Inv_Value;
1479
1480 for (node = key; node; node = node->next)
1481 {
1482 if (!is_selfsig (node, keyid))
1483 continue;
1484 unode = cdk_kbnode_find_prev (key, node, CDK_PKT_USER_ID);
1485 if (!unode)
1486 return CDK_Error_No_Key;
1487 uid = unode->pkt->pkt.user_id;
1488 sig = node->pkt->pkt.signature;
1489 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PRIMARY_UID);
1490 if (s)
1491 uid->is_primary = 1;
1492 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_FEATURES);
1493 if (s && s->size == 1 && s->d[0] & 0x01)
1494 uid->mdc_feature = 1;
1495 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_KEY_EXPIRE);
1496 if (s && s->size == 4)
1497 key_expire = _cdk_buftou32 (s->d);
1498 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_KEY_FLAGS);
1499 if (s)
1500 {
1501 if (s->d[0] & 0x03) /* cert + sign data */
1502 key_usage |= CDK_KEY_USG_SIGN;
1503 if (s->d[0] & 0x0C) /* encrypt comm. + storage */
1504 key_usage |= CDK_KEY_USG_ENCR;
1505 if (s->d[0] & 0x20)
1506 key_usage |= CDK_KEY_USG_AUTH;
1507 }
1508 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_SYM);
1509 if (s)
1510 {
1511 symalg = s->d;
1512 nsymalg = s->size;
1513 n += s->size + 1;
1514 }
1515 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_HASH);
1516 if (s)
1517 {
1518 hashalg = s->d;
1519 nhashalg = s->size;
1520 n += s->size + 1;
1521 }
1522 s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_ZIP);
1523 if (s)
1524 {
1525 compalg = s->d;
1526 ncompalg = s->size;
1527 n += s->size + 1;
1528 }
1529 if (uid->prefs != NULL)
1530 cdk_free (uid->prefs);
1531 if (!n || !hashalg || !compalg || !symalg)
1532 uid->prefs = NULL;
1533 else
1534 {
1535 uid->prefs = cdk_calloc (1, sizeof (*uid->prefs) * (n + 1));
1536 if (!uid->prefs)
1537 return CDK_Out_Of_Core;
1538 n = 0;
1539 for (; nsymalg; nsymalg--, n++)
1540 {
1541 uid->prefs[n].type = CDK_PREFTYPE_SYM;
1542 uid->prefs[n].value = *symalg++;
1543 }
1544 for (; nhashalg; nhashalg--, n++)
1545 {
1546 uid->prefs[n].type = CDK_PREFTYPE_HASH;
1547 uid->prefs[n].value = *hashalg++;
1548 }
1549 for (; ncompalg; ncompalg--, n++)
1550 {
1551 uid->prefs[n].type = CDK_PREFTYPE_ZIP;
1552 uid->prefs[n].value = *compalg++;
1553 }
1554
1555 uid->prefs[n].type = CDK_PREFTYPE_NONE; /* end of list marker */
1556 uid->prefs[n].value = 0;
1557 uid->prefs_size = n;
1558 }
1559 }
1560
1561 /* Now we add the extracted information to the primary key. */
1562 kbnode = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
1563 if (kbnode)
1564 {
1565 cdk_pkt_pubkey_t pk = kbnode->pkt->pkt.public_key;
1566 if (uid && uid->prefs && n)
1567 {
1568 if (pk->prefs != NULL)
1569 cdk_free (pk->prefs);
1570 pk->prefs = _cdk_copy_prefs (uid->prefs);
1571 pk->prefs_size = n;
1572 }
1573 if (key_expire)
1574 {
1575 pk->expiredate = pk->timestamp + key_expire;
1576 pk->has_expired = pk->expiredate > (u32) time (NULL) ? 0 : 1;
1577 }
1578
1579 if (key_usage)
1580 pk->pubkey_usage = key_usage;
1581 pk->is_invalid = 0;
1582 }
1583
1584 return 0;
1585}
1586
1587
1588static cdk_error_t
1589keydb_parse_allsigs (cdk_kbnode_t knode, cdk_keydb_hd_t hd, int check)
1590{
1591 cdk_kbnode_t node, kb;
1592 cdk_pkt_signature_t sig;
1593 cdk_pkt_pubkey_t pk;
1594 cdk_subpkt_t s = NULL;
1595 u32 expiredate = 0, curtime = (u32) time (NULL);
1596 u32 keyid[2];
1597
1598 if (!knode)
1599 return CDK_Inv_Value;
1600 if (check && !hd)
1601 return CDK_Inv_Mode;
1602
1603 kb = cdk_kbnode_find (knode, CDK_PKT_SECRET_KEY);
1604 if (kb)
1605 return 0;
1606
1607 /* Reset */
1608 for (node = knode; node; node = node->next)
1609 {
1610 if (node->pkt->pkttype == CDK_PKT_USER_ID)
1611 node->pkt->pkt.user_id->is_revoked = 0;
1612 else if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
1613 node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
1614 node->pkt->pkt.public_key->is_revoked = 0;
1615 }
1616
1617 kb = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
1618 if (!kb)
1619 return CDK_Wrong_Format;
1620 cdk_pk_get_keyid (kb->pkt->pkt.public_key, keyid);
1621
1622 for (node = knode; node; node = node->next)
1623 {
1624 if (node->pkt->pkttype == CDK_PKT_SIGNATURE)
1625 {
1626 sig = node->pkt->pkt.signature;
1627 /* Revocation certificates for primary keys */
1628 if (sig->sig_class == 0x20)
1629 {
1630 kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_KEY);
1631 if (kb)
1632 {
1633 kb->pkt->pkt.public_key->is_revoked = 1;
1634 if (check)
1635 _cdk_pk_check_sig (hd, kb, node, NULL);
1636 }
1637 else
1638 return CDK_Error_No_Key;
1639 }
1640 /* Revocation certificates for subkeys */
1641 else if (sig->sig_class == 0x28)
1642 {
1643 kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY);
1644 if (kb)
1645 {
1646 kb->pkt->pkt.public_key->is_revoked = 1;
1647 if (check)
1648 _cdk_pk_check_sig (hd, kb, node, NULL);
1649 }
1650 else
1651 return CDK_Error_No_Key;
1652 }
1653 /* Revocation certifcates for user ID's */
1654 else if (sig->sig_class == 0x30)
1655 {
1656 if (sig->keyid[0] != keyid[0] || sig->keyid[1] != keyid[1])
1657 continue; /* revokes an earlier signature, no userID. */
1658 kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_USER_ID);
1659 if (kb)
1660 {
1661 kb->pkt->pkt.user_id->is_revoked = 1;
1662 if (check)
1663 _cdk_pk_check_sig (hd, kb, node, NULL);
1664 }
1665 else
1666 return CDK_Error_No_Key;
1667 }
1668 /* Direct certificates for primary keys */
1669 else if (sig->sig_class == 0x1F)
1670 {
1671 kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_KEY);
1672 if (kb)
1673 {
1674 pk = kb->pkt->pkt.public_key;
1675 pk->is_invalid = 0;
1676 s = cdk_subpkt_find (node->pkt->pkt.signature->hashed,
1677 CDK_SIGSUBPKT_KEY_EXPIRE);
1678 if (s)
1679 {
1680 expiredate = _cdk_buftou32 (s->d);
1681 pk->expiredate = pk->timestamp + expiredate;
1682 pk->has_expired = pk->expiredate > curtime ? 0 : 1;
1683 }
1684 if (check)
1685 _cdk_pk_check_sig (hd, kb, node, NULL);
1686 }
1687 else
1688 return CDK_Error_No_Key;
1689 }
1690 /* Direct certificates for subkeys */
1691 else if (sig->sig_class == 0x18)
1692 {
1693 kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY);
1694 if (kb)
1695 {
1696 pk = kb->pkt->pkt.public_key;
1697 pk->is_invalid = 0;
1698 s = cdk_subpkt_find (node->pkt->pkt.signature->hashed,
1699 CDK_SIGSUBPKT_KEY_EXPIRE);
1700 if (s)
1701 {
1702 expiredate = _cdk_buftou32 (s->d);
1703 pk->expiredate = pk->timestamp + expiredate;
1704 pk->has_expired = pk->expiredate > curtime ? 0 : 1;
1705 }
1706 if (check)
1707 _cdk_pk_check_sig (hd, kb, node, NULL);
1708 }
1709 else
1710 return CDK_Error_No_Key;
1711 }
1712 }
1713 }
1714 node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
1715 if (node && node->pkt->pkt.public_key->version == 3)
1716 {
1717 /* v3 public keys have no additonal signatures for the key directly.
1718 we say the key is valid when we have at least a self signature. */
1719 pk = node->pkt->pkt.public_key;
1720 for (node = knode; node; node = node->next)
1721 {
1722 if (is_selfsig (node, keyid))
1723 {
1724 pk->is_invalid = 0;
1725 break;
1726 }
1727 }
1728 }
1729 if (node && (node->pkt->pkt.public_key->is_revoked ||
1730 node->pkt->pkt.public_key->has_expired))
1731 {
1732 /* If the primary key has been revoked, mark all subkeys as invalid
1733 because without a primary key they are not useable */
1734 for (node = knode; node; node = node->next)
1735 {
1736 if (node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
1737 node->pkt->pkt.public_key->is_invalid = 1;
1738 }
1739 }
1740
1741 return 0;
1742}
1743
1744
1745cdk_error_t
1746cdk_keydb_get_keyblock (cdk_stream_t inp, cdk_kbnode_t * r_knode)
1747{
1748 cdk_packet_t pkt;
1749 cdk_kbnode_t knode, node;
1750 cdk_desig_revoker_t revkeys;
1751 cdk_error_t rc;
1752 u32 keyid[2], main_keyid[2];
1753 off_t old_off;
1754 int key_seen, got_key;
1755
1756 if (!inp || !r_knode)
1757 return CDK_Inv_Value;
1758
1759 /* Reset all values. */
1760 keyid[0] = keyid[1] = 0;
1761 main_keyid[0] = main_keyid[1] = 0;
1762 revkeys = NULL;
1763 knode = NULL;
1764 key_seen = got_key = 0;
1765
1766 *r_knode = NULL;
1767 rc = CDK_EOF;
1768 while (!cdk_stream_eof (inp))
1769 {
1770 cdk_pkt_new (&pkt);
1771 old_off = cdk_stream_tell (inp);
1772 rc = cdk_pkt_read (inp, pkt);
1773 if (rc)
1774 {
1775 cdk_pkt_release (pkt);
1776 if (rc == CDK_EOF)
1777 break;
1778 else
1779 { /* Release all packets we reached so far. */
1780 _cdk_log_debug ("keydb_get_keyblock: error %d\n", rc);
1781 cdk_kbnode_release (knode);
1782 return rc;
1783 }
1784 }
1785 if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
1786 pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
1787 pkt->pkttype == CDK_PKT_SECRET_KEY ||
1788 pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
1789 {
1790 if (key_seen && (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
1791 pkt->pkttype == CDK_PKT_SECRET_KEY))
1792 {
1793 /* The next key starts here so set the file pointer
1794 and leave the loop. */
1795 cdk_stream_seek (inp, old_off);
1796 cdk_pkt_release (pkt);
1797 break;
1798 }
1799 if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
1800 pkt->pkttype == CDK_PKT_SECRET_KEY)
1801 {
1802 _cdk_pkt_get_keyid (pkt, main_keyid);
1803 key_seen = 1;
1804 }
1805 else if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
1806 pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
1807 {
1808 if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
1809 {
1810 pkt->pkt.public_key->main_keyid[0] = main_keyid[0];
1811 pkt->pkt.public_key->main_keyid[1] = main_keyid[1];
1812 }
1813 else
1814 {
1815 pkt->pkt.secret_key->main_keyid[0] = main_keyid[0];
1816 pkt->pkt.secret_key->main_keyid[1] = main_keyid[1];
1817 }
1818 }
1819 /* We save this for the signature */
1820 _cdk_pkt_get_keyid (pkt, keyid);
1821 got_key = 1;
1822 }
1823 else if (pkt->pkttype == CDK_PKT_USER_ID)
1824 ;
1825 else if (pkt->pkttype == CDK_PKT_SIGNATURE)
1826 {
1827 pkt->pkt.signature->key[0] = keyid[0];
1828 pkt->pkt.signature->key[1] = keyid[1];
1829 if (pkt->pkt.signature->sig_class == 0x1F &&
1830 pkt->pkt.signature->revkeys)
1831 revkeys = pkt->pkt.signature->revkeys;
1832 }
1833 node = cdk_kbnode_new (pkt);
1834 if (!knode)
1835 knode = node;
1836 else
1837 _cdk_kbnode_add (knode, node);
1838 }
1839
1840 if (got_key)
1841 {
1842 keydb_merge_selfsig (knode, main_keyid);
1843 rc = keydb_parse_allsigs (knode, NULL, 0);
1844 if (revkeys)
1845 {
1846 node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
1847 if (node)
1848 node->pkt->pkt.public_key->revkeys = revkeys;
1849 }
1850 }
1851 else
1852 cdk_kbnode_release (knode);
1853 *r_knode = got_key ? knode : NULL;
1854
1855 /* It is possible that we are in an EOF condition after we
1856 successfully read a keyblock. For example if the requested
1857 key is the last in the file. */
1858 if (rc == CDK_EOF && got_key)
1859 rc = 0;
1860 return rc;
1861}
1862
1863
1864/* Return the type of the given data. In case it cannot be classified,
1865 a substring search will be performed. */
1866static int
1867classify_data (const byte * buf, size_t len)
1868{
1869 int type;
1870 int i;
1871
1872 if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
1873 { /* Skip hex prefix. */
1874 buf += 2;
1875 len -= 2;
1876 }
1877
1878 /* The length of the data does not match either a keyid or a fingerprint. */
1879 if (len != 8 && len != 16 && len != 40)
1880 return CDK_DBSEARCH_SUBSTR;
1881
1882 for (i = 0; i < len; i++)
1883 {
1884 if (!isxdigit (buf[i]))
1885 return CDK_DBSEARCH_SUBSTR;
1886 }
1887 if (i != len)
1888 return CDK_DBSEARCH_SUBSTR;
1889 switch (len)
1890 {
1891 case 8:
1892 type = CDK_DBSEARCH_SHORT_KEYID;
1893 break;
1894 case 16:
1895 type = CDK_DBSEARCH_KEYID;
1896 break;
1897 case 40:
1898 type = CDK_DBSEARCH_FPR;
1899 break;
1900 default:
1901 type = CDK_DBSEARCH_SUBSTR;
1902 break;
1903 }
1904
1905 return type;
1906}
1907
1908
1909/**
1910 * cdk_keydb_export:
1911 * @hd: the keydb handle
1912 * @out: the output stream
1913 * @remusr: the list of key pattern to export
1914 *
1915 * Export a list of keys to the given output stream.
1916 * Use string list with names for pattering searching.
1917 * This procedure strips local signatures.
1918 **/
1919cdk_error_t
1920cdk_keydb_export (cdk_keydb_hd_t hd, cdk_stream_t out, cdk_strlist_t remusr)
1921{
1922 cdk_kbnode_t knode, node;
1923 cdk_strlist_t r;
1924 cdk_error_t rc;
1925 int old_ctb;
1926
1927 for (r = remusr; r; r = r->next)
1928 {
1929 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, r->d);
1930 if (rc)
1931 return rc;
1932 rc = cdk_keydb_search (hd, &knode);
1933 if (rc)
1934 return rc;
1935 node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
1936 if (!node)
1937 return CDK_Error_No_Key;
1938
1939 /* If the key is a version 3 key, use the old packet
1940 format for the output. */
1941 if (node->pkt->pkt.public_key->version == 3)
1942 old_ctb = 1;
1943 else
1944 old_ctb = 0;
1945
1946 for (node = knode; node; node = node->next)
1947 {
1948 /* No specified format; skip them */
1949 if (node->pkt->pkttype == CDK_PKT_RING_TRUST)
1950 continue;
1951 /* We never export local signed signatures */
1952 if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
1953 !node->pkt->pkt.signature->flags.exportable)
1954 continue;
1955 /* Filter out invalid signatures */
1956 if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
1957 !KEY_CAN_SIGN (node->pkt->pkt.signature->pubkey_algo))
1958 continue;
1959
1960 /* Adjust the ctb flag if needed. */
1961 node->pkt->old_ctb = old_ctb;
1962 rc = cdk_pkt_write (out, node->pkt);
1963 if (rc)
1964 {
1965 cdk_kbnode_release (knode);
1966 return rc;
1967 }
1968 }
1969 cdk_kbnode_release (knode);
1970 knode = NULL;
1971 }
1972 return 0;
1973}
1974
1975
1976static cdk_packet_t
1977find_key_packet (cdk_kbnode_t knode, int *r_is_sk)
1978{
1979 cdk_packet_t pkt;
1980
1981 pkt = cdk_kbnode_find_packet (knode, CDK_PKT_PUBLIC_KEY);
1982 if (!pkt)
1983 {
1984 pkt = cdk_kbnode_find_packet (knode, CDK_PKT_SECRET_KEY);
1985 if (r_is_sk)
1986 *r_is_sk = pkt ? 1 : 0;
1987 }
1988 return pkt;
1989}
1990
1991
1992/* Return 1 if the is allowd in a key node. */
1993static int
1994is_key_node (cdk_kbnode_t node)
1995{
1996 switch (node->pkt->pkttype)
1997 {
1998 case CDK_PKT_SIGNATURE:
1999 case CDK_PKT_SECRET_KEY:
2000 case CDK_PKT_PUBLIC_KEY:
2001 case CDK_PKT_SECRET_SUBKEY:
2002 case CDK_PKT_PUBLIC_SUBKEY:
2003 case CDK_PKT_USER_ID:
2004 case CDK_PKT_ATTRIBUTE:
2005 return 1;
2006
2007 default:
2008 return 0;
2009 }
2010
2011 return 0;
2012}
2013
2014
2015cdk_error_t
2016cdk_keydb_import (cdk_keydb_hd_t hd, cdk_kbnode_t knode)
2017{
2018 cdk_kbnode_t node, chk;
2019 cdk_packet_t pkt;
2020 cdk_stream_t out;
2021 cdk_error_t rc;
2022 u32 keyid[2];
2023
2024 if (!hd || !knode)
2025 return CDK_Inv_Value;
2026
2027 pkt = find_key_packet (knode, NULL);
2028 if (!pkt)
2029 return CDK_Inv_Packet;
2030
2031 _cdk_pkt_get_keyid (pkt, keyid);
2032 chk = NULL;
2033 cdk_keydb_get_bykeyid (hd, keyid, &chk);
2034 if (chk)
2035 { /* FIXME: search for new signatures */
2036 cdk_kbnode_release (chk);
2037 return 0;
2038 }
2039
2040 /* We append data to the stream so we need to close
2041 the stream here to re-open it later. */
2042 if (hd->fp)
2043 {
2044 cdk_stream_close (hd->fp);
2045 hd->fp = NULL;
2046 }
2047
2048 rc = _cdk_stream_append (hd->name, &out);
2049 if (rc)
2050 return rc;
2051
2052 for (node = knode; node; node = node->next)
2053 {
2054 if (node->pkt->pkttype == CDK_PKT_RING_TRUST)
2055 continue; /* No uniformed syntax for this packet */
2056 if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
2057 !node->pkt->pkt.signature->flags.exportable)
2058 {
2059 _cdk_log_debug ("key db import: skip local signature\n");
2060 continue;
2061 }
2062
2063 if (!is_key_node (node))
2064 {
2065 _cdk_log_debug ("key db import: skip invalid node of type %d\n",
2066 node->pkt->pkttype);
2067 continue;
2068 }
2069
2070 rc = cdk_pkt_write (out, node->pkt);
2071 if (rc)
2072 {
2073 cdk_stream_close (out);
2074 return rc;
2075 }
2076 }
2077
2078 cdk_stream_close (out);
2079 if (!hd->no_cache)
2080 cdk_keydb_idx_rebuild (hd);
2081 hd->stats.new_keys++;
2082
2083 return 0;
2084}
2085
2086
2087cdk_error_t
2088_cdk_keydb_check_userid (cdk_keydb_hd_t hd, u32 * keyid, const char *id)
2089{
2090 cdk_kbnode_t knode = NULL, unode = NULL;
2091 cdk_error_t rc;
2092 int check;
2093
2094 if (!hd)
2095 return CDK_Inv_Value;
2096
2097 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
2098 if (rc)
2099 return rc;
2100 rc = cdk_keydb_search (hd, &knode);
2101 if (rc)
2102 return rc;
2103
2104 rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_EXACT, (char *) id);
2105 if (!rc)
2106 rc = cdk_keydb_search (hd, &unode);
2107 if (rc)
2108 {
2109 cdk_kbnode_release (knode);
2110 return rc;
2111 }
2112
2113 check = 0;
2114 cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
2115 if (unode && find_by_keyid (unode, hd->dbs))
2116 check++;
2117 cdk_kbnode_release (unode);
2118
2119 cdk_keydb_search_start (hd, CDK_DBSEARCH_EXACT, (char *) id);
2120 if (knode && find_by_pattern (knode, hd->dbs))
2121 check++;
2122 cdk_kbnode_release (knode);
2123
2124 return check == 2 ? 0 : CDK_Inv_Value;
2125}
2126
2127
2128/**
2129 * cdk_keydb_check_sk:
2130 * @hd: the key db handle
2131 * @keyid: the 64-bit keyid
2132 *
2133 * Check if a secret key with the given key ID is available
2134 * in the key database.
2135 **/
2136cdk_error_t
2137cdk_keydb_check_sk (cdk_keydb_hd_t hd, u32 * keyid)
2138{
2139 cdk_stream_t db;
2140 cdk_packet_t pkt;
2141 cdk_error_t rc;
2142 u32 kid[2];
2143
2144 if (!hd || !keyid)
2145 return CDK_Inv_Value;
2146 if (!hd->secret)
2147 return CDK_Inv_Mode;
2148
2149 rc = _cdk_keydb_open (hd, &db);
2150 if (rc)
2151 return rc;
2152 cdk_pkt_new (&pkt);
2153 while (!cdk_pkt_read (db, pkt))
2154 {
2155 if (pkt->pkttype != CDK_PKT_SECRET_KEY &&
2156 pkt->pkttype != CDK_PKT_SECRET_SUBKEY)
2157 {
2158 cdk_pkt_free (pkt);
2159 continue;
2160 }
2161 cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
2162 if (KEYID_CMP (kid, keyid))
2163 {
2164 cdk_pkt_release (pkt);
2165 return 0;
2166 }
2167 cdk_pkt_free (pkt);
2168 }
2169 cdk_pkt_release (pkt);
2170 return CDK_Error_No_Key;
2171}
2172
2173
2174/**
2175 * cdk_listkey_start:
2176 * @r_ctx: pointer to store the new context
2177 * @db: the key database handle
2178 * @patt: string pattern
2179 * @fpatt: recipients from a stringlist to show
2180 *
2181 * Prepare a key listing with the given parameters. Two modes are supported.
2182 * The first mode uses string pattern to determine if the key should be
2183 * returned or not. The other mode uses a string list to request the key
2184 * which should be listed.
2185 **/
2186cdk_error_t
2187cdk_listkey_start (cdk_listkey_t * r_ctx, cdk_keydb_hd_t db,
2188 const char *patt, cdk_strlist_t fpatt)
2189{
2190 cdk_listkey_t ctx;
2191 cdk_stream_t inp;
2192 cdk_error_t rc;
2193
2194 if (!r_ctx || !db)
2195 return CDK_Inv_Value;
2196 if ((patt && fpatt) || (!patt && !fpatt))
2197 return CDK_Inv_Mode;
2198 rc = _cdk_keydb_open (db, &inp);
2199 if (rc)
2200 return rc;
2201 ctx = cdk_calloc (1, sizeof *ctx);
2202 if (!ctx)
2203 return CDK_Out_Of_Core;
2204 ctx->db = db;
2205 ctx->inp = inp;
2206 if (patt)
2207 {
2208 ctx->u.patt = cdk_strdup (patt);
2209 if (!ctx->u.patt)
2210 return CDK_Out_Of_Core;
2211 }
2212 else if (fpatt)
2213 {
2214 cdk_strlist_t l;
2215 for (l = fpatt; l; l = l->next)
2216 cdk_strlist_add (&ctx->u.fpatt, l->d);
2217 }
2218 ctx->type = patt ? 1 : 0;
2219 ctx->init = 1;
2220 *r_ctx = ctx;
2221 return 0;
2222}
2223
2224
2225/**
2226 * cdk_listkey_close:
2227 * @ctx: the list key context
2228 *
2229 * Free the list key context.
2230 **/
2231void
2232cdk_listkey_close (cdk_listkey_t ctx)
2233{
2234 if (!ctx)
2235 return;
2236
2237 if (ctx->type)
2238 cdk_free (ctx->u.patt);
2239 else
2240 cdk_strlist_free (ctx->u.fpatt);
2241 cdk_free (ctx);
2242}
2243
2244
2245/**
2246 * cdk_listkey_next:
2247 * @ctx: list key context
2248 * @r_key: the pointer to the new key node object
2249 *
2250 * Retrieve the next key from the pattern of the key list context.
2251 **/
2252cdk_error_t
2253cdk_listkey_next (cdk_listkey_t ctx, cdk_kbnode_t * ret_key)
2254{
2255 if (!ctx || !ret_key)
2256 return CDK_Inv_Value;
2257 if (!ctx->init)
2258 return CDK_Inv_Mode;
2259
2260 if (ctx->type && ctx->u.patt[0] == '*')
2261 return cdk_keydb_get_keyblock (ctx->inp, ret_key);
2262 else if (ctx->type)
2263 {
2264 cdk_kbnode_t node;
2265 struct cdk_dbsearch_s ks;
2266 cdk_error_t rc;
2267
2268 for (;;)
2269 {
2270 rc = cdk_keydb_get_keyblock (ctx->inp, &node);
2271 if (rc)
2272 return rc;
2273 memset (&ks, 0, sizeof (ks));
2274 ks.type = CDK_DBSEARCH_SUBSTR;
2275 ks.u.pattern = ctx->u.patt;
2276 if (find_by_pattern (node, &ks))
2277 {
2278 *ret_key = node;
2279 return 0;
2280 }
2281 cdk_kbnode_release (node);
2282 node = NULL;
2283 }
2284 }
2285 else
2286 {
2287 if (!ctx->t)
2288 ctx->t = ctx->u.fpatt;
2289 else if (ctx->t->next)
2290 ctx->t = ctx->t->next;
2291 else
2292 return CDK_EOF;
2293 return cdk_keydb_get_bypattern (ctx->db, ctx->t->d, ret_key);
2294 }
2295 return CDK_General_Error;
2296}
2297
2298
2299int
2300_cdk_keydb_is_secret (cdk_keydb_hd_t db)
2301{
2302 return db->secret;
2303}
diff --git a/src/daemon/https/opencdk/literal.c b/src/daemon/https/opencdk/literal.c
new file mode 100644
index 00000000..4ccba6b2
--- /dev/null
+++ b/src/daemon/https/opencdk/literal.c
@@ -0,0 +1,307 @@
1/* Literal.c - Literal packet filters
2 * Copyright (C) 2002, 2003 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17# include <config.h>
18#endif
19#include <stdio.h>
20#include <time.h>
21
22#include "opencdk.h"
23#include "main.h"
24#include "filters.h"
25
26
27/* Duplicate the string @s but strip of possible
28 relative folder names of it. */
29static char *
30dup_trim_filename (const char *s)
31{
32 char *p = NULL;
33
34 p = strrchr (s, '/');
35 if (!p)
36 p = strrchr (s, '\\');
37 if (!p)
38 return cdk_strdup (s);
39 return cdk_strdup (p + 1);
40}
41
42
43static cdk_error_t
44literal_decode (void *opaque, FILE * in, FILE * out)
45{
46 literal_filter_t *pfx = opaque;
47 cdk_stream_t si, so;
48 cdk_packet_t pkt;
49 cdk_pkt_literal_t pt;
50 byte buf[BUFSIZE];
51 size_t nread;
52 int bufsize;
53 cdk_error_t rc;
54
55 _cdk_log_debug ("literal filter: decode\n");
56
57 if (!pfx || !in || !out)
58 return CDK_Inv_Value;
59
60 rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
61 if (rc)
62 return rc;
63
64 cdk_pkt_new (&pkt);
65 rc = cdk_pkt_read (si, pkt);
66 if (rc || pkt->pkttype != CDK_PKT_LITERAL)
67 {
68 cdk_pkt_release (pkt);
69 cdk_stream_close (si);
70 return !rc ? CDK_Inv_Packet : rc;
71 }
72
73 rc = _cdk_stream_fpopen (out, STREAMCTL_WRITE, &so);
74 if (rc)
75 {
76 cdk_pkt_release (pkt);
77 cdk_stream_close (si);
78 return rc;
79 }
80
81 pt = pkt->pkt.literal;
82 pfx->mode = pt->mode;
83
84 if (pfx->filename && pt->namelen > 0)
85 {
86 /* The name in the literal packet is more authorative. */
87 cdk_free (pfx->filename);
88 pfx->filename = dup_trim_filename (pt->name);
89 }
90 else if (!pfx->filename && pt->namelen > 0)
91 pfx->filename = dup_trim_filename (pt->name);
92 else if (!pt->namelen && !pfx->filename && pfx->orig_filename)
93 {
94 /* In this case, we need to derrive the output file name
95 from the original name and cut off the OpenPGP extension.
96 If this is not possible, we return an error. */
97 if (!stristr (pfx->orig_filename, ".gpg") &&
98 !stristr (pfx->orig_filename, ".pgp") &&
99 !stristr (pfx->orig_filename, ".asc"))
100 {
101 cdk_pkt_release (pkt);
102 cdk_stream_close (si);
103 cdk_stream_close (so);
104 _cdk_log_debug
105 ("literal filter: no file name and no PGP extension\n");
106 return CDK_Inv_Mode;
107 }
108 _cdk_log_debug ("literal filter: derrive file name from original\n");
109 pfx->filename = dup_trim_filename (pfx->orig_filename);
110 pfx->filename[strlen (pfx->filename) - 4] = '\0';
111 }
112
113 while (!feof (in))
114 {
115 _cdk_log_debug ("literal_decode: part on %d size %lu\n",
116 pfx->blkmode.on, pfx->blkmode.size);
117 if (pfx->blkmode.on)
118 bufsize = pfx->blkmode.size;
119 else
120 bufsize = pt->len < DIM (buf) ? pt->len : DIM (buf);
121 nread = cdk_stream_read (pt->buf, buf, bufsize);
122 if (nread == EOF)
123 {
124 rc = CDK_File_Error;
125 break;
126 }
127 if (pfx->md)
128 gcry_md_write (pfx->md, buf, nread);
129 cdk_stream_write (so, buf, nread);
130 pt->len -= nread;
131 if (pfx->blkmode.on)
132 {
133 pfx->blkmode.size = _cdk_pkt_read_len (in, &pfx->blkmode.on);
134 if (pfx->blkmode.size == (size_t) EOF)
135 return CDK_Inv_Packet;
136 }
137 if (pt->len <= 0 && !pfx->blkmode.on)
138 break;
139 }
140
141 cdk_stream_close (si);
142 cdk_stream_close (so);
143 cdk_pkt_release (pkt);
144 return rc;
145}
146
147
148static char
149intmode_to_char (int mode)
150{
151 switch (mode)
152 {
153 case CDK_LITFMT_BINARY:
154 return 'b';
155 case CDK_LITFMT_TEXT:
156 return 't';
157 case CDK_LITFMT_UNICODE:
158 return 'u';
159 default:
160 return 'b';
161 }
162
163 return 'b';
164}
165
166
167static cdk_error_t
168literal_encode (void *opaque, FILE * in, FILE * out)
169{
170 literal_filter_t *pfx = opaque;
171 cdk_pkt_literal_t pt;
172 cdk_stream_t si;
173 cdk_packet_t pkt;
174 size_t filelen;
175 cdk_error_t rc;
176
177 _cdk_log_debug ("literal filter: encode\n");
178
179 if (!pfx || !in || !out)
180 return CDK_Inv_Value;
181 if (!pfx->filename)
182 {
183 pfx->filename = cdk_strdup ("_CONSOLE");
184 if (!pfx->filename)
185 return CDK_Out_Of_Core;
186 }
187
188 rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
189 if (rc)
190 return rc;
191
192 filelen = strlen (pfx->filename);
193 cdk_pkt_new (&pkt);
194 pt = pkt->pkt.literal = cdk_calloc (1, sizeof *pt + filelen - 1);
195 if (!pt)
196 {
197 cdk_pkt_release (pkt);
198 cdk_stream_close (si);
199 return CDK_Out_Of_Core;
200 }
201 memcpy (pt->name, pfx->filename, filelen);
202 pt->namelen = filelen;
203 pt->name[pt->namelen] = '\0';
204 pt->timestamp = (u32) time (NULL);
205 pt->mode = intmode_to_char (pfx->mode);
206 pt->len = cdk_stream_get_length (si);
207 pt->buf = si;
208 pkt->old_ctb = 1;
209 pkt->pkttype = CDK_PKT_LITERAL;
210 pkt->pkt.literal = pt;
211 rc = _cdk_pkt_write_fp (out, pkt);
212
213 cdk_pkt_release (pkt);
214 cdk_stream_close (si);
215 return rc;
216}
217
218
219int
220_cdk_filter_literal (void *opaque, int ctl, FILE * in, FILE * out)
221{
222 if (ctl == STREAMCTL_READ)
223 return literal_decode (opaque, in, out);
224 else if (ctl == STREAMCTL_WRITE)
225 return literal_encode (opaque, in, out);
226 else if (ctl == STREAMCTL_FREE)
227 {
228 literal_filter_t *pfx = opaque;
229 if (pfx)
230 {
231 _cdk_log_debug ("free literal filter\n");
232 cdk_free (pfx->filename);
233 pfx->filename = NULL;
234 cdk_free (pfx->orig_filename);
235 pfx->orig_filename = NULL;
236 return 0;
237 }
238 }
239 return CDK_Inv_Mode;
240}
241
242
243static int
244text_encode (void *opaque, FILE * in, FILE * out)
245{
246 const char *s;
247 char buf[2048];
248
249 if (!in || !out)
250 return CDK_Inv_Value;
251
252 /* FIXME: This code does not work for very long lines. */
253 while (!feof (in))
254 {
255 s = fgets (buf, DIM (buf) - 1, in);
256 if (!s)
257 break;
258 _cdk_trim_string (buf, 1);
259 fwrite (buf, 1, strlen (buf), out);
260 }
261
262 return 0;
263}
264
265
266static int
267text_decode (void *opaque, FILE * in, FILE * out)
268{
269 text_filter_t *tfx = opaque;
270 const char *s;
271 char buf[2048];
272
273 if (!tfx || !in || !out)
274 return CDK_Inv_Value;
275
276 while (!feof (in))
277 {
278 s = fgets (buf, DIM (buf) - 1, in);
279 if (!s)
280 break;
281 _cdk_trim_string (buf, 0);
282 fwrite (buf, 1, strlen (buf), out);
283 fwrite (tfx->lf, 1, strlen (tfx->lf), out);
284 }
285
286 return 0;
287}
288
289
290int
291_cdk_filter_text (void *opaque, int ctl, FILE * in, FILE * out)
292{
293 if (ctl == STREAMCTL_READ)
294 return text_encode (opaque, in, out);
295 else if (ctl == STREAMCTL_WRITE)
296 return text_decode (opaque, in, out);
297 else if (ctl == STREAMCTL_FREE)
298 {
299 text_filter_t *tfx = opaque;
300 if (tfx)
301 {
302 _cdk_log_debug ("free text filter\n");
303 tfx->lf = NULL;
304 }
305 }
306 return CDK_Inv_Mode;
307}
diff --git a/src/daemon/https/opencdk/main.c b/src/daemon/https/opencdk/main.c
new file mode 100644
index 00000000..be5aec62
--- /dev/null
+++ b/src/daemon/https/opencdk/main.c
@@ -0,0 +1,779 @@
1/* main.c
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17# include <config.h>
18#endif
19#include <stdio.h>
20#include <errno.h>
21#ifdef HAVE_UNISTD_H
22# include <unistd.h>
23#endif
24#ifdef _WIN32
25#include <windows.h>
26#endif
27
28#include "opencdk.h"
29#include "main.h"
30#include "packet.h"
31
32
33/* Set a default cipher algorithm and a digest algorithm.
34 Even if AES and SHA-256 are not 'MUST' in the latest
35 OpenPGP draft, AES seems to be a good choice. */
36#define DEFAULT_CIPHER_ALGO GCRY_CIPHER_AES
37#define DEFAULT_DIGEST_ALGO GCRY_MD_SHA256
38
39/* The site of the secure memory which is allocated in gcrypt. */
40#define SECMEM_SIZE 16384
41
42
43/* Hooks to custom memory allocation functions. */
44static void *(*alloc_func) (size_t n) = gcry_xmalloc;
45static void *(*alloc_secure_func) (size_t n) = gcry_malloc_secure;
46static void *(*realloc_func) (void *p, size_t n) = gcry_realloc;
47static void *(*calloc_func) (size_t m, size_t n) = gcry_calloc;
48static void (*free_func) (void *) = gcry_free;
49static int malloc_hooks = 0;
50static int secmem_init = 0;
51
52/* Global settings for the logging. */
53static cdk_log_fnc_t log_handler = NULL;
54static void *log_handler_value = NULL;
55static int log_level = CDK_LOG_NONE;
56
57
58/**
59 * cdk_strerror:
60 * @ec: the error number
61 *
62 * Return an error text for the given id.
63 **/
64const char *
65cdk_strerror (int ec)
66{
67 static char buf[20];
68
69 switch (ec)
70 {
71 case CDK_EOF:
72 return "End Of File";
73 case CDK_Success:
74 return "No error";
75 case CDK_General_Error:
76 return "General error";
77 case CDK_File_Error:
78 return strerror (errno);
79 case CDK_Bad_Sig:
80 return "Bad signature";
81 case CDK_Inv_Packet:
82 return "Invalid packet";
83 case CDK_Inv_Algo:
84 return "Invalid algorithm";
85 case CDK_Not_Implemented:
86 return "This is not implemented yet";
87 case CDK_Armor_Error:
88 return "ASCII armor error";
89 case CDK_Armor_CRC_Error:
90 return "ASCII armored damaged (CRC error)";
91 case CDK_MPI_Error:
92 return "Invalid or missformed MPI";
93 case CDK_Inv_Value:
94 return "Invalid parameter or value";
95 case CDK_Error_No_Key:
96 return "No key available or not found";
97 case CDK_Chksum_Error:
98 return "Check for key does not match";
99 case CDK_Time_Conflict:
100 return "Time conflict";
101 case CDK_Zlib_Error:
102 return "ZLIB error";
103 case CDK_Weak_Key:
104 return "Weak key was detected";
105 case CDK_Out_Of_Core:
106 return "Out of core!!";
107 case CDK_Wrong_Seckey:
108 return "Wrong secret key";
109 case CDK_Wrong_Format:
110 return "Data has wrong format";
111 case CDK_Bad_MDC:
112 return "Manipulated MDC detected";
113 case CDK_Inv_Mode:
114 return "Invalid mode";
115 case CDK_Error_No_Keyring:
116 return "No keyring available";
117 case CDK_Inv_Packet_Ver:
118 return "Invalid version for packet";
119 case CDK_Too_Short:
120 return "Buffer or object is too short";
121 case CDK_Unusable_Key:
122 return "Unusable public key";
123 case CDK_No_Data:
124 return "No data";
125 case CDK_No_Passphrase:
126 return "No passphrase supplied";
127 case CDK_Network_Error:
128 return "A network error occurred";
129 default:
130 sprintf (buf, "ec=%d", ec);
131 return buf;
132 }
133 return NULL;
134}
135
136
137static void
138out_of_core (size_t n)
139{
140 fprintf (stderr, "\n ** fatal error: out of memory (%d bytes) **\n", n);
141}
142
143
144/**
145 * cdk_set_malloc_hooks:
146 * @new_alloc_func: malloc replacement
147 * @new_alloc_secure_func: secure malloc replacement
148 * @new_realloc_func: realloc replacement
149 * @new_calloc_func: calloc replacement
150 * @new_free_func: free replacement
151 *
152 * Set private memory hooks for the library.
153 */
154void
155cdk_set_malloc_hooks (void *(*new_alloc_func) (size_t n),
156 void *(*new_alloc_secure_func) (size_t n),
157 void *(*new_realloc_func) (void *p, size_t n),
158 void *(*new_calloc_func) (size_t m, size_t n),
159 void (*new_free_func) (void *))
160{
161 alloc_func = new_alloc_func;
162 alloc_secure_func = new_alloc_secure_func;
163 realloc_func = new_realloc_func;
164 calloc_func = new_calloc_func;
165 free_func = new_free_func;
166 malloc_hooks = 1;
167}
168
169
170/**
171 * cdk_malloc_hook_initialized:
172 *
173 * Return if the malloc hooks are already initialized.
174 **/
175int
176cdk_malloc_hook_initialized (void)
177{
178 return malloc_hooks;
179}
180
181
182void *
183cdk_malloc (size_t size)
184{
185 void *p = alloc_func (size);
186 if (!p)
187 out_of_core (size);
188 return p;
189}
190
191
192/**
193 * cdk_calloc:
194 * @n: amount of elements
195 * @m: size of one element
196 *
197 * Safe wrapper around the c-function calloc.
198 **/
199void *
200cdk_calloc (size_t n, size_t m)
201{
202 void *p = calloc_func (n, m);
203 if (!p)
204 out_of_core (m);
205 return p;
206}
207
208
209/* Things which need to be done after the secure memory initialisation. */
210static void
211_secmem_finish (void)
212{
213 gcry_control (GCRYCTL_DROP_PRIVS);
214}
215
216
217/* Initialize the secure memory. */
218static void
219_secmem_init (size_t size)
220{
221 if (secmem_init == 1)
222 return;
223 if (size >= SECMEM_SIZE)
224 size = SECMEM_SIZE;
225
226 /* Check if no other library has already initialized gcrypt. */
227 if (!gcry_control (GCRYCTL_ANY_INITIALIZATION_P))
228 {
229 _cdk_log_debug ("init: libgcrypt initialize.\n");
230 gcry_control (GCRYCTL_INIT_SECMEM, size, 0);
231 gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
232 gcry_control (GCRYCTL_DISABLE_SECMEM_WARN);
233 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
234 secmem_init = 1;
235 }
236}
237
238
239/* Things which needs to be done to deinit the secure memory. */
240static void
241_secmem_end (void)
242{
243 gcry_control (GCRYCTL_TERM_SECMEM);
244 secmem_init = 0;
245}
246
247
248/* The Windows system needs to startup the Winsock interface first
249 before we can use any socket related function. */
250#ifdef _WIN32
251static void
252init_sockets (void)
253{
254 static int initialized = 0;
255 WSADATA wsdata;
256
257 if (initialized)
258 return;
259 if (WSAStartup (0x202, &wsdata))
260 _cdk_log_debug ("winsock init failed.\n");
261
262 initialized = 1;
263}
264
265static void
266deinit_sockets (void)
267{
268 WSACleanup ();
269}
270#else
271void
272init_sockets (void)
273{
274}
275void
276deinit_sockets (void)
277{
278}
279#endif
280
281
282/**
283 * cdk_lib_startup:
284 *
285 * Prepare the internal structures of the library.
286 * This function should be called before any other CDK function.
287 */
288void
289cdk_lib_startup (void)
290{
291 _secmem_init (SECMEM_SIZE);
292 _secmem_finish ();
293 init_sockets ();
294}
295
296
297/**
298 * cdk_lib_shutdown:
299 *
300 * Shutdown the library and free all internal and globally used
301 * memory and structures. This function should be called in the
302 * exit handler of the calling program.
303 */
304void
305cdk_lib_shutdown (void)
306{
307 deinit_sockets ();
308 _secmem_end ();
309}
310
311/**
312 * cdk_salloc:
313 * @size: how much bytes should be allocated.
314 * @clear: shall the buffer cleared after the allocation?
315 *
316 * Allocated the requested amount of bytes in 'secure' memory.
317 */
318void *
319cdk_salloc (size_t size, int clear)
320{
321 void *p;
322
323 if (!secmem_init)
324 _secmem_init (SECMEM_SIZE);
325
326 p = alloc_secure_func (size);
327 if (!p)
328 out_of_core (size);
329 if (clear)
330 memset (p, 0, size);
331 return p;
332}
333
334
335void *
336cdk_realloc (void *ptr, size_t size)
337{
338 void *p = realloc_func (ptr, size);
339 if (!p)
340 out_of_core (size);
341 return p;
342}
343
344
345char *
346cdk_strdup (const char *ptr)
347{
348 char *p = cdk_malloc (strlen (ptr) + 1);
349 if (p)
350 strcpy (p, ptr);
351 return p;
352}
353
354
355void
356cdk_free (void *ptr)
357{
358 if (ptr)
359 free_func (ptr);
360}
361
362
363/* Internal logging routine. */
364static void
365_cdk_logv (int level, const char *fmt, va_list arg_ptr)
366{
367
368 if (log_handler)
369 log_handler (log_handler_value, level, fmt, arg_ptr);
370 else
371 {
372 if (level == CDK_LOG_NONE)
373 return;
374 if (level == CDK_LOG_DEBUG)
375 fputs ("DBG: ", stderr);
376 vfprintf (stderr, fmt, arg_ptr);
377 }
378}
379
380
381/**
382 * cdk_set_log_handler:
383 * @logfnc: the function pointer
384 * @opaque: a private values for the function
385 *
386 * Set a custom handler for logging.
387 **/
388void
389cdk_set_log_handler (cdk_log_fnc_t logfnc, void *opaque)
390{
391 log_handler = logfnc;
392 log_handler_value = opaque;
393}
394
395
396/**
397 * cdk_set_log_level:
398 * @lvl: the level
399 *
400 * Set the verbosity level.
401 **/
402void
403cdk_set_log_level (int level)
404{
405 log_level = level;
406}
407
408
409/* Return the current log level of the lib. */
410int
411_cdk_get_log_level (void)
412{
413 return log_level;
414}
415
416
417void
418_cdk_log_info (const char *fmt, ...)
419{
420 va_list arg;
421
422 if (log_level == CDK_LOG_NONE)
423 return;
424 va_start (arg, fmt);
425 _cdk_logv (CDK_LOG_INFO, fmt, arg);
426 va_end (arg);
427}
428
429
430void
431_cdk_log_debug (const char *fmt, ...)
432{
433 va_list arg;
434
435 if (log_level < CDK_LOG_DEBUG)
436 return;
437 va_start (arg, fmt);
438 _cdk_logv (CDK_LOG_DEBUG, fmt, arg);
439 va_end (arg);
440}
441
442
443/* Use the passphrase callback in the handle HD or
444 return NULL if there is no valid callback. */
445char *
446_cdk_passphrase_get (cdk_ctx_t hd, const char *prompt)
447{
448 if (!hd || !hd->passphrase_cb)
449 return NULL;
450 return hd->passphrase_cb (hd->passphrase_cb_value, prompt);
451}
452
453
454static void
455handle_set_cipher (cdk_ctx_t hd, int cipher)
456{
457 if (!hd)
458 return;
459 if (gcry_cipher_test_algo (cipher))
460 cipher = DEFAULT_CIPHER_ALGO;
461 hd->cipher_algo = cipher;
462}
463
464
465static void
466handle_set_digest (cdk_ctx_t hd, int digest)
467{
468 if (!hd)
469 return;
470 if (gcry_md_test_algo (digest))
471 digest = DEFAULT_DIGEST_ALGO;
472 hd->digest_algo = digest;
473}
474
475
476static void
477handle_set_s2k (cdk_ctx_t hd, int mode, int digest, int cipher)
478{
479 if (!hd)
480 return;
481 if (gcry_cipher_test_algo (cipher))
482 cipher = DEFAULT_CIPHER_ALGO;
483 if (gcry_md_test_algo (digest))
484 digest = DEFAULT_DIGEST_ALGO;
485 if (mode != CDK_S2K_SIMPLE &&
486 mode != CDK_S2K_SALTED && mode != CDK_S2K_ITERSALTED)
487 mode = CDK_S2K_ITERSALTED;
488 hd->_s2k.mode = mode;
489 hd->_s2k.digest_algo = digest;
490}
491
492
493static void
494handle_set_compress (cdk_ctx_t hd, int algo, int level)
495{
496 if (!hd)
497 return;
498 if (algo < 0 || algo > 2)
499 algo = 0;
500 hd->compress.algo = algo;
501 if (!algo)
502 hd->opt.compress = 0;
503 else
504 {
505 if (level > 0 && level < 10)
506 hd->compress.level = level;
507 else
508 hd->compress.level = 6;
509 }
510}
511
512
513/**
514 * cdk_handle_control:
515 * @hd: session handle
516 * @action: flag which indicates whether put or get is requested
517 * @cmd: command id
518 *
519 * Perform various control operations for the current session.
520 **/
521int
522cdk_handle_control (cdk_ctx_t hd, int action, int cmd, ...)
523{
524 va_list arg_ptr;
525 int set = action == CDK_CTLF_SET, val = 0;
526
527 if (!hd)
528 return -1;
529
530 if (action != CDK_CTLF_SET && action != CDK_CTLF_GET)
531 return -1;
532 va_start (arg_ptr, cmd);
533 switch (cmd)
534 {
535 case CDK_CTL_ARMOR:
536 if (set)
537 hd->opt.armor = va_arg (arg_ptr, int);
538 else
539 val = hd->opt.armor;
540 break;
541
542 case CDK_CTL_CIPHER:
543 if (set)
544 handle_set_cipher (hd, va_arg (arg_ptr, int));
545 else
546 val = hd->cipher_algo;
547 break;
548
549 case CDK_CTL_DIGEST:
550 if (set)
551 handle_set_digest (hd, va_arg (arg_ptr, int));
552 else
553 val = hd->digest_algo;
554 break;
555
556 case CDK_CTL_OVERWRITE:
557 if (set)
558 hd->opt.overwrite = va_arg (arg_ptr, int);
559 else
560 val = hd->opt.overwrite;
561 break;
562
563 case CDK_CTL_COMPRESS:
564 if (set)
565 {
566 int algo = va_arg (arg_ptr, int);
567 int level = va_arg (arg_ptr, int);
568 handle_set_compress (hd, algo, level);
569 }
570 else
571 val = hd->compress.algo;
572 break;
573
574 case CDK_CTL_S2K:
575 if (set)
576 {
577 int mode = va_arg (arg_ptr, int);
578 int digest = va_arg (arg_ptr, int);
579 int cipher = va_arg (arg_ptr, int);
580 handle_set_s2k (hd, mode, digest, cipher);
581 }
582 else
583 val = hd->_s2k.mode;
584 break;
585
586 case CDK_CTL_FORCE_DIGEST:
587 if (set)
588 hd->opt.force_digest = va_arg (arg_ptr, int);
589 else
590 val = hd->opt.force_digest;
591 break;
592
593 case CDK_CTL_BLOCKMODE_ON:
594 if (set)
595 hd->opt.blockmode = va_arg (arg_ptr, int);
596 else
597 val = hd->opt.blockmode;
598 break;
599
600 default:
601 val = -1;
602 break;
603 }
604 va_end (arg_ptr);
605 return val;
606}
607
608
609
610/**
611 * cdk_handle_new:
612 * @r_ctx: context to store the handle
613 *
614 * create a new session handle.
615 **/
616cdk_error_t
617cdk_handle_new (cdk_ctx_t * r_ctx)
618{
619 cdk_ctx_t c;
620
621 if (!r_ctx)
622 return CDK_Inv_Value;
623
624 c = cdk_calloc (1, sizeof *c);
625 if (!c)
626 return CDK_Out_Of_Core;
627
628 /* For S2K use the iterated and salted mode and use the
629 default digest and cipher algorithms. Because the MDC
630 feature will be used, the default cipher should use a
631 blocksize of 128 bits. */
632 c->_s2k.mode = CDK_S2K_ITERSALTED;
633 c->_s2k.digest_algo = DEFAULT_DIGEST_ALGO;
634
635 c->opt.mdc = 1;
636 c->opt.compress = 1;
637 c->opt.armor = 0;
638 c->opt.textmode = 0;
639
640 c->digest_algo = DEFAULT_DIGEST_ALGO;
641 c->cipher_algo = DEFAULT_CIPHER_ALGO;
642
643 c->compress.algo = CDK_COMPRESS_ZIP;
644 c->compress.level = 6;
645
646 *r_ctx = c;
647 return 0;
648}
649
650
651/**
652 * cdk_handle_set_keyring:
653 * @hd: session handle
654 * @type: public=0 or secret=1 keyring type
655 * @kringname: file name of the keyring which shall be used.
656 *
657 * Convenient function to set the keyring for the current session.
658 */
659cdk_error_t
660cdk_handle_set_keyring (cdk_ctx_t hd, int type, const char *kringname)
661{
662 cdk_keydb_hd_t db;
663 cdk_error_t err;
664
665 err = cdk_keydb_new_from_file (&db, type, kringname);
666 if (err)
667 return err;
668
669 if (!type)
670 hd->db.pub = db;
671 else
672 hd->db.sec = db;
673 hd->db.close_db = 1;
674 return 0;
675}
676
677
678/**
679 * cdk_handle_set_keydb:
680 * @hd: session handle
681 * @db: the database handle
682 *
683 * set the key database handle.
684 * the function automatically detects whether this is a public or
685 * secret keyring and the right handle is set.
686 **/
687void
688cdk_handle_set_keydb (cdk_ctx_t hd, cdk_keydb_hd_t db)
689{
690 if (!hd)
691 return;
692 if (_cdk_keydb_is_secret (db))
693 hd->db.sec = db;
694 else
695 hd->db.pub = db;
696}
697
698
699/**
700 * cdk_handle_get_keydb:
701 * @hd: session handle
702 * @type: type of the keyring
703 *
704 * Return the keydb handle from the session handle.
705 * The caller should not free these handles.
706 **/
707cdk_keydb_hd_t
708cdk_handle_get_keydb (cdk_ctx_t hd, int type)
709{
710 if (!hd)
711 return NULL;
712 if (type == CDK_DBTYPE_PK_KEYRING)
713 return hd->db.pub;
714 else if (type == CDK_DBTYPE_SK_KEYRING)
715 return hd->db.sec;
716 return NULL;
717}
718
719
720/**
721 * cdk_handle_set_passphrase_cb:
722 * @hd: session handle
723 * @cb: callback function
724 * @cb_value: the opaque value for the cb function
725 *
726 * set the passphrase callback.
727 **/
728void
729cdk_handle_set_passphrase_cb (cdk_ctx_t hd,
730 char *(*cb) (void *opa, const char *prompt),
731 void *cb_value)
732{
733 if (!hd)
734 return;
735 hd->passphrase_cb = cb;
736 hd->passphrase_cb_value = cb_value;
737}
738
739
740/**
741 * cdk_handle_verify_get_result:
742 * @hd: the session handle
743 *
744 * Return the verify result for the current session.
745 * Do not free the pointer.
746 **/
747cdk_verify_result_t
748cdk_handle_verify_get_result (cdk_ctx_t hd)
749{
750 return hd->result.verify;
751}
752
753
754/**
755 * cdk_handle_free:
756 * @hd: the handle
757 *
758 * Release the main handle.
759 **/
760void
761cdk_handle_free (cdk_ctx_t hd)
762{
763 if (!hd)
764 return;
765 _cdk_result_verify_free (hd->result.verify);
766
767 /* If cdk_handle_set_keyring() were used, we need to free the key db
768 handles here because the handles are not controlled by the user. */
769 if (hd->db.close_db)
770 {
771 if (hd->db.pub)
772 cdk_keydb_free (hd->db.pub);
773 if (hd->db.sec)
774 cdk_keydb_free (hd->db.sec);
775 hd->db.pub = hd->db.sec = NULL;
776 }
777 cdk_free (hd->dek);
778 cdk_free (hd);
779}
diff --git a/src/daemon/https/opencdk/main.h b/src/daemon/https/opencdk/main.h
new file mode 100644
index 00000000..3e9a443d
--- /dev/null
+++ b/src/daemon/https/opencdk/main.h
@@ -0,0 +1,183 @@
1/* main.h
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifndef CDK_MAIN_H
17#define CDK_MAIN_H
18
19#include <gcrypt.h>
20#include "types.h"
21
22/* The general size of a buffer for the variou modules. */
23#define BUFSIZE 8192
24
25/* This is the default block size for the partial length packet mode. */
26#define DEF_BLOCKSIZE 8192
27#define DEF_BLOCKBITS 13 /* 2^13 = 8192 */
28
29/* For now SHA-1 is used to create fingerprint for keys.
30 But if this will ever change, it is a good idea to
31 have a constant for it to avoid to change it in all files. */
32#define KEY_FPR_LEN 20
33
34#include "context.h"
35
36/* The maximal amount of bits a multi precsion integer can have. */
37#define MAX_MPI_BITS 16384
38#define MAX_MPI_BYTES (MAX_MPI_BITS/8)
39
40
41/* Because newer DSA variants are not limited to SHA-1, we must consider
42 that SHA-512 is used and increase the buffer size of the digest. */
43#define MAX_DIGEST_LEN 64
44
45/* Helper to find out if the signature were made over a user ID
46 or if the signature revokes a previous user ID. */
47#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
48#define IS_UID_REV(s) ((s)->sig_class == 0x30)
49
50#define DEBUG_PKT (_cdk_get_log_level () == (CDK_LOG_DEBUG+1))
51
52/* Helper to find out if a key has the requested capability. */
53#define KEY_CAN_ENCRYPT(a) (_cdk_pk_algo_usage ((a)) & CDK_KEY_USG_ENCR)
54#define KEY_CAN_SIGN(a) (_cdk_pk_algo_usage ((a)) & CDK_KEY_USG_SIGN)
55#define KEY_CAN_AUTH(a) (_cdk_pk_algo_usage ((a)) & CDK_KEY_USG_AUTH)
56
57/* Helper macro to make sure the buffer is overwritten. */
58#define wipemem(_ptr,_len) do { \
59 volatile char *_vptr = (volatile char *)(_ptr); \
60 size_t _vlen = (_len); \
61 while (_vlen) \
62 { \
63 *_vptr = 0; \
64 _vptr++; \
65 _vlen--; \
66 } } while (0)
67
68/*-- armor.c --*/
69const char * _cdk_armor_get_lineend (void);
70
71/*-- main.c --*/
72int _cdk_get_log_level (void);
73void _cdk_log_info (const char * fmt, ...);
74void _cdk_log_debug (const char * fmt, ...);
75char * _cdk_passphrase_get (cdk_ctx_t hd, const char *prompt);
76
77/*-- misc.c --*/
78int _cdk_check_args( int overwrite, const char * in, const char * out );
79u32 _cdk_buftou32 (const byte * buf);
80void _cdk_u32tobuf (u32 u, byte * buf);
81const char *_cdk_memistr (const char * buf, size_t buflen, const char * sub);
82cdk_error_t _cdk_map_gcry_error (gcry_error_t err);
83#define map_gcry_error(err) _cdk_map_gcry_error (err)
84
85/* Helper to provide case insentensive strstr version. */
86#define stristr(haystack, needle) \
87 _cdk_memistr((haystack), strlen (haystack), (needle))
88
89/*-- proc-packet.c --*/
90cdk_error_t _cdk_proc_packets (cdk_ctx_t hd, cdk_stream_t inp,
91 cdk_stream_t data,
92 const char *output, cdk_stream_t outstream,
93 gcry_md_hd_t md);
94cdk_error_t _cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx);
95
96/*-- pubkey.c --*/
97u32 _cdk_pkt_get_keyid (cdk_packet_t pkt, u32 * keyid);
98cdk_error_t _cdk_pkt_get_fingerprint (cdk_packet_t pkt, byte *fpr);
99int _cdk_pk_algo_usage (int algo);
100int _cdk_pk_test_algo (int algo, unsigned int usage);
101int _cdk_sk_get_csum (cdk_pkt_seckey_t sk);
102
103/*-- new-packet.c --*/
104byte * _cdk_subpkt_get_array (cdk_subpkt_t s, int count, size_t * r_nbytes);
105cdk_error_t _cdk_subpkt_copy (cdk_subpkt_t * r_dst, cdk_subpkt_t src);
106void _cdk_pkt_detach_free (cdk_packet_t pkt, int *r_pkttype, void **ctx);
107
108/*-- sig-check.c --*/
109cdk_error_t _cdk_sig_check (cdk_pkt_pubkey_t pk, cdk_pkt_signature_t sig,
110 gcry_md_hd_t digest, int * r_expired);
111cdk_error_t _cdk_hash_sig_data (cdk_pkt_signature_t sig, gcry_md_hd_t hd);
112cdk_error_t _cdk_hash_userid (cdk_pkt_userid_t uid, int sig_version, gcry_md_hd_t md);
113cdk_error_t _cdk_hash_pubkey (cdk_pkt_pubkey_t pk, gcry_md_hd_t md,
114 int use_fpr);
115cdk_error_t _cdk_pk_check_sig (cdk_keydb_hd_t hd,
116 cdk_kbnode_t knode,
117 cdk_kbnode_t snode, int *is_selfsig);
118
119/*-- kbnode.c --*/
120void _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node);
121void _cdk_kbnode_clone (cdk_kbnode_t node);
122
123/*-- sesskey.c --*/
124cdk_error_t _cdk_digest_encode_pkcs1 (byte **r_md, size_t *r_mdlen,
125 int pk_algo,
126 const byte * md,
127 int digest_algo, unsigned nbits);
128cdk_error_t _cdk_sk_unprotect_auto (cdk_ctx_t hd, cdk_pkt_seckey_t sk);
129
130/*-- keydb.c --*/
131int _cdk_keydb_is_secret (cdk_keydb_hd_t db);
132cdk_error_t _cdk_keydb_get_pk_byusage (cdk_keydb_hd_t hd, const char * name,
133 cdk_pkt_pubkey_t * ret_pk, int usage);
134cdk_error_t _cdk_keydb_get_sk_byusage (cdk_keydb_hd_t hd, const char * name,
135 cdk_pkt_seckey_t * ret_sk, int usage);
136cdk_error_t _cdk_keydb_check_userid (cdk_keydb_hd_t hd, u32 * keyid,
137 const char * id);
138
139/*-- sign.c --*/
140int _cdk_sig_hash_for (cdk_pkt_pubkey_t pk);
141void _cdk_trim_string (char * s, int canon);
142cdk_error_t _cdk_sig_create (cdk_pkt_pubkey_t pk, cdk_pkt_signature_t sig);
143cdk_error_t _cdk_sig_complete (cdk_pkt_signature_t sig, cdk_pkt_seckey_t sk,
144 gcry_md_hd_t hd);
145
146/*-- stream.c --*/
147void _cdk_stream_set_compress_algo (cdk_stream_t s, int algo);
148cdk_error_t _cdk_stream_open_mode (const char *file, const char *mode,
149 cdk_stream_t *ret_s);
150void * _cdk_stream_get_opaque( cdk_stream_t s, int fid );
151const char * _cdk_stream_get_fname( cdk_stream_t s );
152FILE * _cdk_stream_get_fp( cdk_stream_t s );
153int _cdk_stream_gets( cdk_stream_t s, char * buf, size_t count );
154cdk_error_t _cdk_stream_append( const char * file, cdk_stream_t * ret_s );
155int _cdk_stream_get_errno( cdk_stream_t s );
156cdk_error_t _cdk_stream_set_blockmode( cdk_stream_t s, size_t nbytes );
157int _cdk_stream_get_blockmode( cdk_stream_t s );
158int _cdk_stream_puts( cdk_stream_t s, const char * buf );
159cdk_error_t _cdk_stream_fpopen (FILE * fp, unsigned write_mode,
160 cdk_stream_t *ret_out);
161
162/*-- verify.c --*/
163void _cdk_result_verify_free (cdk_verify_result_t res);
164cdk_verify_result_t _cdk_result_verify_new (void);
165
166
167/*-- read-packet.c --*/
168size_t _cdk_pkt_read_len (FILE * inp, size_t *ret_partial);
169
170/*-- write-packet.c --*/
171cdk_error_t _cdk_pkt_write_fp( FILE * out, cdk_packet_t pkt );
172
173/*-- seskey.c --*/
174cdk_error_t _cdk_s2k_copy (cdk_s2k_t *r_dst, cdk_s2k_t src);
175
176cdk_error_t cdk_dek_encode_pkcs1 (cdk_dek_t dek, size_t nbits,
177 gcry_mpi_t *r_enc);
178cdk_error_t cdk_dek_decode_pkcs1 (cdk_dek_t * ret_dek, gcry_mpi_t esk);
179cdk_error_t cdk_dek_extract (cdk_dek_t * ret_dek, cdk_ctx_t hd,
180 cdk_pkt_pubkey_enc_t enc,
181 cdk_pkt_seckey_t sk );
182
183#endif /* CDK_MAIN_H */
diff --git a/src/daemon/https/opencdk/misc.c b/src/daemon/https/opencdk/misc.c
new file mode 100644
index 00000000..c296de40
--- /dev/null
+++ b/src/daemon/https/opencdk/misc.c
@@ -0,0 +1,571 @@
1/* misc.c
2 * Copyright (C) 2002, 2003 Timo Schulz
3 * Copyright (C) 1998-2002, 2007 Free Software Foundation, Inc.
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdio.h>
21#include <string.h>
22#include <ctype.h>
23#include <sys/stat.h>
24
25#include "opencdk.h"
26#include "main.h"
27
28
29u32
30_cdk_buftou32 (const byte * buf)
31{
32 u32 u;
33
34 if (!buf)
35 return 0;
36 u = buf[0] << 24;
37 u |= buf[1] << 16;
38 u |= buf[2] << 8;
39 u |= buf[3];
40 return u;
41}
42
43
44void
45_cdk_u32tobuf (u32 u, byte * buf)
46{
47 if (!buf)
48 return;
49 buf[0] = u >> 24;
50 buf[1] = u >> 16;
51 buf[2] = u >> 8;
52 buf[3] = u;
53}
54
55
56static const char *
57parse_version_number (const char *s, int *number)
58{
59 int val = 0;
60
61 if (*s == '0' && isdigit (s[1]))
62 return NULL;
63 /* leading zeros are not allowed */
64 for (; isdigit (*s); s++)
65 {
66 val *= 10;
67 val += *s - '0';
68 }
69 *number = val;
70 return val < 0 ? NULL : s;
71}
72
73
74static const char *
75parse_version_string (const char *s, int *major, int *minor, int *micro)
76{
77 s = parse_version_number (s, major);
78 if (!s || *s != '.')
79 return NULL;
80 s++;
81 s = parse_version_number (s, minor);
82 if (!s || *s != '.')
83 return NULL;
84 s++;
85 s = parse_version_number (s, micro);
86 if (!s)
87 return NULL;
88 return s; /* patchlevel */
89}
90
91
92/**
93 * cdk_check_version:
94 * @req_version: The requested version
95 *
96 * Check that the the version of the library is at minimum the requested
97 * one and return the version string; return NULL if the condition is
98 * not satisfied. If a NULL is passed to this function, no check is done,
99 *but the version string is simply returned.
100 **/
101const char *
102cdk_check_version (const char *req_version)
103{
104 const char *ver = VERSION;
105 int my_major, my_minor, my_micro;
106 int rq_major, rq_minor, rq_micro;
107 const char *my_plvl, *rq_plvl;
108
109 if (!req_version)
110 return ver;
111 my_plvl = parse_version_string (ver, &my_major, &my_minor, &my_micro);
112 if (!my_plvl)
113 return NULL;
114 /* very strange our own version is bogus */
115 rq_plvl = parse_version_string (req_version, &rq_major, &rq_minor,
116 &rq_micro);
117 if (!rq_plvl)
118 return NULL; /* req version string is invalid */
119 if (my_major > rq_major
120 || (my_major == rq_major && my_minor > rq_minor)
121 || (my_major == rq_major && my_minor == rq_minor
122 && my_micro > rq_micro)
123 || (my_major == rq_major && my_minor == rq_minor
124 && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
125 return ver;
126 return NULL;
127}
128
129
130/**
131 * cdk_strlist_free:
132 * @sl: the string list
133 *
134 * Release the string list object.
135 **/
136void
137cdk_strlist_free (cdk_strlist_t sl)
138{
139 cdk_strlist_t sl2;
140
141 for (; sl; sl = sl2)
142 {
143 sl2 = sl->next;
144 cdk_free (sl);
145 }
146}
147
148
149/**
150 * cdk_strlist_add:
151 * @list: destination string list
152 * @string: the string to add
153 *
154 * Add the given list to the string list.
155 **/
156cdk_strlist_t
157cdk_strlist_add (cdk_strlist_t * list, const char *string)
158{
159 cdk_strlist_t sl;
160
161 if (!string)
162 return NULL;
163
164 sl = cdk_calloc (1, sizeof *sl + strlen (string) + 1);
165 if (!sl)
166 return NULL;
167 strcpy (sl->d, string);
168 sl->next = *list;
169 *list = sl;
170 return sl;
171}
172
173
174/**
175 * cdk_strlist_next:
176 * @root: the opaque string list.
177 * @r_str: optional argument to store the string data.
178 *
179 * Return the next string list node from @root. The optional
180 * argument @r_str return the data of the current (!) node.
181 **/
182cdk_strlist_t
183cdk_strlist_next (cdk_strlist_t root, const char **r_str)
184{
185 cdk_strlist_t node;
186
187 if (root && r_str)
188 *r_str = root->d;
189 for (node = root->next; node; node = node->next)
190 return node;
191
192 return NULL;
193}
194
195
196const char *
197_cdk_memistr (const char *buf, size_t buflen, const char *sub)
198{
199 const byte *t, *s;
200 size_t n;
201
202 for (t = (byte *) buf, n = buflen, s = (byte *) sub; n; t++, n--)
203 {
204 if (toupper (*t) == toupper (*s))
205 {
206 for (buf = t++, buflen = n--, s++;
207 n && toupper (*t) == toupper ((byte) * s); t++, s++, n--)
208 ;
209 if (!*s)
210 return buf;
211 t = (byte *) buf;
212 n = buflen;
213 s = (byte *) sub;
214 }
215 }
216
217 return NULL;
218}
219
220
221/**
222 * cdk_utf8_encode:
223 * @string:
224 *
225 * Encode the given string in utf8 and return it.
226 **/
227char *
228cdk_utf8_encode (const char *string)
229{
230 const byte *s;
231 char *buffer;
232 byte *p;
233 size_t length;
234
235 /* FIXME: We should use iconv if possible for utf8 issues. */
236 for (s = (const byte *) string, length = 0; *s; s++)
237 {
238 length++;
239 if (*s & 0x80)
240 length++;
241 }
242
243 buffer = cdk_calloc (1, length + 1);
244 for (p = (byte *) buffer, s = (byte *) string; *s; s++)
245 {
246 if (*s & 0x80)
247 {
248 *p++ = 0xc0 | ((*s >> 6) & 3);
249 *p++ = 0x80 | (*s & 0x3f);
250 }
251 else
252 *p++ = *s;
253 }
254 *p = 0;
255 return buffer;
256}
257
258
259/**
260 * cdk_utf8_decode:
261 * @string: the string to decode
262 * @length: the length of the string
263 * @delim: the delimiter
264 *
265 * Decode the given utf8 string and return the native representation.
266 **/
267char *
268cdk_utf8_decode (const char *string, size_t length, int delim)
269{
270 int nleft;
271 int i;
272 byte encbuf[8];
273 int encidx;
274 const byte *s;
275 size_t n;
276 byte *buffer = NULL, *p = NULL;
277 unsigned long val = 0;
278 size_t slen;
279 int resync = 0;
280
281 /* 1. pass (p==NULL): count the extended utf-8 characters */
282 /* 2. pass (p!=NULL): create string */
283 for (;;)
284 {
285 for (slen = length, nleft = encidx = 0, n = 0, s = (byte *) string;
286 slen; s++, slen--)
287 {
288 if (resync)
289 {
290 if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
291 {
292 /* still invalid */
293 if (p)
294 {
295 sprintf ((char *) p, "\\x%02x", *s);
296 p += 4;
297 }
298 n += 4;
299 continue;
300 }
301 resync = 0;
302 }
303 if (!nleft)
304 {
305 if (!(*s & 0x80))
306 { /* plain ascii */
307 if (*s < 0x20 || *s == 0x7f || *s == delim ||
308 (delim && *s == '\\'))
309 {
310 n++;
311 if (p)
312 *p++ = '\\';
313 switch (*s)
314 {
315 case '\n':
316 n++;
317 if (p)
318 *p++ = 'n';
319 break;
320 case '\r':
321 n++;
322 if (p)
323 *p++ = 'r';
324 break;
325 case '\f':
326 n++;
327 if (p)
328 *p++ = 'f';
329 break;
330 case '\v':
331 n++;
332 if (p)
333 *p++ = 'v';
334 break;
335 case '\b':
336 n++;
337 if (p)
338 *p++ = 'b';
339 break;
340 case 0:
341 n++;
342 if (p)
343 *p++ = '0';
344 break;
345 default:
346 n += 3;
347 if (p)
348 {
349 sprintf ((char *) p, "x%02x", *s);
350 p += 3;
351 }
352 break;
353 }
354 }
355 else
356 {
357 if (p)
358 *p++ = *s;
359 n++;
360 }
361 }
362 else if ((*s & 0xe0) == 0xc0)
363 { /* 110x xxxx */
364 val = *s & 0x1f;
365 nleft = 1;
366 encidx = 0;
367 encbuf[encidx++] = *s;
368 }
369 else if ((*s & 0xf0) == 0xe0)
370 { /* 1110 xxxx */
371 val = *s & 0x0f;
372 nleft = 2;
373 encidx = 0;
374 encbuf[encidx++] = *s;
375 }
376 else if ((*s & 0xf8) == 0xf0)
377 { /* 1111 0xxx */
378 val = *s & 0x07;
379 nleft = 3;
380 encidx = 0;
381 encbuf[encidx++] = *s;
382 }
383 else if ((*s & 0xfc) == 0xf8)
384 { /* 1111 10xx */
385 val = *s & 0x03;
386 nleft = 4;
387 encidx = 0;
388 encbuf[encidx++] = *s;
389 }
390 else if ((*s & 0xfe) == 0xfc)
391 { /* 1111 110x */
392 val = *s & 0x01;
393 nleft = 5;
394 encidx = 0;
395 encbuf[encidx++] = *s;
396 }
397 else
398 { /* invalid encoding: print as \xnn */
399 if (p)
400 {
401 sprintf ((char *) p, "\\x%02x", *s);
402 p += 4;
403 }
404 n += 4;
405 resync = 1;
406 }
407 }
408 else if (*s < 0x80 || *s >= 0xc0)
409 { /* invalid */
410 if (p)
411 {
412 for (i = 0; i < encidx; i++)
413 {
414 sprintf ((char *) p, "\\x%02x", encbuf[i]);
415 p += 4;
416 }
417 sprintf ((char *) p, "\\x%02x", *s);
418 p += 4;
419 }
420 n += 4 + 4 * encidx;
421 nleft = 0;
422 encidx = 0;
423 resync = 1;
424 }
425 else
426 {
427 encbuf[encidx++] = *s;
428 val <<= 6;
429 val |= *s & 0x3f;
430 if (!--nleft)
431 { /* ready native set */
432 if (val >= 0x80 && val < 256)
433 {
434 n++; /* we can simply print this character */
435 if (p)
436 *p++ = val;
437 }
438 else
439 { /* we do not have a translation: print utf8 */
440 if (p)
441 {
442 for (i = 0; i < encidx; i++)
443 {
444 sprintf ((char *) p, "\\x%02x", encbuf[i]);
445 p += 4;
446 }
447 }
448 n += encidx * 4;
449 encidx = 0;
450 }
451 }
452 }
453
454 }
455 if (!buffer) /* allocate the buffer after the first pass */
456 buffer = p = cdk_malloc (n + 1);
457 else
458 {
459 *p = 0; /* make a string */
460 return (char *) buffer;
461 }
462 }
463}
464
465
466/* Map the gcrypt error to a valid opencdk error constant. */
467cdk_error_t
468_cdk_map_gcry_error (gcry_error_t err)
469{
470 /* FIXME: We need to catch them all. */
471 switch (gpg_err_code (err))
472 {
473 case GPG_ERR_NO_ERROR:
474 return CDK_Success;
475 case GPG_ERR_INV_VALUE:
476 return CDK_Inv_Value;
477 case GPG_ERR_GENERAL:
478 return CDK_General_Error;
479 case GPG_ERR_INV_PACKET:
480 return CDK_Inv_Packet;
481 case GPG_ERR_TOO_SHORT:
482 return CDK_Too_Short;
483 case GPG_ERR_TOO_LARGE:
484 return CDK_Inv_Value;
485 case GPG_ERR_NO_PUBKEY:
486 case GPG_ERR_NO_SECKEY:
487 return CDK_Error_No_Key;
488 case GPG_ERR_BAD_SIGNATURE:
489 return CDK_Bad_Sig;
490 case GPG_ERR_NO_DATA:
491 return CDK_No_Data;
492 default:
493 break;
494 }
495
496 return (cdk_error_t) err;
497}
498
499
500/* Remove all trailing white spaces from the string. */
501void
502_cdk_trim_string (char *s, int canon)
503{
504 while (s && *s &&
505 (s[strlen (s) - 1] == '\t' ||
506 s[strlen (s) - 1] == '\r' ||
507 s[strlen (s) - 1] == '\n' || s[strlen (s) - 1] == ' '))
508 s[strlen (s) - 1] = '\0';
509 if (canon)
510 strcat (s, "\r\n");
511}
512
513
514int
515_cdk_check_args (int overwrite, const char *in, const char *out)
516{
517 struct stat stbuf;
518
519 if (!in || !out)
520 return CDK_Inv_Value;
521 if (strlen (in) == strlen (out) && strcmp (in, out) == 0)
522 return CDK_Inv_Mode;
523 if (!overwrite && !stat (out, &stbuf))
524 return CDK_Inv_Mode;
525 return 0;
526}
527
528#ifdef _WIN32
529#include <io.h>
530#include <fcntl.h>
531
532FILE *
533my_tmpfile (void)
534{
535 /* Because the tmpfile() version of wine is not really useful,
536 we implement our own version to avoid problems with 'make check'. */
537 static const char *letters = "abcdefghijklmnopqrstuvwxyz";
538 char buf[512], rnd[24];
539 FILE *fp;
540 int fd, i;
541
542 gcry_create_nonce (rnd, DIM (rnd));
543 for (i = 0; i < DIM (rnd) - 1; i++)
544 {
545 char c = letters[(unsigned char) rnd[i] % 26];
546 rnd[i] = c;
547 }
548 rnd[DIM (rnd) - 1] = 0;
549 if (!GetTempPath (464, buf))
550 return NULL;
551 strcat (buf, "_cdk_");
552 strcat (buf, rnd);
553
554 /* We need to make sure the file will be deleted when it is closed. */
555 fd = _open (buf, _O_CREAT | _O_EXCL | _O_TEMPORARY |
556 _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE);
557 if (fd == -1)
558 return NULL;
559 fp = fdopen (fd, "w+b");
560 if (fp != NULL)
561 return fp;
562 _close (fd);
563 return NULL;
564}
565#else
566FILE *
567my_tmpfile (void)
568{
569 return tmpfile ();
570}
571#endif
diff --git a/src/daemon/https/opencdk/new-packet.c b/src/daemon/https/opencdk/new-packet.c
new file mode 100644
index 00000000..d6f60690
--- /dev/null
+++ b/src/daemon/https/opencdk/new-packet.c
@@ -0,0 +1,874 @@
1/* new-packet.c - packet handling (freeing, copying, ...)
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17# include <config.h>
18#endif
19#include <string.h>
20#include <stdio.h>
21#include <assert.h>
22
23#include "opencdk.h"
24#include "main.h"
25#include "packet.h"
26
27
28/* Release an array of MPI values. */
29void
30_cdk_free_mpibuf (size_t n, gcry_mpi_t * array)
31{
32 while (n--)
33 {
34 gcry_mpi_release (array[n]);
35 array[n] = NULL;
36 }
37}
38
39
40/**
41 * cdk_pkt_new:
42 * @r_pkt: the new packet
43 *
44 * Allocate a new packet.
45 **/
46cdk_error_t
47cdk_pkt_new (cdk_packet_t * r_pkt)
48{
49 cdk_packet_t pkt;
50
51 if (!r_pkt)
52 return CDK_Inv_Value;
53 pkt = cdk_calloc (1, sizeof *pkt);
54 if (!pkt)
55 return CDK_Out_Of_Core;
56 *r_pkt = pkt;
57 return 0;
58}
59
60
61static void
62free_symkey_enc (cdk_pkt_symkey_enc_t enc)
63{
64 if (!enc)
65 return;
66 cdk_s2k_free (enc->s2k);
67 cdk_free (enc);
68}
69
70
71static void
72free_pubkey_enc (cdk_pkt_pubkey_enc_t enc)
73{
74 size_t nenc;
75
76 if (!enc)
77 return;
78
79 nenc = cdk_pk_get_nenc (enc->pubkey_algo);
80 _cdk_free_mpibuf (nenc, enc->mpi);
81 cdk_free (enc);
82}
83
84
85static void
86free_literal (cdk_pkt_literal_t pt)
87{
88 if (!pt)
89 return;
90 /* The buffer which is referenced in this packet is closed
91 elsewhere. To close it here would cause a double close. */
92 cdk_free (pt);
93}
94
95
96void
97_cdk_free_userid (cdk_pkt_userid_t uid)
98{
99 if (!uid)
100 return;
101
102 cdk_free (uid->prefs);
103 uid->prefs = NULL;
104 cdk_free (uid->attrib_img);
105 uid->attrib_img = NULL;
106 cdk_free (uid);
107}
108
109
110void
111_cdk_free_signature (cdk_pkt_signature_t sig)
112{
113 cdk_desig_revoker_t r;
114 size_t nsig;
115
116 if (!sig)
117 return;
118
119 nsig = cdk_pk_get_nsig (sig->pubkey_algo);
120 _cdk_free_mpibuf (nsig, sig->mpi);
121
122 cdk_subpkt_free (sig->hashed);
123 sig->hashed = NULL;
124 cdk_subpkt_free (sig->unhashed);
125 sig->unhashed = NULL;
126 while (sig->revkeys)
127 {
128 r = sig->revkeys->next;
129 cdk_free (sig->revkeys);
130 sig->revkeys = r;
131 }
132 cdk_free (sig);
133}
134
135
136void
137cdk_pk_release (cdk_pubkey_t pk)
138{
139 size_t npkey;
140
141 if (!pk)
142 return;
143
144 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
145 _cdk_free_userid (pk->uid);
146 pk->uid = NULL;
147 cdk_free (pk->prefs);
148 pk->prefs = NULL;
149 _cdk_free_mpibuf (npkey, pk->mpi);
150 cdk_free (pk);
151}
152
153
154void
155cdk_sk_release (cdk_seckey_t sk)
156{
157 size_t nskey;
158
159 if (!sk)
160 return;
161
162 nskey = cdk_pk_get_nskey (sk->pubkey_algo);
163 _cdk_free_mpibuf (nskey, sk->mpi);
164 cdk_free (sk->encdata);
165 sk->encdata = NULL;
166 cdk_pk_release (sk->pk);
167 sk->pk = NULL;
168 cdk_s2k_free (sk->protect.s2k);
169 sk->protect.s2k = NULL;
170 cdk_free (sk);
171}
172
173
174static void
175free_encrypted (cdk_pkt_encrypted_t enc)
176{
177 if (!enc)
178 return;
179
180 /* This is just a reference for the filters to know where
181 the encrypted data starts and to read from the sream. It
182 us closed elsewhere and to close it here would double close it. */
183 /*cdk_stream_close (enc->buf); */
184 enc->buf = NULL;
185 cdk_free (enc);
186}
187
188
189/* Detach the openpgp packet from the packet structure
190 and release the packet structure itself. */
191void
192_cdk_pkt_detach_free (cdk_packet_t pkt, int *r_pkttype, void **ctx)
193{
194 /* For now we just allow this for keys. */
195 switch (pkt->pkttype)
196 {
197 case CDK_PKT_PUBLIC_KEY:
198 case CDK_PKT_PUBLIC_SUBKEY:
199 *ctx = pkt->pkt.public_key;
200 break;
201
202 case CDK_PKT_SECRET_KEY:
203 case CDK_PKT_SECRET_SUBKEY:
204 *ctx = pkt->pkt.secret_key;
205 break;
206
207 default:
208 *r_pkttype = 0;
209 return;
210 }
211
212 /* The caller might expect a specific packet type and
213 is not interested to store it for later use. */
214 if (r_pkttype)
215 *r_pkttype = pkt->pkttype;
216
217 cdk_free (pkt);
218}
219
220
221void
222cdk_pkt_free (cdk_packet_t pkt)
223{
224 if (!pkt)
225 return;
226
227 switch (pkt->pkttype)
228 {
229 case CDK_PKT_ATTRIBUTE:
230 case CDK_PKT_USER_ID:
231 _cdk_free_userid (pkt->pkt.user_id);
232 break;
233 case CDK_PKT_PUBLIC_KEY:
234 case CDK_PKT_PUBLIC_SUBKEY:
235 cdk_pk_release (pkt->pkt.public_key);
236 break;
237 case CDK_PKT_SECRET_KEY:
238 case CDK_PKT_SECRET_SUBKEY:
239 cdk_sk_release (pkt->pkt.secret_key);
240 break;
241 case CDK_PKT_SIGNATURE:
242 _cdk_free_signature (pkt->pkt.signature);
243 break;
244 case CDK_PKT_PUBKEY_ENC:
245 free_pubkey_enc (pkt->pkt.pubkey_enc);
246 break;
247 case CDK_PKT_SYMKEY_ENC:
248 free_symkey_enc (pkt->pkt.symkey_enc);
249 break;
250 case CDK_PKT_MDC:
251 cdk_free (pkt->pkt.mdc);
252 break;
253 case CDK_PKT_ENCRYPTED:
254 case CDK_PKT_ENCRYPTED_MDC:
255 free_encrypted (pkt->pkt.encrypted);
256 break;
257 case CDK_PKT_ONEPASS_SIG:
258 cdk_free (pkt->pkt.onepass_sig);
259 break;
260 case CDK_PKT_LITERAL:
261 free_literal (pkt->pkt.literal);
262 break;
263 case CDK_PKT_COMPRESSED:
264 cdk_free (pkt->pkt.compressed);
265 break;
266 default:
267 break;
268 }
269
270 /* Reset the packet type to avoid, when cdk_pkt_release() will be
271 used, that the second cdk_pkt_free() call will double free the data. */
272 pkt->pkttype = 0;
273}
274
275
276/**
277 * cdk_pkt_release:
278 * @pkt: the packet
279 *
280 * Free the contents of the given package and
281 * release the memory of the structure.
282 **/
283void
284cdk_pkt_release (cdk_packet_t pkt)
285{
286 if (!pkt)
287 return;
288 cdk_pkt_free (pkt);
289 cdk_free (pkt);
290}
291
292
293/**
294 * cdk_pkt_alloc:
295 * @r_pkt: output is the new packet
296 * @pkttype: the requested packet type
297 *
298 * Allocate a new packet structure with the given packet type.
299 **/
300cdk_error_t
301cdk_pkt_alloc (cdk_packet_t * r_pkt, int pkttype)
302{
303 cdk_packet_t pkt;
304 int rc;
305
306 if (!r_pkt)
307 return CDK_Inv_Value;
308
309 rc = cdk_pkt_new (&pkt);
310 if (rc)
311 return rc;
312
313 switch (pkttype)
314 {
315 case CDK_PKT_USER_ID:
316 pkt->pkt.user_id = cdk_calloc (1, sizeof pkt->pkt.user_id);
317 if (!pkt->pkt.user_id)
318 return CDK_Out_Of_Core;
319 break;
320
321 case CDK_PKT_PUBLIC_KEY:
322 case CDK_PKT_PUBLIC_SUBKEY:
323 pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
324 if (!pkt->pkt.public_key)
325 return CDK_Out_Of_Core;
326 break;
327
328 case CDK_PKT_SECRET_KEY:
329 case CDK_PKT_SECRET_SUBKEY:
330 pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
331 pkt->pkt.secret_key->pk =
332 cdk_calloc (1, sizeof *pkt->pkt.secret_key->pk);
333 if (!pkt->pkt.secret_key || !pkt->pkt.secret_key->pk)
334 return CDK_Out_Of_Core;
335 break;
336
337 case CDK_PKT_SIGNATURE:
338 pkt->pkt.signature = cdk_calloc (1, sizeof *pkt->pkt.signature);
339 if (!pkt->pkt.signature)
340 return CDK_Out_Of_Core;
341 break;
342
343 case CDK_PKT_SYMKEY_ENC:
344 pkt->pkt.symkey_enc = cdk_calloc (1, sizeof *pkt->pkt.symkey_enc);
345 if (!pkt->pkt.symkey_enc)
346 return CDK_Out_Of_Core;
347 break;
348
349 case CDK_PKT_PUBKEY_ENC:
350 pkt->pkt.pubkey_enc = cdk_calloc (1, sizeof *pkt->pkt.pubkey_enc);
351 if (!pkt->pkt.pubkey_enc)
352 return CDK_Out_Of_Core;
353 break;
354
355 case CDK_PKT_MDC:
356 pkt->pkt.mdc = cdk_calloc (1, sizeof *pkt->pkt.mdc);
357 if (!pkt->pkt.mdc)
358 return CDK_Out_Of_Core;
359 break;
360
361 case CDK_PKT_ENCRYPTED_MDC:
362 case CDK_PKT_ENCRYPTED:
363 pkt->pkt.symkey_enc = cdk_calloc (1, sizeof *pkt->pkt.symkey_enc);
364 if (!pkt->pkt.symkey_enc)
365 return CDK_Out_Of_Core;
366 break;
367
368 case CDK_PKT_ONEPASS_SIG:
369 pkt->pkt.onepass_sig = cdk_calloc (1, sizeof *pkt->pkt.onepass_sig);
370 if (!pkt->pkt.onepass_sig)
371 return CDK_Out_Of_Core;
372 break;
373
374 case CDK_PKT_LITERAL:
375 /* FIXME: We would need the size of the file name to allocate extra
376 bytes, otherwise the result would be useless. */
377 pkt->pkt.literal = cdk_calloc (1, sizeof *pkt->pkt.literal);
378 if (!pkt->pkt.literal)
379 return CDK_Out_Of_Core;
380 break;
381 }
382 pkt->pkttype = pkttype;
383 *r_pkt = pkt;
384 return 0;
385}
386
387
388cdk_prefitem_t
389_cdk_copy_prefs (const cdk_prefitem_t prefs)
390{
391 size_t n = 0;
392 struct cdk_prefitem_s *new_prefs;
393
394 if (!prefs)
395 return NULL;
396
397 for (n = 0; prefs[n].type; n++)
398 ;
399 new_prefs = cdk_calloc (1, sizeof *new_prefs * (n + 1));
400 if (!new_prefs)
401 return NULL;
402 for (n = 0; prefs[n].type; n++)
403 {
404 new_prefs[n].type = prefs[n].type;
405 new_prefs[n].value = prefs[n].value;
406 }
407 new_prefs[n].type = CDK_PREFTYPE_NONE;
408 new_prefs[n].value = 0;
409 return new_prefs;
410}
411
412
413cdk_error_t
414_cdk_copy_userid (cdk_pkt_userid_t * dst, cdk_pkt_userid_t src)
415{
416 cdk_pkt_userid_t u;
417
418 if (!dst || !src)
419 return CDK_Inv_Value;
420
421 *dst = NULL;
422 u = cdk_calloc (1, sizeof *u + strlen (src->name) + 1);
423 if (!u)
424 return CDK_Out_Of_Core;
425 memcpy (u, src, sizeof *u);
426 memcpy (u->name, src->name, strlen (src->name));
427 u->prefs = _cdk_copy_prefs (src->prefs);
428 if (src->selfsig)
429 _cdk_copy_signature (&u->selfsig, src->selfsig);
430 *dst = u;
431
432 return 0;
433}
434
435
436cdk_error_t
437_cdk_copy_pubkey (cdk_pkt_pubkey_t * dst, cdk_pkt_pubkey_t src)
438{
439 cdk_pkt_pubkey_t k;
440 int i;
441
442 if (!dst || !src)
443 return CDK_Inv_Value;
444
445 *dst = NULL;
446 k = cdk_calloc (1, sizeof *k);
447 if (!k)
448 return CDK_Out_Of_Core;
449 memcpy (k, src, sizeof *k);
450 if (src->uid)
451 _cdk_copy_userid (&k->uid, src->uid);
452 if (src->prefs)
453 k->prefs = _cdk_copy_prefs (src->prefs);
454 for (i = 0; i < cdk_pk_get_npkey (src->pubkey_algo); i++)
455 k->mpi[i] = gcry_mpi_copy (src->mpi[i]);
456 *dst = k;
457
458 return 0;
459}
460
461
462cdk_error_t
463_cdk_copy_seckey (cdk_pkt_seckey_t * dst, cdk_pkt_seckey_t src)
464{
465 cdk_pkt_seckey_t k;
466 int i;
467
468 if (!dst || !src)
469 return CDK_Inv_Value;
470
471 *dst = NULL;
472 k = cdk_calloc (1, sizeof *k);
473 if (!k)
474 return CDK_Out_Of_Core;
475 memcpy (k, src, sizeof *k);
476 _cdk_copy_pubkey (&k->pk, src->pk);
477
478 if (src->encdata)
479 {
480 k->encdata = cdk_calloc (1, src->enclen + 1);
481 if (!k->encdata)
482 return CDK_Out_Of_Core;
483 memcpy (k->encdata, src->encdata, src->enclen);
484 }
485
486 _cdk_s2k_copy (&k->protect.s2k, src->protect.s2k);
487
488 for (i = 0; i < cdk_pk_get_nskey (src->pubkey_algo); i++)
489 {
490 k->mpi[i] = gcry_mpi_copy (src->mpi[i]);
491 gcry_mpi_set_flag (k->mpi[i], GCRYMPI_FLAG_SECURE);
492 }
493
494 *dst = k;
495 return 0;
496}
497
498
499cdk_error_t
500_cdk_copy_pk_to_sk (cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk)
501{
502 if (!pk || !sk)
503 return CDK_Inv_Value;
504
505 sk->version = pk->version;
506 sk->expiredate = pk->expiredate;
507 sk->pubkey_algo = pk->pubkey_algo;
508 sk->has_expired = pk->has_expired;
509 sk->is_revoked = pk->is_revoked;
510 sk->main_keyid[0] = pk->main_keyid[0];
511 sk->main_keyid[1] = pk->main_keyid[1];
512 sk->keyid[0] = pk->keyid[0];
513 sk->keyid[1] = pk->keyid[1];
514
515 return 0;
516}
517
518
519cdk_error_t
520_cdk_copy_signature (cdk_pkt_signature_t * dst, cdk_pkt_signature_t src)
521{
522 cdk_pkt_signature_t s;
523
524 if (!dst || !src)
525 return CDK_Inv_Value;
526
527 *dst = NULL;
528 s = cdk_calloc (1, sizeof *s);
529 if (!s)
530 return CDK_Out_Of_Core;
531 memcpy (s, src, sizeof *src);
532 _cdk_subpkt_copy (&s->hashed, src->hashed);
533 _cdk_subpkt_copy (&s->unhashed, src->unhashed);
534 /* FIXME: Copy MPI parts */
535 *dst = s;
536
537 return 0;
538}
539
540
541cdk_error_t
542_cdk_pubkey_compare (cdk_pkt_pubkey_t a, cdk_pkt_pubkey_t b)
543{
544 int na, nb, i;
545
546 if (a->timestamp != b->timestamp || a->pubkey_algo != b->pubkey_algo)
547 return -1;
548 if (a->version < 4 && a->expiredate != b->expiredate)
549 return -1;
550 na = cdk_pk_get_npkey (a->pubkey_algo);
551 nb = cdk_pk_get_npkey (b->pubkey_algo);
552 if (na != nb)
553 return -1;
554
555 for (i = 0; i < na; i++)
556 {
557 if (gcry_mpi_cmp (a->mpi[i], b->mpi[i]))
558 return -1;
559 }
560
561 return 0;
562}
563
564
565/**
566 * cdk_subpkt_free:
567 * @ctx: the sub packet node to free
568 *
569 * Release the context.
570 **/
571void
572cdk_subpkt_free (cdk_subpkt_t ctx)
573{
574 cdk_subpkt_t s;
575
576 while (ctx)
577 {
578 s = ctx->next;
579 cdk_free (ctx);
580 ctx = s;
581 }
582}
583
584
585/**
586 * cdk_subpkt_find:
587 * @ctx: the sub packet node
588 * @type: the packet type to find
589 *
590 * Find the given packet type in the node. If no packet with this
591 * type was found, return null otherwise pointer to the node.
592 **/
593cdk_subpkt_t
594cdk_subpkt_find (cdk_subpkt_t ctx, size_t type)
595{
596 return cdk_subpkt_find_nth (ctx, type, 0);
597}
598
599/**
600 * cdk_subpkt_type_count:
601 * @ctx: The sub packet context
602 * @type: The sub packet type.
603 *
604 * Return the amount of sub packets with this type.
605 **/
606size_t
607cdk_subpkt_type_count (cdk_subpkt_t ctx, size_t type)
608{
609 cdk_subpkt_t s;
610 size_t count;
611
612 count = 0;
613 for (s = ctx; s; s = s->next)
614 {
615 if (s->type == type)
616 count++;
617 }
618
619 return count;
620}
621
622
623/**
624 * cdk_subpkt_find_nth:
625 * @ctx: The sub packet context
626 * @type: The sub packet type
627 * @index: The nth packet to retrieve, 0 means the first
628 *
629 * Return the nth sub packet of the given type.
630 **/
631cdk_subpkt_t
632cdk_subpkt_find_nth (cdk_subpkt_t ctx, size_t type, size_t idx)
633{
634 cdk_subpkt_t s;
635 size_t pos;
636
637 pos = 0;
638 for (s = ctx; s; s = s->next)
639 {
640 if (s->type == type && pos++ == idx)
641 return s;
642 }
643
644 return NULL;
645}
646
647
648/**
649 * cdk_subpkt_new:
650 * @size: the size of the new context
651 *
652 * Create a new sub packet node with the size of @size.
653 **/
654cdk_subpkt_t
655cdk_subpkt_new (size_t size)
656{
657 cdk_subpkt_t s;
658
659 if (!size)
660 return NULL;
661 s = cdk_calloc (1, sizeof *s + size + 1);
662 if (!s)
663 return NULL;
664 return s;
665}
666
667
668/**
669 * cdk_subpkt_get_data:
670 * @ctx: the sub packet node
671 * @r_type: pointer store the packet type
672 * @r_nbytes: pointer to store the packet size
673 *
674 * Extract the data from the given sub packet. The type is returned
675 * in @r_type and the size in @r_nbytes.
676 **/
677const byte *
678cdk_subpkt_get_data (cdk_subpkt_t ctx, size_t * r_type, size_t * r_nbytes)
679{
680 if (!ctx || !r_nbytes)
681 return NULL;
682 if (r_type)
683 *r_type = ctx->type;
684 *r_nbytes = ctx->size;
685 return ctx->d;
686}
687
688
689/**
690 * cdk_subpkt_add:
691 * @root: the root node
692 * @node: the node to add
693 *
694 * Add the node in @node to the root node @root.
695 **/
696cdk_error_t
697cdk_subpkt_add (cdk_subpkt_t root, cdk_subpkt_t node)
698{
699 cdk_subpkt_t n1;
700
701 if (!root)
702 return CDK_Inv_Value;
703 for (n1 = root; n1->next; n1 = n1->next)
704 ;
705 n1->next = node;
706 return 0;
707}
708
709
710byte *
711_cdk_subpkt_get_array (cdk_subpkt_t s, int count, size_t * r_nbytes)
712{
713 cdk_subpkt_t list;
714 byte *buf;
715 size_t n, nbytes;
716
717 if (!s)
718 {
719 if (r_nbytes)
720 *r_nbytes = 0;
721 return NULL;
722 }
723
724 for (n = 0, list = s; list; list = list->next)
725 {
726 n++; /* type */
727 n += list->size;
728 if (list->size < 192)
729 n++;
730 else if (list->size < 8384)
731 n += 2;
732 else
733 n += 5;
734 }
735 buf = cdk_calloc (1, n + 1);
736 if (!buf)
737 return NULL;
738
739 n = 0;
740 for (list = s; list; list = list->next)
741 {
742 nbytes = 1 + list->size; /* type */
743 if (nbytes < 192)
744 buf[n++] = nbytes;
745 else if (nbytes < 8384)
746 {
747 buf[n++] = nbytes / 256 + 192;
748 buf[n++] = nbytes % 256;
749 }
750 else
751 {
752 buf[n++] = 0xFF;
753 buf[n++] = nbytes >> 24;
754 buf[n++] = nbytes >> 16;
755 buf[n++] = nbytes >> 8;
756 buf[n++] = nbytes;
757 }
758 buf[n++] = list->type;
759 memcpy (buf + n, list->d, list->size);
760 n += list->size;
761 }
762
763 if (count)
764 {
765 cdk_free (buf);
766 buf = NULL;
767 }
768 if (r_nbytes)
769 *r_nbytes = n;
770 return buf;
771}
772
773
774cdk_error_t
775_cdk_subpkt_copy (cdk_subpkt_t * r_dst, cdk_subpkt_t src)
776{
777 cdk_subpkt_t root, p, node;
778
779 if (!src || !r_dst)
780 return CDK_Inv_Value;
781
782 root = NULL;
783 for (p = src; p; p = p->next)
784 {
785 node = cdk_subpkt_new (p->size);
786 if (node)
787 {
788 memcpy (node->d, p->d, p->size);
789 node->type = p->type;
790 node->size = p->size;
791 }
792 if (!root)
793 root = node;
794 else
795 cdk_subpkt_add (root, node);
796 }
797 *r_dst = root;
798 return 0;
799}
800
801
802/**
803 * cdk_subpkt_init:
804 * @node: the sub packet node
805 * @type: type of the packet which data should be initialized
806 * @buf: the buffer with the actual data
807 * @buflen: the size of the data
808 *
809 * Set the packet data of the given root and set the type of it.
810 **/
811void
812cdk_subpkt_init (cdk_subpkt_t node, size_t type,
813 const void *buf, size_t buflen)
814{
815 if (!node)
816 return;
817 node->type = type;
818 node->size = buflen;
819 memcpy (node->d, buf, buflen);
820}
821
822
823/* FIXME: We need to think of a public interface for it. */
824const byte *
825cdk_key_desig_revoker_walk (cdk_desig_revoker_t root,
826 cdk_desig_revoker_t * ctx,
827 int *r_class, int *r_algid)
828{
829 cdk_desig_revoker_t n;
830
831 if (!*ctx)
832 {
833 *ctx = root;
834 n = root;
835 }
836 else
837 {
838 n = (*ctx)->next;
839 *ctx = n;
840 }
841
842 if (n && r_class && r_algid)
843 {
844 *r_class = n->r_class;
845 *r_algid = n->algid;
846 }
847
848 return n ? n->fpr : NULL;
849}
850
851
852/**
853 * cdk_subpkt_find_next:
854 * @root: the base where to begin the iteration
855 * @type: the type to find or 0 for the next node.
856 *
857 * Try to find the next node after @root with type.
858 * If type is 0, the next node will be returned.
859 **/
860cdk_subpkt_t
861cdk_subpkt_find_next (cdk_subpkt_t root, size_t type)
862{
863 cdk_subpkt_t node;
864
865 for (node = root->next; node; node = node->next)
866 {
867 if (!type)
868 return node;
869 else if (node->type == type)
870 return node;
871 }
872
873 return NULL;
874}
diff --git a/src/daemon/https/opencdk/opencdk.h b/src/daemon/https/opencdk/opencdk.h
new file mode 100644
index 00000000..83ca487e
--- /dev/null
+++ b/src/daemon/https/opencdk/opencdk.h
@@ -0,0 +1,1169 @@
1/* opencdk.h - Open Crypto Development Kit (OpenCDK)
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 * Copyright (C) 2006, 2007 Free Software Foundation, Inc.
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17
18#ifndef OPENCDK_H
19#define OPENCDK_H
20
21#include <stddef.h> /* for size_t */
22#include <stdarg.h>
23#include <gcrypt.h>
24
25/* The OpenCDK version as a string. */
26#define OPENCDK_VERSION "0.6.6"
27
28/* The OpenCDK version as integer components major.minor.path */
29#define OPENCDK_VERSION_MAJOR 0
30#define OPENCDK_VERSION_MINOR 6
31#define OPENCDK_VERSION_PATCH 6
32
33#ifdef __cplusplus
34extern "C" {
35#if 0
36}
37#endif
38#endif
39
40/* General contexts */
41
42/* 'Session' handle to support the various options and run-time
43 information. */
44struct cdk_ctx_s;
45typedef struct cdk_ctx_s *cdk_ctx_t;
46
47/* A generic context to store list of strings. */
48struct cdk_strlist_s;
49typedef struct cdk_strlist_s *cdk_strlist_t;
50
51/* Context used to list keys of a keyring. */
52struct cdk_listkey_s;
53typedef struct cdk_listkey_s *cdk_listkey_t;
54
55/* Opaque Data Encryption Key (DEK) context. */
56struct cdk_dek_s;
57typedef struct cdk_dek_s *cdk_dek_t;
58
59/* Opaque String to Key (S2K) handle. */
60struct cdk_s2k_s;
61typedef struct cdk_s2k_s *cdk_s2k_t;
62
63/* Abstract I/O object, a stream, which is used for most operations. */
64struct cdk_stream_s;
65typedef struct cdk_stream_s *cdk_stream_t;
66
67/* Opaque handle for the user ID preferences. */
68struct cdk_prefitem_s;
69typedef struct cdk_prefitem_s *cdk_prefitem_t;
70
71/* Node to store a single key node packet. */
72struct cdk_kbnode_s;
73typedef struct cdk_kbnode_s *cdk_kbnode_t;
74
75/* Key database handle. */
76struct cdk_keydb_hd_s;
77typedef struct cdk_keydb_hd_s *cdk_keydb_hd_t;
78
79/* Context to store a list of recipient keys. */
80struct cdk_keylist_s;
81typedef struct cdk_keylist_s *cdk_keylist_t;
82
83/* Context to encapsulate a single sub packet of a signature. */
84struct cdk_subpkt_s;
85typedef struct cdk_subpkt_s *cdk_subpkt_t;
86
87/* Context used to generate key pairs. */
88struct cdk_keygen_ctx_s;
89typedef struct cdk_keygen_ctx_s *cdk_keygen_ctx_t;
90
91/* Handle for a single designated revoker. */
92struct cdk_desig_revoker_s;
93typedef struct cdk_desig_revoker_s *cdk_desig_revoker_t;
94
95/* Alias for backward compatibility. */
96typedef gcry_mpi_t cdk_mpi_t;
97
98
99/* All valid error constants. */
100typedef enum {
101 CDK_EOF = -1,
102 CDK_Success = 0,
103 CDK_General_Error = 1,
104 CDK_File_Error = 2,
105 CDK_Bad_Sig = 3,
106 CDK_Inv_Packet = 4,
107 CDK_Inv_Algo = 5,
108 CDK_Not_Implemented = 6,
109 CDK_Armor_Error = 8,
110 CDK_Armor_CRC_Error = 9,
111 CDK_MPI_Error = 10,
112 CDK_Inv_Value = 11,
113 CDK_Error_No_Key = 12,
114 CDK_Chksum_Error = 13,
115 CDK_Time_Conflict = 14,
116 CDK_Zlib_Error = 15,
117 CDK_Weak_Key = 16,
118 CDK_Out_Of_Core = 17,
119 CDK_Wrong_Seckey = 18,
120 CDK_Bad_MDC = 19,
121 CDK_Inv_Mode = 20,
122 CDK_Error_No_Keyring = 21,
123 CDK_Wrong_Format = 22,
124 CDK_Inv_Packet_Ver = 23,
125 CDK_Too_Short = 24,
126 CDK_Unusable_Key = 25,
127 CDK_No_Data = 26,
128 CDK_No_Passphrase = 27,
129 CDK_Network_Error = 28
130} cdk_error_t;
131
132
133enum cdk_control_flags {
134 CDK_CTLF_SET = 0, /* Value to set an option */
135 CDK_CTLF_GET = 1, /* Value to get an option */
136 CDK_CTL_DIGEST = 10, /* Option to set the digest algorithm. */
137 CDK_CTL_CIPHER = 11, /* Option to set the cipher algorithm. */
138 CDK_CTL_ARMOR = 12, /* Option to enable armor output. */
139 CDK_CTL_COMPRESS = 13, /* Option to enable compression. */
140 CDK_CTL_COMPAT = 14, /* Option to switch in compat mode. */
141 CDK_CTL_OVERWRITE = 15, /* Option to enable file overwritting. */
142 CDK_CTL_S2K = 16, /* Option to set S2K values. */
143 CDK_CTL_FORCE_DIGEST = 19, /* Force the use of a digest algorithm. */
144 CDK_CTL_BLOCKMODE_ON = 20 /* Enable partial body lengths */
145};
146
147
148/* Specifies all valid log levels. */
149enum cdk_log_level_t {
150 CDK_LOG_NONE = 0, /* No log message will be shown. */
151 CDK_LOG_INFO = 1,
152 CDK_LOG_DEBUG = 2,
153 CDK_LOG_DEBUG_PKT = 3
154};
155
156
157/* All valid compression algorithms in OpenPGP */
158enum cdk_compress_algo_t {
159 CDK_COMPRESS_NONE = 0,
160 CDK_COMPRESS_ZIP = 1,
161 CDK_COMPRESS_ZLIB = 2,
162 CDK_COMPRESS_BZIP2 = 3 /* Not supported in this version */
163};
164
165
166/* All valid public key algorithms valid in OpenPGP */
167enum cdk_pubkey_algo_t {
168 CDK_PK_RSA = 1,
169 CDK_PK_RSA_E = 2, /* RSA-E and RSA-S are deprecated use RSA instead */
170 CDK_PK_RSA_S = 3, /* and use the key flags in the self signatures. */
171 CDK_PK_ELG_E = 16,
172 CDK_PK_DSA = 17
173};
174
175
176/* All valid message digest algorithms in OpenPGP. */
177enum cdk_digest_algo_t {
178 CDK_MD_NONE = 0,
179 CDK_MD_MD5 = 1,
180 CDK_MD_SHA1 = 2,
181 CDK_MD_RMD160 = 3,
182 CDK_MD_SHA256 = 8,
183 CDK_MD_SHA384 = 9,
184 CDK_MD_SHA512 = 10,
185 CDK_MD_SHA224 = 11 /* This algorithm is NOT available. */
186};
187
188
189/* All valid symmetric cipher algorithms in OpenPGP */
190enum cdk_cipher_algo_t {
191 CDK_CIPHER_NONE = 0,
192 CDK_CIPHER_IDEA = 1, /* This algorithm is NOT available */
193 CDK_CIPHER_3DES = 2,
194 CDK_CIPHER_CAST5 = 3,
195 CDK_CIPHER_BLOWFISH = 4,
196 CDK_CIPHER_AES = 7,
197 CDK_CIPHER_AES192 = 8,
198 CDK_CIPHER_AES256 = 9,
199 CDK_CIPHER_TWOFISH = 10
200};
201
202
203/* The valid 'String-To-Key' modes */
204enum cdk_s2k_type_t {
205 CDK_S2K_SIMPLE = 0,
206 CDK_S2K_SALTED = 1,
207 CDK_S2K_ITERSALTED = 3
208};
209
210
211/* The different kind of user ID preferences. */
212enum cdk_pref_type_t {
213 CDK_PREFTYPE_NONE = 0,
214 CDK_PREFTYPE_SYM = 1, /* Symmetric ciphers */
215 CDK_PREFTYPE_HASH = 2, /* Message digests */
216 CDK_PREFTYPE_ZIP = 3 /* Compression algorithms */
217};
218
219
220/* All valid sub packet types. */
221enum cdk_sig_subpacket_t {
222 CDK_SIGSUBPKT_NONE = 0,
223 CDK_SIGSUBPKT_SIG_CREATED = 2,
224 CDK_SIGSUBPKT_SIG_EXPIRE = 3,
225 CDK_SIGSUBPKT_EXPORTABLE = 4,
226 CDK_SIGSUBPKT_TRUST = 5,
227 CDK_SIGSUBPKT_REGEXP = 6,
228 CDK_SIGSUBPKT_REVOCABLE = 7,
229 CDK_SIGSUBPKT_KEY_EXPIRE = 9,
230 CDK_SIGSUBPKT_PREFS_SYM = 11,
231 CDK_SIGSUBPKT_REV_KEY = 12,
232 CDK_SIGSUBPKT_ISSUER = 16,
233 CDK_SIGSUBPKT_NOTATION = 20,
234 CDK_SIGSUBPKT_PREFS_HASH = 21,
235 CDK_SIGSUBPKT_PREFS_ZIP = 22,
236 CDK_SIGSUBPKT_KS_FLAGS = 23,
237 CDK_SIGSUBPKT_PREF_KS = 24,
238 CDK_SIGSUBPKT_PRIMARY_UID = 25,
239 CDK_SIGSUBPKT_POLICY = 26,
240 CDK_SIGSUBPKT_KEY_FLAGS = 27,
241 CDK_SIGSUBPKT_SIGNERS_UID = 28,
242 CDK_SIGSUBPKT_REVOC_REASON = 29,
243 CDK_SIGSUBPKT_FEATURES = 30
244};
245
246
247/* All valid armor types. */
248enum cdk_armor_type_t {
249 CDK_ARMOR_MESSAGE = 0,
250 CDK_ARMOR_PUBKEY = 1,
251 CDK_ARMOR_SECKEY = 2,
252 CDK_ARMOR_SIGNATURE = 3,
253 CDK_ARMOR_CLEARSIG = 4
254};
255
256enum cdk_keydb_flag_t {
257 /* Valid database search modes */
258 CDK_DBSEARCH_EXACT = 1, /* Exact string search */
259 CDK_DBSEARCH_SUBSTR = 2, /* Sub string search */
260 CDK_DBSEARCH_SHORT_KEYID = 3, /* 32-bit keyid search */
261 CDK_DBSEARCH_KEYID = 4, /* 64-bit keyid search */
262 CDK_DBSEARCH_FPR = 5, /* 160-bit fingerprint search */
263 CDK_DBSEARCH_NEXT = 6, /* Enumerate all keys */
264 CDK_DBSEARCH_AUTO = 7, /* Try to classify the string */
265 /* Valid database types */
266 CDK_DBTYPE_PK_KEYRING = 100, /* A file with one or more public keys */
267 CDK_DBTYPE_SK_KEYRING = 101, /* A file with one or more secret keys */
268 CDK_DBTYPE_DATA = 102, /* A buffer with at least one public key */
269 CDK_DBTYPE_STREAM = 103 /* A stream is used to read keys from */
270};
271
272
273/* All valid modes for cdk_data_transform() */
274enum cdk_crypto_mode_t {
275 CDK_CRYPTYPE_NONE = 0,
276 CDK_CRYPTYPE_ENCRYPT = 1,
277 CDK_CRYPTYPE_DECRYPT = 2,
278 CDK_CRYPTYPE_SIGN = 3,
279 CDK_CRYPTYPE_VERIFY = 4,
280 CDK_CRYPTYPE_EXPORT = 5,
281 CDK_CRYPTYPE_IMPORT = 6
282};
283
284
285/* A list of valid public key usages. */
286enum cdk_key_usage_t {
287 CDK_KEY_USG_ENCR = 1, /* Key can be used for encryption. */
288 CDK_KEY_USG_SIGN = 2, /* Key can be used for signing and certifying. */
289 CDK_KEY_USG_AUTH = 4 /* Key can be used for authentication. */
290};
291
292
293/* Valid flags for keys. */
294enum cdk_key_flag_t {
295 CDK_KEY_VALID = 0,
296 CDK_KEY_INVALID = 1, /* Missing or wrong self signature */
297 CDK_KEY_EXPIRED = 2, /* Key is expired. */
298 CDK_KEY_REVOKED = 4, /* Key has been revoked. */
299 CDK_KEY_NOSIGNER = 8
300};
301
302
303/* Trust values and flags for keys and user IDs */
304enum cdk_trust_flag_t {
305 CDK_TRUST_UNKNOWN = 0,
306 CDK_TRUST_EXPIRED = 1,
307 CDK_TRUST_UNDEFINED = 2,
308 CDK_TRUST_NEVER = 3,
309 CDK_TRUST_MARGINAL = 4,
310 CDK_TRUST_FULLY = 5,
311 CDK_TRUST_ULTIMATE = 6,
312 /* trust flags */
313 CDK_TFLAG_REVOKED = 32,
314 CDK_TFLAG_SUB_REVOKED = 64,
315 CDK_TFLAG_DISABLED = 128
316};
317
318
319/* Signature states and the signature modes. */
320enum cdk_signature_stat_t {
321 /* Signature status */
322 CDK_SIGSTAT_NONE = 0,
323 CDK_SIGSTAT_GOOD = 1,
324 CDK_SIGSTAT_BAD = 2,
325 CDK_SIGSTAT_NOKEY = 3,
326 CDK_SIGSTAT_VALID = 4, /* True if made with a valid key. */
327 /* FIXME: We need indicators for revoked/expires signatures. */
328
329 /* Signature modes */
330 CDK_SIGMODE_NORMAL = 100,
331 CDK_SIGMODE_DETACHED = 101,
332 CDK_SIGMODE_CLEAR = 102
333};
334
335
336/* Key flags. */
337typedef enum {
338 CDK_FLAG_KEY_REVOKED = 256,
339 CDK_FLAG_KEY_EXPIRED = 512,
340 CDK_FLAG_SIG_EXPIRED = 1024
341} cdk_key_flags_t;
342
343
344/* Possible format for the literal data. */
345typedef enum {
346 CDK_LITFMT_BINARY = 0,
347 CDK_LITFMT_TEXT = 1,
348 CDK_LITFMT_UNICODE= 2
349} cdk_lit_format_t;
350
351/* Valid OpenPGP packet types and their IDs */
352typedef enum {
353 CDK_PKT_RESERVED = 0,
354 CDK_PKT_PUBKEY_ENC = 1,
355 CDK_PKT_SIGNATURE = 2,
356 CDK_PKT_SYMKEY_ENC = 3,
357 CDK_PKT_ONEPASS_SIG = 4,
358 CDK_PKT_SECRET_KEY = 5,
359 CDK_PKT_PUBLIC_KEY = 6,
360 CDK_PKT_SECRET_SUBKEY = 7,
361 CDK_PKT_COMPRESSED = 8,
362 CDK_PKT_ENCRYPTED = 9,
363 CDK_PKT_MARKER = 10,
364 CDK_PKT_LITERAL = 11,
365 CDK_PKT_RING_TRUST = 12,
366 CDK_PKT_USER_ID = 13,
367 CDK_PKT_PUBLIC_SUBKEY = 14,
368 CDK_PKT_OLD_COMMENT = 16,
369 CDK_PKT_ATTRIBUTE = 17,
370 CDK_PKT_ENCRYPTED_MDC = 18,
371 CDK_PKT_MDC = 19
372} cdk_packet_type_t;
373
374/* Define the maximal number of multiprecion integers for
375 a public key. */
376#define MAX_CDK_PK_PARTS 4
377
378/* Define the maximal number of multiprecision integers for
379 a signature/encrypted blob issued by a secret key. */
380#define MAX_CDK_DATA_PARTS 2
381
382
383/* Helper macro to figure out if the packet is encrypted */
384#define CDK_PKT_IS_ENCRYPTED(pkttype) (\
385 ((pkttype)==CDK_PKT_ENCRYPTED_MDC) \
386 || ((pkttype)==CDK_PKT_ENCRYPTED))
387
388
389struct cdk_pkt_signature_s {
390 unsigned char version;
391 unsigned char sig_class;
392 unsigned int timestamp;
393 unsigned int expiredate;
394 unsigned int keyid[2];
395 unsigned char pubkey_algo;
396 unsigned char digest_algo;
397 unsigned char digest_start[2];
398 unsigned short hashed_size;
399 cdk_subpkt_t hashed;
400 unsigned short unhashed_size;
401 cdk_subpkt_t unhashed;
402 gcry_mpi_t mpi[MAX_CDK_DATA_PARTS];
403 cdk_desig_revoker_t revkeys;
404 struct {
405 unsigned exportable:1;
406 unsigned revocable:1;
407 unsigned policy_url:1;
408 unsigned notation:1;
409 unsigned expired:1;
410 unsigned checked:1;
411 unsigned valid:1;
412 unsigned missing_key:1;
413 } flags;
414 unsigned int key[2]; /* only valid for key signatures */
415};
416typedef struct cdk_pkt_signature_s *cdk_pkt_signature_t;
417
418
419struct cdk_pkt_userid_s {
420 unsigned int len;
421 unsigned is_primary:1;
422 unsigned is_revoked:1;
423 unsigned mdc_feature:1;
424 cdk_prefitem_t prefs;
425 size_t prefs_size;
426 unsigned char * attrib_img; /* Tag 17 if not null */
427 size_t attrib_len;
428 cdk_pkt_signature_t selfsig;
429 char name[1];
430};
431typedef struct cdk_pkt_userid_s *cdk_pkt_userid_t;
432
433
434struct cdk_pkt_pubkey_s {
435 unsigned char version;
436 unsigned char pubkey_algo;
437 unsigned char fpr[20];
438 unsigned int keyid[2];
439 unsigned int main_keyid[2];
440 unsigned int timestamp;
441 unsigned int expiredate;
442 gcry_mpi_t mpi[MAX_CDK_PK_PARTS];
443 unsigned is_revoked:1;
444 unsigned is_invalid:1;
445 unsigned has_expired:1;
446 int pubkey_usage;
447 cdk_pkt_userid_t uid;
448 cdk_prefitem_t prefs;
449 size_t prefs_size;
450 cdk_desig_revoker_t revkeys;
451};
452typedef struct cdk_pkt_pubkey_s *cdk_pkt_pubkey_t;
453
454/* Alias to define a generic public key context. */
455typedef cdk_pkt_pubkey_t cdk_pubkey_t;
456
457
458struct cdk_pkt_seckey_s {
459 cdk_pkt_pubkey_t pk;
460 unsigned int expiredate;
461 int version;
462 int pubkey_algo;
463 unsigned int keyid[2];
464 unsigned int main_keyid[2];
465 unsigned char s2k_usage;
466 struct {
467 unsigned char algo;
468 unsigned char sha1chk; /* SHA1 is used instead of a 16 bit checksum */
469 cdk_s2k_t s2k;
470 unsigned char iv[16];
471 unsigned char ivlen;
472 } protect;
473 unsigned short csum;
474 gcry_mpi_t mpi[MAX_CDK_PK_PARTS];
475 unsigned char * encdata;
476 size_t enclen;
477 unsigned char is_protected;
478 unsigned is_primary:1;
479 unsigned has_expired:1;
480 unsigned is_revoked:1;
481};
482typedef struct cdk_pkt_seckey_s *cdk_pkt_seckey_t;
483
484/* Alias to define a generic secret key context. */
485typedef cdk_pkt_seckey_t cdk_seckey_t;
486
487
488struct cdk_pkt_onepass_sig_s {
489 unsigned char version;
490 unsigned int keyid[2];
491 unsigned char sig_class;
492 unsigned char digest_algo;
493 unsigned char pubkey_algo;
494 unsigned char last;
495};
496typedef struct cdk_pkt_onepass_sig_s * cdk_pkt_onepass_sig_t;
497
498
499struct cdk_pkt_pubkey_enc_s {
500 unsigned char version;
501 unsigned int keyid[2];
502 int throw_keyid;
503 unsigned char pubkey_algo;
504 gcry_mpi_t mpi[MAX_CDK_DATA_PARTS];
505};
506typedef struct cdk_pkt_pubkey_enc_s * cdk_pkt_pubkey_enc_t;
507
508
509struct cdk_pkt_symkey_enc_s {
510 unsigned char version;
511 unsigned char cipher_algo;
512 cdk_s2k_t s2k;
513 unsigned char seskeylen;
514 unsigned char seskey[32];
515};
516typedef struct cdk_pkt_symkey_enc_s *cdk_pkt_symkey_enc_t;
517
518
519struct cdk_pkt_encrypted_s {
520 unsigned int len;
521 int extralen;
522 unsigned char mdc_method;
523 cdk_stream_t buf;
524};
525typedef struct cdk_pkt_encrypted_s *cdk_pkt_encrypted_t;
526
527
528struct cdk_pkt_mdc_s {
529 unsigned char hash[20];
530};
531typedef struct cdk_pkt_mdc_s *cdk_pkt_mdc_t;
532
533
534struct cdk_pkt_literal_s {
535 unsigned int len;
536 cdk_stream_t buf;
537 int mode;
538 unsigned int timestamp;
539 int namelen;
540 char name[1];
541};
542typedef struct cdk_pkt_literal_s *cdk_pkt_literal_t;
543
544
545struct cdk_pkt_compressed_s {
546 unsigned int len;
547 int algorithm;
548 cdk_stream_t buf;
549};
550typedef struct cdk_pkt_compressed_s *cdk_pkt_compressed_t;
551
552
553/* Structure which represents a single OpenPGP packet. */
554struct cdk_packet_s {
555 size_t pktlen; /* real packet length */
556 size_t pktsize; /* length with all headers */
557 int old_ctb; /* 1 if RFC1991 mode is used */
558 cdk_packet_type_t pkttype;
559 union {
560 cdk_pkt_mdc_t mdc;
561 cdk_pkt_userid_t user_id;
562 cdk_pkt_pubkey_t public_key;
563 cdk_pkt_seckey_t secret_key;
564 cdk_pkt_signature_t signature;
565 cdk_pkt_pubkey_enc_t pubkey_enc;
566 cdk_pkt_symkey_enc_t symkey_enc;
567 cdk_pkt_compressed_t compressed;
568 cdk_pkt_encrypted_t encrypted;
569 cdk_pkt_literal_t literal;
570 cdk_pkt_onepass_sig_t onepass_sig;
571 } pkt;
572};
573typedef struct cdk_packet_s *cdk_packet_t;
574
575/* memory routines */
576typedef void (*cdk_log_fnc_t) (void *, int, const char *, va_list);
577
578/* Set the log level. */
579void cdk_set_log_level (int lvl);
580
581/* Set a custom log handler which is used for logging. */
582void cdk_set_log_handler (cdk_log_fnc_t logfnc, void *opaque);
583
584/* Return a human readable error description of the given error coe. */
585const char* cdk_strerror (int ec);
586
587/* Allow the user to set custom hooks for memory allocation.
588 If this function is not used, the standard allocation functions
589 will be used. Extra care must be taken for the 'secure' alloc
590 function. */
591void cdk_set_malloc_hooks (void *(*new_alloc_func) (size_t n),
592 void *(*new_alloc_secure_func) (size_t n),
593 void *(*new_realloc_func) (void *p, size_t n),
594 void *(*new_calloc_func) (size_t m, size_t n),
595 void (*new_free_func) (void *));
596
597/* Return 1 if the malloc hooks were already set via the function above. */
598int cdk_malloc_hook_initialized (void);
599
600/* Standard memory wrapper. */
601void *cdk_malloc (size_t size);
602void *cdk_calloc (size_t n, size_t m);
603void *cdk_realloc (void * ptr, size_t size);
604void *cdk_salloc (size_t size, int clear);
605char *cdk_strdup (const char * ptr);
606void cdk_free (void * ptr);
607
608/* Startup routines. */
609
610/* This function has to be called before any other
611 CDK function is executed. */
612void cdk_lib_startup (void);
613
614/* This function should be called before the application exists
615 to allow the lib to cleanup its internal structures. */
616void cdk_lib_shutdown (void);
617
618/* Session handle routines */
619cdk_error_t cdk_handle_new (cdk_ctx_t *r_ctx);
620void cdk_handle_free (cdk_ctx_t c);
621
622/* Set the key database handle for the given session handle.
623 The type of the key db handle (public or secret) decides
624 which session key db handle to use. */
625void cdk_handle_set_keydb (cdk_ctx_t hd, cdk_keydb_hd_t db);
626
627/* Convenient function to avoid to open a key db first.
628 The user can directly use the file name, the rest is
629 done internally. */
630cdk_error_t cdk_handle_set_keyring (cdk_ctx_t hd, int type,
631 const char *kringname);
632
633/* Return keydb handle stored in the session handle. */
634cdk_keydb_hd_t cdk_handle_get_keydb (cdk_ctx_t hd, int type);
635int cdk_handle_control (cdk_ctx_t hd, int action, int cmd, ...);
636
637/* Set a passphrase callback for the given session handle. */
638void cdk_handle_set_passphrase_cb (cdk_ctx_t hd,
639 char *(*cb) (void *opa, const char *prompt),
640 void *cb_value);
641
642/* shortcuts for some controls */
643
644/* Enable or disable armor output. */
645#define cdk_handle_set_armor(a, val) \
646 cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_ARMOR, (val))
647
648/* Set the compression algorithm and level. 0 means disable compression. */
649#define cdk_handle_set_compress(a, algo, level) \
650 cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_COMPRESS, (algo), (level))
651
652/* Activate partial bodies for the output. This is needed if the length
653 of the data is not known in advance or for the use with sockets
654 or pipes. */
655#define cdk_handle_set_blockmode(a, val) \
656 cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_BLOCKMODE_ON, (val))
657
658/* Set the symmetric cipher for encryption. */
659#define cdk_handle_set_cipher(a, val) \
660 cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_CIPHER, (val))
661
662/* Set the digest for the PK signing operation. */
663#define cdk_handle_set_digest(a, val) \
664 cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_DIGEST, (val))
665
666/* Set the mode and the digest for the S2K operation. */
667#define cdk_handle_set_s2k(a, val1, val2) \
668 cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_S2K, (val1), (val2))
669
670
671/* This context holds all information of the verification process. */
672struct cdk_verify_result_s {
673 int sig_ver; /* Version of the signature. */
674 int sig_status; /* The status (GOOD, BAD) of the signature */
675 int sig_flags; /* May contain expired or revoked flags */
676 unsigned int keyid[2]; /* The issuer key ID */
677 unsigned int created; /* Timestamp when the sig was created. */
678 unsigned int expires;
679 int pubkey_algo;
680 int digest_algo;
681 char *user_id; /* NULL or user ID which issued the signature. */
682 char *policy_url; /* If set, the policy the sig was created under. */
683 size_t sig_len; /* Size of the signature data inbits. */
684 unsigned char *sig_data; /* Raw signature data. */
685};
686typedef struct cdk_verify_result_s *cdk_verify_result_t;
687
688/* Return the verify result. Do not free the data. */
689cdk_verify_result_t cdk_handle_verify_get_result (cdk_ctx_t hd);
690
691/* Raw packet routines. */
692
693/* Allocate a new packet or a new packet with the given packet type. */
694cdk_error_t cdk_pkt_new (cdk_packet_t *r_pkt);
695cdk_error_t cdk_pkt_alloc (cdk_packet_t *r_pkt, int pkttype);
696
697/* Only release the contents of the packet but not @PKT itself. */
698void cdk_pkt_free (cdk_packet_t pkt);
699
700/* Release the packet contents and the packet structure @PKT itself. */
701void cdk_pkt_release (cdk_packet_t pkt);
702
703/* Read or write the given output from or to the stream. */
704cdk_error_t cdk_pkt_read (cdk_stream_t inp, cdk_packet_t pkt);
705cdk_error_t cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt);
706
707/* Sub packet routines */
708cdk_subpkt_t cdk_subpkt_new (size_t size);
709void cdk_subpkt_free (cdk_subpkt_t ctx);
710cdk_subpkt_t cdk_subpkt_find (cdk_subpkt_t ctx, size_t type);
711cdk_subpkt_t cdk_subpkt_find_next (cdk_subpkt_t root, size_t type);
712size_t cdk_subpkt_type_count (cdk_subpkt_t ctx, size_t type);
713cdk_subpkt_t cdk_subpkt_find_nth (cdk_subpkt_t ctx, size_t type, size_t index);
714cdk_error_t cdk_subpkt_add (cdk_subpkt_t root, cdk_subpkt_t node);
715const unsigned char * cdk_subpkt_get_data (cdk_subpkt_t ctx,
716 size_t * r_type, size_t *r_nbytes);
717void cdk_subpkt_init (cdk_subpkt_t node, size_t type,
718 const void *buf, size_t buflen);
719
720/* Designated Revoker routines */
721const unsigned char* cdk_key_desig_revoker_walk (cdk_desig_revoker_t root,
722 cdk_desig_revoker_t * ctx,
723 int *r_class, int *r_algid);
724
725#define is_RSA(a) ((a) == CDK_PK_RSA \
726 || (a) == CDK_PK_RSA_E \
727 || (a) == CDK_PK_RSA_S)
728#define is_ELG(a) ((a) == CDK_PK_ELG_E)
729#define is_DSA(a) ((a) == CDK_PK_DSA)
730
731/* Encrypt the given session key @SK with the public key @PK
732 and write the contents into the packet @PKE. */
733cdk_error_t cdk_pk_encrypt (cdk_pubkey_t pk, cdk_pkt_pubkey_enc_t pke,
734 gcry_mpi_t sk);
735
736/* Decrypt the given encrypted session key in @PKE with the secret key
737 @SK and store it in @R_SK. */
738cdk_error_t cdk_pk_decrypt (cdk_seckey_t sk, cdk_pkt_pubkey_enc_t pke,
739 gcry_mpi_t *r_sk);
740
741/* Sign the given message digest @MD with the secret key @SK and
742 store the signature in the packet @SIG. */
743cdk_error_t cdk_pk_sign (cdk_seckey_t sk, cdk_pkt_signature_t sig,
744 const unsigned char *md);
745
746/* Verify the given signature in @SIG with the public key @PK
747 and compare it against the message digest @MD. */
748cdk_error_t cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
749 const unsigned char *md);
750
751/* Use cdk_pk_get_npkey() and cdk_pk_get_nskey to find out how much
752 multiprecision integers a key consists of. */
753
754/* Return a multi precision integer of the public key with the index @IDX
755 in the buffer @BUF. @R_NWRITTEN will contain the length in octets.
756 Optional @R_NBITS may contain the size in bits. */
757cdk_error_t cdk_pk_get_mpi (cdk_pubkey_t pk, size_t idx,
758 unsigned char *buf, size_t buflen,
759 size_t *r_nwritten, size_t *r_nbits);
760
761/* Same as the function above but of the secret key. */
762cdk_error_t cdk_sk_get_mpi (cdk_seckey_t sk, size_t idx,
763 unsigned char * buf, size_t buflen,
764 size_t *r_nwritten, size_t *r_nbits);
765
766/* Helper to get the exact number of multi precision integers
767 for the given object. */
768int cdk_pk_get_nbits (cdk_pubkey_t pk);
769int cdk_pk_get_npkey (int algo);
770int cdk_pk_get_nskey (int algo);
771int cdk_pk_get_nsig (int algo);
772int cdk_pk_get_nenc (int algo);
773
774/* Fingerprint and key ID routines. */
775
776/* Calculate the fingerprint of the given public key.
777 the FPR parameter must be at least 20 octets to hold the SHA1 hash. */
778cdk_error_t cdk_pk_get_fingerprint (cdk_pubkey_t pk, unsigned char *fpr);
779
780/* Same as above, but with additional sanity checks of the buffer size. */
781cdk_error_t cdk_pk_to_fingerprint (cdk_pubkey_t pk,
782 unsigned char *fpr, size_t fprlen,
783 size_t *r_nout);
784
785/* Derive the keyid from the fingerprint. This is only possible for
786 modern, version 4 keys. */
787unsigned int cdk_pk_fingerprint_get_keyid (const unsigned char *fpr,
788 size_t fprlen,
789 unsigned int *keyid);
790
791/* Various functions to get the keyid from the specific packet type. */
792unsigned int cdk_pk_get_keyid (cdk_pubkey_t pk, unsigned int *keyid);
793unsigned int cdk_sk_get_keyid (cdk_seckey_t sk, unsigned int *keyid);
794unsigned int cdk_sig_get_keyid (cdk_pkt_signature_t sig,
795 unsigned int *keyid);
796
797/* Key release functions. */
798void cdk_pk_release (cdk_pubkey_t pk);
799void cdk_sk_release (cdk_seckey_t sk);
800
801/* Secret key related functions. */
802cdk_error_t cdk_sk_unprotect (cdk_seckey_t sk, const char *pw);
803cdk_error_t cdk_sk_protect (cdk_seckey_t sk, const char *pw);
804
805/* Create a public key with the data from the secret key @SK. */
806cdk_error_t cdk_pk_from_secret_key (cdk_seckey_t sk,
807 cdk_pubkey_t *ret_pk);
808
809/* Sexp conversion of keys. */
810cdk_error_t cdk_pubkey_to_sexp (cdk_pubkey_t pk,
811 char **sexp, size_t *len);
812cdk_error_t cdk_seckey_to_sexp (cdk_seckey_t sk,
813 char **sexp, size_t *len);
814
815
816/* Data Encryption Key (DEK) routines */
817cdk_error_t cdk_dek_new (cdk_dek_t *r_dek);
818void cdk_dek_free (cdk_dek_t dek);
819
820/* Set the symmetric cipher algorithm which shall be used for this
821 DEK object. */
822cdk_error_t cdk_dek_set_cipher (cdk_dek_t dek, int cipher_algo);
823
824/* Return the symmetric cipher which is used for this DEK object. */
825cdk_error_t cdk_dek_get_cipher (cdk_dek_t dek, int *r_cipher_algo);
826
827
828/* Set the session key for the given DEK object.
829 If @KEY and @KEYLEN are both NULL/0, a random key will be generated
830 and stored in the DEK object. */
831cdk_error_t cdk_dek_set_key (cdk_dek_t dek, const unsigned char *key,
832 size_t keylen);
833
834/* Enable the MDC feature for the current DEK object. */
835void cdk_dek_set_mdc_flag (cdk_dek_t dek, int val);
836
837/* Return if the MDC feature is enabled for the current DEK object.*/
838int cdk_dek_get_mdc_flag (cdk_dek_t dek);
839
840/* Transform the given passphrase into a DEK.
841 If @rndsalt is set, a random salt will be generated. */
842cdk_error_t cdk_dek_from_passphrase (cdk_dek_t *ret_dek, int cipher_algo,
843 cdk_s2k_t s2k, int rndsalt,
844 const char *passphrase);
845
846/* String to Key routines. */
847cdk_error_t cdk_s2k_new (cdk_s2k_t *ret_s2k, int mode, int digest_algo,
848 const unsigned char *salt);
849void cdk_s2k_free (cdk_s2k_t s2k);
850
851cdk_error_t cdk_file_armor (cdk_ctx_t hd, const char *file,
852 const char *output);
853cdk_error_t cdk_file_dearmor (const char * file, const char *output);
854int cdk_armor_filter_use (cdk_stream_t inp);
855
856/* Protect the inbuf with ASCII armor of the specified type.
857 If @outbuf and @outlen are NULL, the function returns the calculated
858 size of the base64 encoded data in @nwritten. */
859cdk_error_t cdk_armor_encode_buffer (const unsigned char *inbuf, size_t inlen,
860 char *outbuf, size_t outlen,
861 size_t *nwritten, int type);
862
863
864/* This context contain user callbacks for different stream operations.
865 Some of these callbacks might be NULL to indicate that the callback
866 is not used. */
867struct cdk_stream_cbs_s
868{
869 cdk_error_t (*open)(void *);
870 cdk_error_t (*release)(void *);
871 int (*read)(void *, void *buf, size_t);
872 int (*write)(void *, const void *buf, size_t);
873 int (*seek)(void *, off_t);
874};
875typedef struct cdk_stream_cbs_s *cdk_stream_cbs_t;
876
877
878int cdk_stream_is_compressed (cdk_stream_t s);
879
880/* Return a stream object which is associated to a socket. */
881cdk_error_t cdk_stream_sockopen (const char *host, unsigned short port,
882 cdk_stream_t *ret_out);
883
884/* Return a stream object which is associated to an existing file. */
885cdk_error_t cdk_stream_open (const char * file, cdk_stream_t * ret_s);
886
887/* Return a stream object which is associated to a file which will
888 be created when the stream is closed. */
889cdk_error_t cdk_stream_new (const char * file, cdk_stream_t * ret_s);
890
891/* Return a stream object with custom callback functions for the
892 various core operations. */
893cdk_error_t cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa,
894 cdk_stream_t *ret_s);
895cdk_error_t cdk_stream_create (const char * file, cdk_stream_t * ret_s);
896cdk_error_t cdk_stream_tmp_new (cdk_stream_t *r_out);
897cdk_error_t cdk_stream_tmp_from_mem (const void * buf, size_t buflen,
898 cdk_stream_t *r_out);
899void cdk_stream_tmp_set_mode (cdk_stream_t s, int val);
900cdk_error_t cdk_stream_flush (cdk_stream_t s);
901cdk_error_t cdk_stream_enable_cache (cdk_stream_t s, int val);
902cdk_error_t cdk_stream_filter_disable (cdk_stream_t s, int type);
903cdk_error_t cdk_stream_close (cdk_stream_t s);
904off_t cdk_stream_get_length (cdk_stream_t s);
905int cdk_stream_read (cdk_stream_t s, void * buf, size_t count);
906int cdk_stream_write (cdk_stream_t s, const void * buf, size_t count);
907int cdk_stream_putc (cdk_stream_t s, int c);
908int cdk_stream_getc (cdk_stream_t s);
909int cdk_stream_eof (cdk_stream_t s);
910off_t cdk_stream_tell (cdk_stream_t s);
911cdk_error_t cdk_stream_seek (cdk_stream_t s, off_t offset);
912cdk_error_t cdk_stream_set_armor_flag (cdk_stream_t s, int type);
913
914/* Push the literal filter for the given stream. */
915cdk_error_t cdk_stream_set_literal_flag (cdk_stream_t s,
916 cdk_lit_format_t mode,
917 const char * fname);
918
919cdk_error_t cdk_stream_set_cipher_flag (cdk_stream_t s, cdk_dek_t dek,
920 int use_mdc);
921cdk_error_t cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level);
922cdk_error_t cdk_stream_set_hash_flag (cdk_stream_t s, int algo);
923cdk_error_t cdk_stream_set_text_flag (cdk_stream_t s, const char * lf);
924cdk_error_t cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out);
925cdk_error_t cdk_stream_mmap (cdk_stream_t s, unsigned char **ret_buf,
926 size_t *ret_buflen);
927cdk_error_t cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len,
928 unsigned char **ret_buf, size_t *ret_buflen);
929
930/* Read from the stream but restore the file pointer after reading
931 the requested amount of bytes. */
932int cdk_stream_peek (cdk_stream_t inp, unsigned char *buf, size_t buflen);
933
934/* A wrapper around the various new_from_XXX functions. Because
935 the function does not support all combinations, the dedicated
936 functions should be preferred. */
937cdk_error_t cdk_keydb_new (cdk_keydb_hd_t *r_hd, int type, void *data,
938 size_t count);
939
940/* Create a new key db handle from a memory buffer. */
941cdk_error_t cdk_keydb_new_from_mem (cdk_keydb_hd_t *r_hd, int secret,
942 const void *data, size_t datlen);
943
944/* Create a new key db which uses an existing file. */
945cdk_error_t cdk_keydb_new_from_file (cdk_keydb_hd_t *r_hd, int secret,
946 const char *fname);
947
948/* Uses a stream as the key db input. For searching it is important
949 that the seek function is supported on the stream. Furthermore,
950 the stream is not closed in cdk_keydb_free(). The caller must do it. */
951cdk_error_t cdk_keydb_new_from_stream (cdk_keydb_hd_t *r_hd, int secret,
952 cdk_stream_t in);
953
954/* Check that a secret key with the given key ID is available. */
955cdk_error_t cdk_keydb_check_sk (cdk_keydb_hd_t hd, unsigned int *keyid);
956
957/* Prepare the key db search. */
958cdk_error_t cdk_keydb_search_start (cdk_keydb_hd_t hd, int type, void *desc);
959
960/* Return a key which matches a valid description given in
961 cdk_keydb_search_start(). */
962cdk_error_t cdk_keydb_search (cdk_keydb_hd_t hd, cdk_kbnode_t *ret_key);
963
964/* Release the key db handle and all its resources. */
965void cdk_keydb_free (cdk_keydb_hd_t hd);
966
967/* The following functions will try to find a key in the given key
968 db handle either by keyid, by fingerprint or by some pattern. */
969cdk_error_t cdk_keydb_get_bykeyid (cdk_keydb_hd_t hd, unsigned int *keyid,
970 cdk_kbnode_t *ret_pk);
971cdk_error_t cdk_keydb_get_byfpr (cdk_keydb_hd_t hd, const unsigned char *fpr,
972 cdk_kbnode_t *ret_pk);
973cdk_error_t cdk_keydb_get_bypattern (cdk_keydb_hd_t hd, const char *patt,
974 cdk_kbnode_t *ret_pk);
975
976/* These function, in contrast to most other key db functions, only
977 return the public or secret key packet without the additional
978 signatures and user IDs. */
979cdk_error_t cdk_keydb_get_pk (cdk_keydb_hd_t khd, unsigned int * keyid,
980 cdk_pubkey_t *ret_pk);
981cdk_error_t cdk_keydb_get_sk (cdk_keydb_hd_t khd, unsigned int * keyid,
982 cdk_seckey_t *ret_sk);
983
984/* Try to read the next key block from the given input stream.
985 The key will be returned in @RET_KEY on success. */
986cdk_error_t cdk_keydb_get_keyblock (cdk_stream_t inp, cdk_kbnode_t * ret_key);
987
988/* Rebuild the key db index if possible. */
989cdk_error_t cdk_keydb_idx_rebuild (cdk_keydb_hd_t hd);
990
991/* Export one or more keys from the given key db handle into
992 the stream @OUT. The export is done by substring search and
993 uses the string list @REMUSR for the pattern. */
994cdk_error_t cdk_keydb_export (cdk_keydb_hd_t hd, cdk_stream_t out,
995 cdk_strlist_t remusr);
996
997/* Import the given key node @knode into the key db. */
998cdk_error_t cdk_keydb_import (cdk_keydb_hd_t hd, cdk_kbnode_t knode);
999
1000
1001/* List or enumerate keys from a given key db handle. */
1002
1003/* Start the key list process. Either use @PATT for a pattern search
1004 or @FPATT for a list of pattern. */
1005cdk_error_t cdk_listkey_start (cdk_listkey_t *r_ctx, cdk_keydb_hd_t db,
1006 const char *patt, cdk_strlist_t fpatt);
1007void cdk_listkey_close (cdk_listkey_t ctx);
1008
1009/* Return the next key which matches the pattern. */
1010cdk_error_t cdk_listkey_next (cdk_listkey_t ctx, cdk_kbnode_t *ret_key);
1011
1012cdk_kbnode_t cdk_kbnode_new (cdk_packet_t pkt);
1013cdk_error_t cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
1014 const unsigned char * buf,
1015 size_t buflen);
1016cdk_error_t cdk_kbnode_write_to_mem (cdk_kbnode_t node,
1017 unsigned char * buf, size_t * r_nbytes);
1018cdk_error_t cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
1019 unsigned char **r_buf,
1020 size_t *r_buflen);
1021
1022void cdk_kbnode_release (cdk_kbnode_t node);
1023cdk_kbnode_t cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * ctx, int all);
1024cdk_packet_t cdk_kbnode_find_packet (cdk_kbnode_t node, int pkttype);
1025cdk_packet_t cdk_kbnode_get_packet (cdk_kbnode_t node);
1026cdk_kbnode_t cdk_kbnode_find (cdk_kbnode_t node, int pkttype);
1027cdk_kbnode_t cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node,
1028 int pkttype);
1029cdk_kbnode_t cdk_kbnode_find_next (cdk_kbnode_t node, int pkttype);
1030cdk_error_t cdk_kbnode_hash (cdk_kbnode_t node, gcry_md_hd_t md, int is_v4,
1031 int pkttype, int flags);
1032
1033/* Check each signature in the key node and return a summary of the
1034 key status in @r_status. Values of cdk_key_flag_t are used. */
1035cdk_error_t cdk_pk_check_sigs (cdk_kbnode_t knode, cdk_keydb_hd_t hd,
1036 int *r_status);
1037
1038/* Check the self signature of the key to make sure it is valid. */
1039cdk_error_t cdk_pk_check_self_sig (cdk_kbnode_t knode, int *r_status);
1040
1041/* Return a matching algorithm from the given public key list.
1042 @PREFTYPE can be either sym-cipher/compress/digest. */
1043int cdk_pklist_select_algo (cdk_keylist_t pkl, int preftype);
1044
1045/* Return 0 or 1 if the given key list is able to understand the
1046 MDC feature. */
1047int cdk_pklist_use_mdc (cdk_keylist_t pkl);
1048cdk_error_t cdk_pklist_build (cdk_keylist_t *ret_pkl, cdk_keydb_hd_t hd,
1049 cdk_strlist_t remusr, int use);
1050void cdk_pklist_release (cdk_keylist_t pkl);
1051
1052/* Encrypt the given DEK key with the list of public keys given
1053 in @PKL. The result will be written to the stream output @OUT. */
1054cdk_error_t cdk_pklist_encrypt (cdk_keylist_t pkl, cdk_dek_t dek,
1055 cdk_stream_t out);
1056
1057/* Secret key lists */
1058cdk_error_t cdk_sklist_build (cdk_keylist_t * ret_skl,
1059 cdk_keydb_hd_t db, cdk_ctx_t hd,
1060 cdk_strlist_t locusr,
1061 int unlock, unsigned int use);
1062void cdk_sklist_release (cdk_keylist_t skl);
1063cdk_error_t cdk_sklist_write (cdk_keylist_t skl, cdk_stream_t outp,
1064 gcry_md_hd_t mdctx,
1065 int sigclass, int sigver);
1066cdk_error_t cdk_sklist_write_onepass (cdk_keylist_t skl, cdk_stream_t outp,
1067 int sigclass, int mdalgo);
1068
1069/* Encrypt the given stream @INP with the recipients given in @REMUSR.
1070 If @REMUSR is NULL, symmetric encryption will be used. The output
1071 will be written to @OUT. */
1072cdk_error_t cdk_stream_encrypt (cdk_ctx_t hd, cdk_strlist_t remusr,
1073 cdk_stream_t inp, cdk_stream_t out);
1074
1075/* Decrypt the @INP stream into @OUT. */
1076cdk_error_t cdk_stream_decrypt (cdk_ctx_t hd, cdk_stream_t inp,
1077 cdk_stream_t out);
1078
1079/* Same as the function above but it works on files. */
1080cdk_error_t cdk_file_encrypt (cdk_ctx_t hd, cdk_strlist_t remusr,
1081 const char *file, const char *output);
1082cdk_error_t cdk_file_decrypt (cdk_ctx_t hd, const char * file,
1083 const char *output);
1084
1085/* Generic function to transform data. The mode can be either sign,
1086 verify, encrypt, decrypt, import or export. The meanings of the
1087 parameters are similar to the functions above.
1088 @OUTBUF will contain the output and @OUTSIZE the length of it. */
1089cdk_error_t cdk_data_transform (cdk_ctx_t hd, enum cdk_crypto_mode_t mode,
1090 cdk_strlist_t locusr, cdk_strlist_t remusr,
1091 const void * inbuf, size_t insize,
1092 unsigned char ** outbuf, size_t * outsize,
1093 int modval);
1094
1095/* Sign the stream @INP. Optionally, the output will be encrypted
1096 if @REMUSR is not NULL and the @ENCRYPTFLAG is set.
1097 The output will be written to @OUT.
1098 @LOCUSR contains one ore more pattern for the secret key(s) to use. */
1099cdk_error_t cdk_stream_sign (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t out,
1100 cdk_strlist_t locusr, cdk_strlist_t remusr,
1101 int encryptflag, int sigmode);
1102
1103/* Same as the function above but it works on files. */
1104cdk_error_t cdk_file_sign (cdk_ctx_t hd, cdk_strlist_t locusr,
1105 cdk_strlist_t remusr,
1106 const char *file, const char *output,
1107 int sigmode, int encryptflag);
1108
1109cdk_error_t cdk_stream_verify (cdk_ctx_t hd, cdk_stream_t inp,
1110 cdk_stream_t data,
1111 cdk_stream_t out);
1112
1113/* Verify the given file @FILE. For a detached signature, @DATA_FILE
1114 contains the actual file data and @FILE is only the signature.
1115 If the @OUTPUT is not NULL, the plaintext will be written to this file. */
1116cdk_error_t cdk_file_verify (cdk_ctx_t hd, const char *file,
1117 const char *data_file, const char *output);
1118
1119int cdk_trustdb_get_validity (cdk_stream_t inp, cdk_pkt_userid_t id,
1120 int *r_val);
1121int cdk_trustdb_get_ownertrust (cdk_stream_t inp, cdk_pubkey_t pk,
1122 int *r_val, int *r_flags);
1123
1124void cdk_strlist_free (cdk_strlist_t sl);
1125cdk_strlist_t cdk_strlist_add (cdk_strlist_t * list, const char * string);
1126cdk_strlist_t cdk_strlist_next (cdk_strlist_t root, const char **r_str);
1127const char * cdk_check_version (const char * req_version);
1128/* UTF8 */
1129char* cdk_utf8_encode (const char * string);
1130char* cdk_utf8_decode (const char * string, size_t length, int delim);
1131
1132/* Try to receive the key, which has the key ID @KEYID, from the
1133 keyserver host @HOST and the port @PORT. */
1134cdk_error_t cdk_keyserver_recv_key (const char *host, int port,
1135 const unsigned char *keyid, int kid_type,
1136 cdk_kbnode_t *r_key);
1137
1138cdk_error_t cdk_keygen_new (cdk_keygen_ctx_t * r_hd);
1139void cdk_keygen_free (cdk_keygen_ctx_t hd);
1140
1141/* Set the preferences of the given type for the new key.
1142 @ARRAY is an array which list of algorithm IDs. */
1143cdk_error_t cdk_keygen_set_prefs (cdk_keygen_ctx_t hd,
1144 enum cdk_pref_type_t type,
1145 const unsigned char * array, size_t n);
1146cdk_error_t cdk_keygen_set_algo_info (cdk_keygen_ctx_t hd, int type,
1147 int usage, enum cdk_pubkey_algo_t algo,
1148 unsigned int bits);
1149int cdk_keygen_set_keyserver_flags (cdk_keygen_ctx_t hd, int no_modify,
1150 const char *pref_url);
1151int cdk_keygen_set_expire_date (cdk_keygen_ctx_t hd, int type,
1152 long timestamp);
1153
1154/* Set the user ID specifc parts for the new key.
1155 It is suggested to use a name in the form of
1156 'First Name' 'Last Name' <email-address@host.domain> */
1157void cdk_keygen_set_name (cdk_keygen_ctx_t hd, const char * name);
1158void cdk_keygen_set_passphrase (cdk_keygen_ctx_t hd, const char * pass);
1159cdk_error_t cdk_keygen_start (cdk_keygen_ctx_t hd);
1160cdk_error_t cdk_keygen_save (cdk_keygen_ctx_t hd,
1161 const char * pubf,
1162 const char * secf);
1163
1164#ifdef __cplusplus
1165}
1166#endif
1167
1168#endif /* OPENCDK_H */
1169
diff --git a/src/daemon/https/opencdk/packet.h b/src/daemon/https/opencdk/packet.h
new file mode 100644
index 00000000..03547ace
--- /dev/null
+++ b/src/daemon/https/opencdk/packet.h
@@ -0,0 +1,40 @@
1/* packet.h
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifndef CDK_PACKET_H
17#define CDK_PACKET_H
18
19struct cdk_kbnode_s
20{
21 struct cdk_kbnode_s *next;
22 cdk_packet_t pkt;
23 unsigned int is_deleted:1;
24 unsigned int is_cloned:1;
25};
26
27/*-- new-packet.c --*/
28void _cdk_free_mpibuf (size_t n, gcry_mpi_t *array);
29void _cdk_free_userid (cdk_pkt_userid_t uid);
30void _cdk_free_signature( cdk_pkt_signature_t sig );
31cdk_prefitem_t _cdk_copy_prefs( const cdk_prefitem_t prefs );
32int _cdk_copy_userid( cdk_pkt_userid_t *dst, cdk_pkt_userid_t src );
33int _cdk_copy_pubkey( cdk_pkt_pubkey_t* dst, cdk_pkt_pubkey_t src );
34int _cdk_copy_seckey( cdk_pkt_seckey_t* dst, cdk_pkt_seckey_t src );
35int _cdk_copy_pk_to_sk( cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk );
36int _cdk_copy_signature( cdk_pkt_signature_t* dst, cdk_pkt_signature_t src );
37int _cdk_pubkey_compare( cdk_pkt_pubkey_t a, cdk_pkt_pubkey_t b );
38
39#endif /* CDK_PACKET_H */
40
diff --git a/src/daemon/https/opencdk/pubkey.c b/src/daemon/https/opencdk/pubkey.c
new file mode 100644
index 00000000..0d24df12
--- /dev/null
+++ b/src/daemon/https/opencdk/pubkey.c
@@ -0,0 +1,1380 @@
1/* pubkey.c - Public key API
2 * Copyright (C) 2007 Free Software Foundation, Inc.
3 * Copyright (C) 2002, 2003, 2007 Timo Schulz
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20#include <stdio.h>
21#include <gcrypt.h>
22
23#include "opencdk.h"
24#include "main.h"
25#include "packet.h"
26
27
28/* Convert the given secret key into a gcrypt SEXP object. */
29static int
30seckey_to_sexp (gcry_sexp_t * r_skey, cdk_seckey_t sk)
31{
32 gcry_sexp_t sexp = NULL;
33 gcry_mpi_t *mpk = NULL, *msk = NULL;
34 gcry_error_t err;
35 cdk_pubkey_t pk;
36 const char *fmt;
37
38 if (!r_skey || !sk || !sk->pk)
39 return CDK_Inv_Value;
40
41 pk = sk->pk;
42 mpk = pk->mpi;
43 msk = sk->mpi;
44
45 *r_skey = NULL;
46 if (is_RSA (sk->pubkey_algo))
47 {
48 fmt = "(private-key(openpgp-rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))";
49 err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1],
50 msk[0], msk[1], msk[2], msk[3]);
51 }
52 else if (is_ELG (sk->pubkey_algo))
53 {
54 fmt = "(private-key(openpgp-elg(p%m)(g%m)(y%m)(x%m)))";
55 err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1],
56 mpk[2], msk[0]);
57 }
58 else if (is_DSA (sk->pubkey_algo))
59 {
60 fmt = "(private-key(openpgp-dsa(p%m)(q%m)(g%m)(y%m)(x%m)))";
61 err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1], mpk[2],
62 mpk[3], msk[0]);
63 }
64 else
65 return CDK_Inv_Algo;
66 if (err)
67 return map_gcry_error (err);
68 *r_skey = sexp;
69 return 0;
70}
71
72
73/* Convert the given public key to a gcrypt SEXP object. */
74static cdk_error_t
75pubkey_to_sexp (gcry_sexp_t * r_key_sexp, cdk_pubkey_t pk)
76{
77 gcry_mpi_t *m;
78 gcry_error_t err;
79 const char *fmt = NULL;
80 cdk_error_t rc = 0;
81
82 if (!r_key_sexp || !pk)
83 return CDK_Inv_Value;
84
85 m = pk->mpi;
86 if (is_RSA (pk->pubkey_algo))
87 {
88 fmt = "(public-key(openpgp-rsa(n%m)(e%m)))";
89 err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1]);
90 if (err)
91 rc = map_gcry_error (err);
92 }
93 else if (is_ELG (pk->pubkey_algo))
94 {
95 fmt = "(public-key(openpgp-elg(p%m)(g%m)(y%m)))";
96 err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1], m[2]);
97 if (err)
98 rc = map_gcry_error (err);
99 }
100 else if (is_DSA (pk->pubkey_algo))
101 {
102 fmt = "(public-key(openpgp-dsa(p%m)(q%m)(g%m)(y%m)))";
103 err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1], m[2], m[3]);
104 if (err)
105 rc = map_gcry_error (err);
106 }
107 else
108 rc = CDK_Inv_Algo;
109 return rc;
110}
111
112
113static cdk_error_t
114enckey_to_sexp (gcry_sexp_t * r_sexp, gcry_mpi_t esk)
115{
116 gcry_error_t err;
117
118 if (!r_sexp || !esk)
119 return CDK_Inv_Value;
120 err = gcry_sexp_build (r_sexp, NULL, "%m", esk);
121 if (err)
122 return map_gcry_error (err);
123 return 0;
124}
125
126
127static cdk_error_t
128digest_to_sexp (gcry_sexp_t * r_md_sexp, int digest_algo,
129 const byte * md, size_t mdlen)
130{
131 gcry_mpi_t m;
132 gcry_error_t err;
133
134 if (!r_md_sexp || !md)
135 return CDK_Inv_Value;
136
137 if (!mdlen)
138 mdlen = gcry_md_get_algo_dlen (digest_algo);
139 if (!mdlen)
140 return CDK_Inv_Algo;
141
142 err = gcry_mpi_scan (&m, GCRYMPI_FMT_USG, md, mdlen, &mdlen);
143 if (err)
144 return map_gcry_error (err);
145
146 err = gcry_sexp_build (r_md_sexp, NULL, "%m", m);
147 gcry_mpi_release (m);
148 if (err)
149 return map_gcry_error (err);
150 return 0;
151}
152
153
154static cdk_error_t
155sexp_to_mpi (gcry_sexp_t sexp, const char *val, gcry_mpi_t * ret_buf)
156{
157 gcry_sexp_t list;
158
159 if (!sexp || !val || !ret_buf)
160 return CDK_Inv_Value;
161
162 list = gcry_sexp_find_token (sexp, val, 0);
163 if (!list)
164 return CDK_Inv_Value;
165
166 *ret_buf = gcry_sexp_nth_mpi (list, 1, 0);
167 gcry_sexp_release (list);
168 if (!*ret_buf)
169 return CDK_Inv_Value;
170 return 0;
171}
172
173
174static cdk_error_t
175sexp_to_sig (cdk_pkt_signature_t sig, gcry_sexp_t sexp)
176{
177 if (!sig || !sexp)
178 return CDK_Inv_Value;
179
180 /* ElGamal signatures are not supported any longer. */
181 if (is_ELG (sig->pubkey_algo))
182 {
183 _cdk_log_debug ("sexp_to_sig: unsupported signature type (ElGamal)\n");
184 return CDK_Not_Implemented;
185 }
186
187 if (is_RSA (sig->pubkey_algo))
188 return sexp_to_mpi (sexp, "s", &sig->mpi[0]);
189 else if (is_DSA (sig->pubkey_algo))
190 {
191 cdk_error_t rc;
192
193 rc = sexp_to_mpi (sexp, "r", &sig->mpi[0]);
194 if (!rc)
195 rc = sexp_to_mpi (sexp, "s", &sig->mpi[1]);
196 return rc;
197 }
198 return CDK_Inv_Algo;
199}
200
201
202static cdk_error_t
203sig_to_sexp (gcry_sexp_t * r_sig_sexp, cdk_pkt_signature_t sig)
204{
205 gcry_error_t err;
206 cdk_error_t rc;
207 const char *fmt;
208
209 if (!r_sig_sexp || !sig)
210 return CDK_Inv_Value;
211 if (is_ELG (sig->pubkey_algo))
212 return CDK_Not_Implemented;
213
214 rc = 0;
215 if (is_RSA (sig->pubkey_algo))
216 {
217 fmt = "(sig-val(openpgp-rsa(s%m)))";
218 err = gcry_sexp_build (r_sig_sexp, NULL, fmt, sig->mpi[0]);
219 if (err)
220 rc = map_gcry_error (err);
221 }
222 else if (is_DSA (sig->pubkey_algo))
223 {
224 fmt = "(sig-val(openpgp-dsa(r%m)(s%m)))";
225 err = gcry_sexp_build (r_sig_sexp, NULL, fmt, sig->mpi[0], sig->mpi[1]);
226 if (err)
227 rc = map_gcry_error (err);
228 }
229 else
230 rc = CDK_Inv_Algo;
231 return rc;
232}
233
234
235static cdk_error_t
236sexp_to_pubenc (cdk_pkt_pubkey_enc_t enc, gcry_sexp_t sexp)
237{
238 if (!sexp || !enc)
239 return CDK_Inv_Value;
240
241 if (is_RSA (enc->pubkey_algo))
242 return sexp_to_mpi (sexp, "a", &enc->mpi[0]);
243 else if (is_ELG (enc->pubkey_algo))
244 {
245 cdk_error_t rc = sexp_to_mpi (sexp, "a", &enc->mpi[0]);
246 if (!rc)
247 rc = sexp_to_mpi (sexp, "b", &enc->mpi[1]);
248 return rc;
249 }
250 return CDK_Inv_Algo;
251}
252
253
254static cdk_error_t
255pubenc_to_sexp (gcry_sexp_t * r_sexp, cdk_pkt_pubkey_enc_t enc)
256{
257 gcry_sexp_t sexp = NULL;
258 gcry_error_t err;
259 const char *fmt;
260
261 if (!r_sexp || !enc)
262 return CDK_Inv_Value;
263
264 *r_sexp = NULL;
265 if (is_RSA (enc->pubkey_algo))
266 {
267 fmt = "(enc-val(openpgp-rsa((a%m))))";
268 err = gcry_sexp_build (&sexp, NULL, fmt, enc->mpi[0]);
269 }
270 else if (is_ELG (enc->pubkey_algo))
271 {
272 fmt = "(enc-val(openpgp-elg((a%m)(b%m))))";
273 err = gcry_sexp_build (&sexp, NULL, fmt, enc->mpi[0], enc->mpi[1]);
274 }
275 else
276 return CDK_Inv_Algo;
277 if (err)
278 return map_gcry_error (err);
279 *r_sexp = sexp;
280 return 0;
281}
282
283
284static int
285is_unprotected (cdk_seckey_t sk)
286{
287 if (sk->is_protected && !sk->mpi[0])
288 return 0;
289 return 1;
290}
291
292
293/**
294 * cdk_pk_encrypt:
295 * @pk: the public key
296 * @pke: the public key encrypted packet
297 * @esk: the actual session key
298 *
299 * Encrypt the session key in @esk and write its encrypted content
300 * into the @pke struct.
301 **/
302cdk_error_t
303cdk_pk_encrypt (cdk_pubkey_t pk, cdk_pkt_pubkey_enc_t pke, gcry_mpi_t esk)
304{
305 gcry_sexp_t s_data = NULL, s_pkey = NULL, s_ciph = NULL;
306 gcry_error_t err;
307 cdk_error_t rc;
308
309 if (!pk || !esk || !pke)
310 return CDK_Inv_Value;
311
312 if (!KEY_CAN_ENCRYPT (pk->pubkey_algo))
313 return CDK_Inv_Algo;
314
315 rc = enckey_to_sexp (&s_data, esk);
316 if (!rc)
317 rc = pubkey_to_sexp (&s_pkey, pk);
318 if (!rc)
319 {
320 err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
321 if (err)
322 return map_gcry_error (err);
323 }
324 if (!rc)
325 rc = sexp_to_pubenc (pke, s_ciph);
326
327 gcry_sexp_release (s_data);
328 gcry_sexp_release (s_pkey);
329 gcry_sexp_release (s_ciph);
330 return rc;
331}
332
333
334/**
335 * cdk_pk_decrypt:
336 * @sk: the secret key
337 * @pke: public key encrypted packet
338 * @r_sk: the object to store the plain session key
339 *
340 * Decrypt the encrypted session key from @pke into @r_sk.
341 **/
342cdk_error_t
343cdk_pk_decrypt (cdk_seckey_t sk, cdk_pkt_pubkey_enc_t pke, gcry_mpi_t * r_sk)
344{
345 gcry_sexp_t s_data = NULL, s_skey = NULL, s_plain = NULL;
346 cdk_error_t rc;
347 gcry_error_t err;
348
349 if (!sk || !r_sk || !pke)
350 return CDK_Inv_Value;
351
352 if (!is_unprotected (sk))
353 return CDK_Inv_Mode;
354
355 *r_sk = NULL;
356 rc = seckey_to_sexp (&s_skey, sk);
357 if (rc)
358 return rc;
359
360 rc = pubenc_to_sexp (&s_data, pke);
361 if (rc)
362 {
363 gcry_sexp_release (s_skey);
364 return rc;
365 }
366
367 err = gcry_pk_decrypt (&s_plain, s_data, s_skey);
368 if (err)
369 rc = map_gcry_error (err);
370 else
371 *r_sk = gcry_sexp_nth_mpi (s_plain, 0, 0);
372
373 gcry_sexp_release (s_data);
374 gcry_sexp_release (s_skey);
375 gcry_sexp_release (s_plain);
376 return rc;
377}
378
379
380/**
381 * cdk_pk_sign:
382 * @sk: secret key
383 * @sig: signature
384 * @md: the message digest
385 *
386 * Sign the message digest from @md and write the result into @sig.
387 **/
388cdk_error_t
389cdk_pk_sign (cdk_seckey_t sk, cdk_pkt_signature_t sig, const byte * md)
390{
391 gcry_sexp_t s_skey = NULL, s_sig = NULL, s_hash = NULL;
392 byte *encmd = NULL;
393 size_t enclen = 0;
394 int nbits;
395 cdk_error_t rc;
396 gcry_error_t err;
397
398 if (!sk || !sk->pk || !sig || !md)
399 return CDK_Inv_Value;
400
401 if (!is_unprotected (sk))
402 return CDK_Inv_Mode;
403
404 if (!KEY_CAN_SIGN (sig->pubkey_algo))
405 return CDK_Inv_Algo;
406
407 nbits = cdk_pk_get_nbits (sk->pk);
408 rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, sk->pk->pubkey_algo, md,
409 sig->digest_algo, nbits);
410 if (rc)
411 return rc;
412
413 rc = seckey_to_sexp (&s_skey, sk);
414 if (!rc)
415 rc = digest_to_sexp (&s_hash, sig->digest_algo, encmd, enclen);
416 if (rc)
417 {
418 cdk_free (encmd);
419 gcry_sexp_release (s_skey);
420 return rc;
421 }
422
423 err = gcry_pk_sign (&s_sig, s_hash, s_skey);
424 if (err)
425 rc = map_gcry_error (err);
426 else
427 {
428 rc = sexp_to_sig (sig, s_sig);
429 if (!rc)
430 {
431 sig->digest_start[0] = md[0];
432 sig->digest_start[1] = md[1];
433 }
434 }
435
436 gcry_sexp_release (s_skey);
437 gcry_sexp_release (s_hash);
438 gcry_sexp_release (s_sig);
439 cdk_free (encmd);
440 return rc;
441}
442
443
444/**
445 * cdk_pk_verify:
446 * @pk: the public key
447 * @sig: signature
448 * @md: the message digest
449 *
450 * Verify the signature in @sig and compare it with the message digest in @md.
451 **/
452cdk_error_t
453cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md)
454{
455 gcry_sexp_t s_pkey = NULL, s_sig = NULL, s_hash = NULL;
456 byte *encmd = NULL;
457 size_t enclen;
458 cdk_error_t rc;
459
460 if (!pk || !sig || !md)
461 return CDK_Inv_Value;
462
463 rc = pubkey_to_sexp (&s_pkey, pk);
464 if (rc)
465 return rc;
466
467 rc = sig_to_sexp (&s_sig, sig);
468 if (rc)
469 goto leave;
470
471 rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, pk->pubkey_algo, md,
472 sig->digest_algo, cdk_pk_get_nbits (pk));
473 if (rc)
474 goto leave;
475
476 rc = digest_to_sexp (&s_hash, sig->digest_algo, encmd, enclen);
477 if (rc)
478 goto leave;
479
480 if (gcry_pk_verify (s_sig, s_hash, s_pkey))
481 rc = CDK_Bad_Sig;
482
483leave:
484 gcry_sexp_release (s_sig);
485 gcry_sexp_release (s_hash);
486 gcry_sexp_release (s_pkey);
487 cdk_free (encmd);
488 return rc;
489}
490
491
492/**
493 * cdk_pk_get_nbits:
494 * @pk: the public key
495 *
496 * Return the length of the public key in bits.
497 * The meaning of length is actually the size of the 'prime'
498 * object in the key. For RSA keys the modulus, for ElG/DSA
499 * the size of the public prime.
500 **/
501int
502cdk_pk_get_nbits (cdk_pubkey_t pk)
503{
504 if (!pk || !pk->mpi[0])
505 return 0;
506 return gcry_mpi_get_nbits (pk->mpi[0]);
507}
508
509
510/**
511 * cdk_pk_get_npkey:
512 * @algo: The public key algorithm.
513 *
514 * Return the number of multiprecison integer forming an public
515 * key with the given algorithm.
516 */
517int
518cdk_pk_get_npkey (int algo)
519{
520 size_t bytes;
521
522 if (algo == 16)
523 algo = 20; /* FIXME: libgcrypt returns 0 for 16 */
524 if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &bytes))
525 return 0;
526 return bytes;
527}
528
529
530/**
531 * cdk_pk_get_nskey:
532 * @algo: the public key algorithm
533 *
534 * Return the number of multiprecision integers forming an
535 * secret key with the given algorithm.
536 **/
537int
538cdk_pk_get_nskey (int algo)
539{
540 size_t bytes;
541
542 if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &bytes))
543 return 0;
544 bytes -= cdk_pk_get_npkey (algo);
545 return bytes;
546}
547
548
549/**
550 * cdk_pk_get_nbits:
551 * @algo: the public key algorithm
552 *
553 * Return the number of MPIs a signature consists of.
554 **/
555int
556cdk_pk_get_nsig (int algo)
557{
558 size_t bytes;
559
560 if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &bytes))
561 return 0;
562 return bytes;
563}
564
565
566/**
567 * cdk_pk_get_nenc:
568 * @algo: the public key algorithm
569 *
570 * Return the number of MPI's the encrypted data consists of.
571 **/
572int
573cdk_pk_get_nenc (int algo)
574{
575 size_t bytes;
576
577 if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NENCR, NULL, &bytes))
578 return 0;
579 return bytes;
580}
581
582
583int
584_cdk_pk_algo_usage (int algo)
585{
586 int usage;
587
588 /* The ElGamal sign+encrypt algorithm is not supported any longer. */
589 switch (algo)
590 {
591 case CDK_PK_RSA:
592 usage = CDK_KEY_USG_SIGN | CDK_KEY_USG_ENCR;
593 break;
594 case CDK_PK_RSA_E:
595 usage = CDK_KEY_USG_ENCR;
596 break;
597 case CDK_PK_RSA_S:
598 usage = CDK_KEY_USG_SIGN;
599 break;
600 case CDK_PK_ELG_E:
601 usage = CDK_KEY_USG_ENCR;
602 break;
603 case CDK_PK_DSA:
604 usage = CDK_KEY_USG_SIGN;
605 break;
606 default:
607 usage = 0;
608 }
609 return usage;
610}
611
612
613static cdk_error_t
614mpi_to_buffer (gcry_mpi_t a, byte * buf, size_t buflen,
615 size_t * r_nwritten, size_t * r_nbits)
616{
617 size_t nbits;
618
619 if (!a || !buf || !r_nwritten)
620 return CDK_Inv_Value;
621
622 nbits = gcry_mpi_get_nbits (a);
623 if (r_nbits)
624 *r_nbits = nbits;
625 if ((nbits + 7) / 8 + 2 > buflen)
626 return CDK_Too_Short;
627 *r_nwritten = (nbits + 7) / 8 + 2;
628 if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf, buflen, r_nwritten, a))
629 return CDK_Wrong_Format;
630 return 0;
631}
632
633
634/**
635 * cdk_pk_get_mpi:
636 * @pk: public key
637 * @idx: index of the MPI to retrieve
638 * @buf: buffer to hold the raw data
639 * @r_nwritten: output how large the raw data is
640 * @r_nbits: size of the MPI in bits.
641 *
642 * Return the MPI with the given index of the public key.
643 **/
644cdk_error_t
645cdk_pk_get_mpi (cdk_pubkey_t pk, size_t idx,
646 byte * buf, size_t buflen, size_t * r_nwritten,
647 size_t * r_nbits)
648{
649 if (!pk || !r_nwritten)
650 return CDK_Inv_Value;
651 if (idx > cdk_pk_get_npkey (pk->pubkey_algo))
652 return CDK_Inv_Value;
653 return mpi_to_buffer (pk->mpi[idx], buf, buflen, r_nwritten, r_nbits);
654}
655
656
657/**
658 * cdk_sk_get_mpi:
659 * @sk: secret key
660 * @idx: index of the MPI to retrieve
661 * @buf: buffer to hold the raw data
662 * @r_nwritten: output length of the raw data
663 * @r_nbits: length of the MPI data in bits.
664 *
665 * Return the MPI of the given secret key with the
666 * index @idx. It is important to check if the key
667 * is protected and thus no real MPI data will be returned then.
668 **/
669cdk_error_t
670cdk_sk_get_mpi (cdk_pkt_seckey_t sk, size_t idx,
671 byte * buf, size_t buflen, size_t * r_nwritten,
672 size_t * r_nbits)
673{
674 if (!sk || !r_nwritten)
675 return CDK_Inv_Value;
676 if (idx > cdk_pk_get_nskey (sk->pubkey_algo))
677 return CDK_Inv_Value;
678 return mpi_to_buffer (sk->mpi[idx], buf, buflen, r_nwritten, r_nbits);
679}
680
681
682static u16
683checksum_mpi (gcry_mpi_t m)
684{
685 byte buf[MAX_MPI_BYTES + 2];
686 size_t nread;
687 int i;
688 u16 chksum = 0;
689
690 if (!m)
691 return 0;
692 if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf, DIM (buf), &nread, m))
693 return 0;
694 for (i = 0; i < nread; i++)
695 chksum += buf[i];
696 return chksum;
697}
698
699
700/**
701 * cdk_sk_unprotect:
702 * @sk: the secret key
703 * @pw: the passphrase
704 *
705 * Unprotect the given secret key with the passphrase.
706 **/
707cdk_error_t
708cdk_sk_unprotect (cdk_pkt_seckey_t sk, const char *pw)
709{
710 gcry_cipher_hd_t hd;
711 cdk_dek_t dek = NULL;
712 byte *data = NULL;
713 u16 chksum = 0;
714 size_t ndata, nbits, nbytes;
715 int i, dlen, pos = 0, nskey;
716 cdk_error_t rc;
717 gcry_error_t err;
718
719 if (!sk)
720 return CDK_Inv_Value;
721
722 nskey = cdk_pk_get_nskey (sk->pubkey_algo);
723 if (!sk->is_protected)
724 {
725 chksum = 0;
726 for (i = 0; i < nskey; i++)
727 chksum += checksum_mpi (sk->mpi[i]);
728 if (chksum != sk->csum)
729 return CDK_Chksum_Error;
730 }
731
732 rc = cdk_dek_from_passphrase (&dek, sk->protect.algo,
733 sk->protect.s2k, 0, pw);
734 if (rc)
735 return rc;
736 err = gcry_cipher_open (&hd, sk->protect.algo, GCRY_CIPHER_MODE_CFB,
737 GCRY_CIPHER_ENABLE_SYNC);
738 if (!err)
739 err = gcry_cipher_setiv (hd, sk->protect.iv, sk->protect.ivlen);
740 if (!err)
741 err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
742 if (err)
743 {
744 cdk_free (dek);
745 return map_gcry_error (err);
746 }
747 cdk_dek_free (dek);
748 chksum = 0;
749 if (sk->version == 4)
750 {
751 ndata = sk->enclen;
752 data = cdk_salloc (ndata, 1);
753 if (!data)
754 return CDK_Out_Of_Core;
755 gcry_cipher_decrypt (hd, data, ndata, sk->encdata, ndata);
756 if (sk->protect.sha1chk)
757 {
758 /* This is the new SHA1 checksum method to detect tampering
759 with the key as used by the Klima/Rosa attack */
760 sk->csum = 0;
761 chksum = 1;
762 dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
763 if (ndata < dlen)
764 {
765 cdk_free (data);
766 return CDK_Inv_Packet;
767 }
768 else
769 {
770 byte mdcheck[20];
771
772 gcry_md_hash_buffer (GCRY_MD_SHA1, mdcheck, data, ndata - dlen);
773 if (!memcmp (mdcheck, data + ndata - dlen, dlen))
774 chksum = 0; /* Digest does match */
775 }
776 }
777 else
778 {
779 for (i = 0; i < ndata - 2; i++)
780 chksum += data[i];
781 sk->csum = data[ndata - 2] << 8 | data[ndata - 1];
782 }
783 if (sk->csum == chksum)
784 {
785 for (i = 0; i < nskey; i++)
786 {
787 nbits = data[pos] << 8 | data[pos + 1];
788
789 if (gcry_mpi_scan (&sk->mpi[i], GCRYMPI_FMT_PGP, data,
790 (nbits + 7) / 8 + 2, &nbytes))
791 {
792 wipemem (data, sk->enclen);
793 cdk_free (data);
794 return CDK_Wrong_Format;
795 }
796 gcry_mpi_set_flag (sk->mpi[i], GCRYMPI_FLAG_SECURE);
797 pos += (nbits + 7) / 8 + 2;
798 }
799 }
800 wipemem (data, sk->enclen);
801 cdk_free (data);
802 }
803 else
804 {
805 byte buf[MAX_MPI_BYTES + 2];
806
807 chksum = 0;
808 for (i = 0; i < nskey; i++)
809 {
810 gcry_cipher_sync (hd);
811 gcry_mpi_print (GCRYMPI_FMT_PGP, buf, DIM (buf),
812 &nbytes, sk->mpi[i]);
813 gcry_cipher_decrypt (hd, buf + 2, nbytes - 2, NULL, 0);
814 gcry_mpi_release (sk->mpi[i]);
815 if (gcry_mpi_scan (&sk->mpi[i], GCRYMPI_FMT_PGP,
816 buf, nbytes, &nbytes))
817 return CDK_Wrong_Format;
818 chksum += checksum_mpi (sk->mpi[i]);
819 }
820 }
821 gcry_cipher_close (hd);
822 if (chksum != sk->csum)
823 return CDK_Chksum_Error;
824 sk->is_protected = 0;
825 return 0;
826}
827
828
829/**
830 * cdk_sk_protect:
831 * @sk: the secret key
832 * @pw: the passphrase to use
833 *
834 * Protect the given secret key with a passphrase.
835 **/
836cdk_error_t
837cdk_sk_protect (cdk_pkt_seckey_t sk, const char *pw)
838{
839 gcry_cipher_hd_t hd = NULL;
840 cdk_dek_t dek = NULL;
841 cdk_s2k_t s2k;
842 byte *p = NULL, buf[MAX_MPI_BYTES + 2];
843 size_t enclen = 0, nskey, i, nbytes;
844 size_t dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
845 gcry_error_t err;
846 cdk_error_t rc;
847
848 nskey = cdk_pk_get_nskey (sk->pubkey_algo);
849 if (!nskey)
850 return CDK_Inv_Algo;
851
852 rc = cdk_s2k_new (&s2k, CDK_S2K_ITERSALTED, GCRY_MD_SHA256, NULL);
853 if (!rc)
854 rc = cdk_dek_from_passphrase (&dek, GCRY_CIPHER_AES, s2k, 1, pw);
855 if (rc)
856 {
857 cdk_s2k_free (s2k);
858 return rc;
859 }
860
861 for (i = 0; i < nskey; i++)
862 {
863 enclen += 2;
864 enclen += (gcry_mpi_get_nbits (sk->mpi[i]) + 7) / 8;
865 }
866 p = sk->encdata = cdk_calloc (1, enclen + dlen + 1);
867 if (!p)
868 {
869 cdk_s2k_free (s2k);
870 return CDK_Out_Of_Core;
871 }
872
873 enclen = 0;
874 for (i = 0; i < nskey; i++)
875 {
876 if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf,
877 DIM (buf), &nbytes, sk->mpi[i]))
878 {
879 cdk_free (p);
880 cdk_s2k_free (s2k);
881 return CDK_Wrong_Format;
882 }
883 memcpy (p + enclen, buf, nbytes);
884 enclen += nbytes;
885 }
886
887 enclen += dlen;
888 sk->enclen = enclen;
889 sk->protect.s2k = s2k;
890 sk->protect.algo = GCRY_CIPHER_AES;
891 sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo);
892 gcry_randomize (sk->protect.iv, sk->protect.ivlen, GCRY_STRONG_RANDOM);
893 err = gcry_cipher_open (&hd, sk->protect.algo, GCRY_CIPHER_MODE_CFB,
894 GCRY_CIPHER_ENABLE_SYNC);
895 if (err)
896 {
897 cdk_dek_free (dek);
898 rc = map_gcry_error (err);
899 goto leave;
900 }
901
902 err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
903 if (!err)
904 err = gcry_cipher_setiv (hd, sk->protect.iv, sk->protect.ivlen);
905 cdk_dek_free (dek);
906 if (err)
907 {
908 rc = map_gcry_error (err);
909 goto leave;
910 }
911
912 sk->protect.sha1chk = 1;
913 sk->is_protected = 1;
914 sk->csum = 0;
915
916 gcry_md_hash_buffer (GCRY_MD_SHA1, buf, p, enclen - dlen);
917 memcpy (p + enclen - dlen, buf, dlen);
918 gcry_cipher_encrypt (hd, p, enclen, NULL, 0);
919
920 /* FIXME: We should release all MPI's and set the elements to NULL. */
921
922leave:
923 gcry_cipher_close (hd);
924 return rc;
925}
926
927
928/**
929 * cdk_pk_from_secret_key:
930 * @sk: the secret key
931 * @ret_pk: the new public key
932 *
933 * Create a new public key from a secret key.
934 **/
935cdk_error_t
936cdk_pk_from_secret_key (cdk_pkt_seckey_t sk, cdk_pubkey_t * ret_pk)
937{
938 if (!sk)
939 return CDK_Inv_Value;
940 return _cdk_copy_pubkey (ret_pk, sk->pk);
941}
942
943
944#if 0 /* FIXME: Code is not finished yet. */
945cdk_error_t
946cdk_pk_revoke_cert_create (cdk_pkt_seckey_t sk, int code, const char *inf,
947 char **ret_revcert)
948{
949 gcry_md_hd_t md;
950 cdk_subpkt_t node;
951 cdk_pkt_signature_t sig;
952 char *p = NULL, *dat;
953 gcry_error_t err;
954 cdk_error_t rc = 0;
955 size_t n;
956
957 if (!sk || !ret_revcert)
958 return CDK_Inv_Value;
959 if (code < 0 || code > 3)
960 return CDK_Inv_Value;
961
962 sig = cdk_calloc (1, sizeof *sig);
963 if (!sig)
964 return CDK_Out_Of_Core;
965 _cdk_sig_create (sk->pk, sig);
966 n = 1;
967 if (inf)
968 {
969 n += strlen (p);
970 p = cdk_utf8_encode (inf);
971 }
972 dat = cdk_calloc (1, n + 1);
973 if (!dat)
974 {
975 _cdk_free_signature (sig);
976 return CDK_Out_Of_Core;
977 }
978 dat[0] = code;
979 if (inf)
980 memcpy (dat + 1, p, strlen (p));
981 cdk_free (p);
982
983 node = cdk_subpkt_new (n);
984 if (node)
985 {
986 cdk_subpkt_init (node, CDK_SIGSUBPKT_REVOC_REASON, dat, n);
987 cdk_subpkt_add (sig->hashed, node);
988 }
989 cdk_free (dat);
990
991 err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
992 if (err)
993 rc = map_gcry_error (err);
994 else
995 _cdk_hash_pubkey (sk->pk, md, 0);
996 _cdk_free_signature (sig);
997
998 return rc;
999}
1000#endif
1001
1002int
1003_cdk_sk_get_csum (cdk_pkt_seckey_t sk)
1004{
1005 u16 csum = 0, i;
1006
1007 if (!sk)
1008 return 0;
1009 for (i = 0; i < cdk_pk_get_nskey (sk->pubkey_algo); i++)
1010 csum += checksum_mpi (sk->mpi[i]);
1011 return csum;
1012}
1013
1014
1015/**
1016 * cdk_pk_get_fingerprint:
1017 * @pk: the public key
1018 * @fpr: the buffer to hold the fingerprint
1019 *
1020 * Return the fingerprint of the given public key.
1021 * The buffer must be at least 20 octets.
1022 * This function should be considered deprecated and
1023 * the new cdk_pk_to_fingerprint() should be used whenever
1024 * possible to avoid overflows.
1025 **/
1026cdk_error_t
1027cdk_pk_get_fingerprint (cdk_pubkey_t pk, byte * fpr)
1028{
1029 gcry_md_hd_t hd;
1030 int md_algo;
1031 int dlen = 0;
1032 gcry_error_t err;
1033
1034 if (!pk || !fpr)
1035 return CDK_Inv_Value;
1036
1037 if (pk->version < 4 && is_RSA (pk->pubkey_algo))
1038 md_algo = GCRY_MD_MD5; /* special */
1039 else
1040 md_algo = GCRY_MD_SHA1;
1041 dlen = gcry_md_get_algo_dlen (md_algo);
1042 err = gcry_md_open (&hd, md_algo, 0);
1043 if (err)
1044 return map_gcry_error (err);
1045 _cdk_hash_pubkey (pk, hd, 1);
1046 gcry_md_final (hd);
1047 memcpy (fpr, gcry_md_read (hd, md_algo), dlen);
1048 gcry_md_close (hd);
1049 if (dlen == 16)
1050 memset (fpr + 16, 0, 4);
1051 return 0;
1052}
1053
1054
1055/**
1056 * cdk_pk_to_fingerprint:
1057 * @pk: the public key
1058 * @fprbuf: buffer to save the fingerprint
1059 * @fprbuflen: buffer size
1060 * @r_nout: actual length of the fingerprint.
1061 *
1062 * Calculate a fingerprint of the given key and
1063 * return it in the given byte array.
1064 **/
1065cdk_error_t
1066cdk_pk_to_fingerprint (cdk_pubkey_t pk,
1067 byte * fprbuf, size_t fprbuflen, size_t * r_nout)
1068{
1069 size_t key_fprlen;
1070 cdk_error_t err;
1071
1072 if (!pk)
1073 return CDK_Inv_Value;
1074
1075 if (pk->version < 4)
1076 key_fprlen = 16;
1077 else
1078 key_fprlen = 20;
1079
1080 /* Only return the required buffer size for the fingerprint. */
1081 if (!fprbuf && !fprbuflen && r_nout)
1082 {
1083 *r_nout = key_fprlen;
1084 return 0;
1085 }
1086
1087 if (!fprbuf || key_fprlen > fprbuflen)
1088 return CDK_Too_Short;
1089
1090 err = cdk_pk_get_fingerprint (pk, fprbuf);
1091 if (r_nout)
1092 *r_nout = key_fprlen;
1093
1094 return err;
1095}
1096
1097
1098/**
1099 * cdk_pk_fingerprint_get_keyid:
1100 * @fpr: the key fingerprint
1101 * @fprlen: the length of the fingerprint
1102 *
1103 * Derive the key ID from the key fingerprint.
1104 * For version 3 keys, this is not working.
1105 **/
1106u32
1107cdk_pk_fingerprint_get_keyid (const byte * fpr, size_t fprlen, u32 * keyid)
1108{
1109 u32 lowbits = 0;
1110
1111 /* In this case we say the key is a V3 RSA key and we can't
1112 use the fingerprint to get the keyid. */
1113 if (fpr && fprlen == 16)
1114 {
1115 keyid[0] = 0;
1116 keyid[1] = 0;
1117 return 0;
1118 }
1119 else if (keyid && fpr)
1120 {
1121 keyid[0] = _cdk_buftou32 (fpr + 12);
1122 keyid[1] = _cdk_buftou32 (fpr + 16);
1123 lowbits = keyid[1];
1124 }
1125 else if (fpr)
1126 lowbits = _cdk_buftou32 (fpr + 16);
1127 return lowbits;
1128}
1129
1130
1131/**
1132 * cdk_pk_get_keyid:
1133 * @pk: the public key
1134 * @keyid: buffer to store the key ID
1135 *
1136 * Calculate the key ID of the given public key.
1137 **/
1138u32
1139cdk_pk_get_keyid (cdk_pubkey_t pk, u32 * keyid)
1140{
1141 u32 lowbits = 0;
1142 byte buf[24];
1143
1144 if (pk && (!pk->keyid[0] || !pk->keyid[1]))
1145 {
1146 if (pk->version < 4 && is_RSA (pk->pubkey_algo))
1147 {
1148 byte p[MAX_MPI_BYTES];
1149 size_t n;
1150
1151 gcry_mpi_print (GCRYMPI_FMT_USG, p, MAX_MPI_BYTES, &n, pk->mpi[0]);
1152 pk->keyid[0] =
1153 p[n - 8] << 24 | p[n - 7] << 16 | p[n - 6] << 8 | p[n - 5];
1154 pk->keyid[1] =
1155 p[n - 4] << 24 | p[n - 3] << 16 | p[n - 2] << 8 | p[n - 1];
1156 }
1157 else if (pk->version == 4)
1158 {
1159 cdk_pk_get_fingerprint (pk, buf);
1160 pk->keyid[0] = _cdk_buftou32 (buf + 12);
1161 pk->keyid[1] = _cdk_buftou32 (buf + 16);
1162 }
1163 }
1164 lowbits = pk ? pk->keyid[1] : 0;
1165 if (keyid && pk)
1166 {
1167 keyid[0] = pk->keyid[0];
1168 keyid[1] = pk->keyid[1];
1169 }
1170
1171 return lowbits;
1172}
1173
1174
1175/**
1176 * cdk_sk_get_keyid:
1177 * @sk: the secret key
1178 * @keyid: buffer to hold the key ID
1179 *
1180 * Calculate the key ID of the secret key, actually the public key.
1181 **/
1182u32
1183cdk_sk_get_keyid (cdk_pkt_seckey_t sk, u32 * keyid)
1184{
1185 u32 lowbits = 0;
1186
1187 if (sk && sk->pk)
1188 {
1189 lowbits = cdk_pk_get_keyid (sk->pk, keyid);
1190 sk->keyid[0] = sk->pk->keyid[0];
1191 sk->keyid[1] = sk->pk->keyid[1];
1192 }
1193
1194 return lowbits;
1195}
1196
1197
1198/**
1199 * cdk_sig_get_keyid:
1200 * @sig: the signature
1201 * @keyid: buffer to hold the key ID
1202 *
1203 * Retrieve the key ID from the given signature.
1204 **/
1205u32
1206cdk_sig_get_keyid (cdk_pkt_signature_t sig, u32 * keyid)
1207{
1208 u32 lowbits = sig ? sig->keyid[1] : 0;
1209
1210 if (keyid && sig)
1211 {
1212 keyid[0] = sig->keyid[0];
1213 keyid[1] = sig->keyid[1];
1214 }
1215 return lowbits;
1216}
1217
1218
1219/* Return the key ID from the given packet.
1220 If this is not possible, 0 is returned */
1221u32
1222_cdk_pkt_get_keyid (cdk_packet_t pkt, u32 * keyid)
1223{
1224 u32 lowbits;
1225
1226 if (!pkt)
1227 return 0;
1228
1229 switch (pkt->pkttype)
1230 {
1231 case CDK_PKT_PUBLIC_KEY:
1232 case CDK_PKT_PUBLIC_SUBKEY:
1233 lowbits = cdk_pk_get_keyid (pkt->pkt.public_key, keyid);
1234 break;
1235
1236 case CDK_PKT_SECRET_KEY:
1237 case CDK_PKT_SECRET_SUBKEY:
1238 lowbits = cdk_sk_get_keyid (pkt->pkt.secret_key, keyid);
1239 break;
1240
1241 case CDK_PKT_SIGNATURE:
1242 lowbits = cdk_sig_get_keyid (pkt->pkt.signature, keyid);
1243 break;
1244
1245 default:
1246 lowbits = 0;
1247 break;
1248 }
1249
1250 return lowbits;
1251}
1252
1253
1254/* Get the fingerprint of the packet if possible. */
1255int
1256_cdk_pkt_get_fingerprint (cdk_packet_t pkt, byte * fpr)
1257{
1258 if (!pkt || !fpr)
1259 return CDK_Inv_Value;
1260
1261 switch (pkt->pkttype)
1262 {
1263 case CDK_PKT_PUBLIC_KEY:
1264 case CDK_PKT_PUBLIC_SUBKEY:
1265 return cdk_pk_get_fingerprint (pkt->pkt.public_key, fpr);
1266
1267 case CDK_PKT_SECRET_KEY:
1268 case CDK_PKT_SECRET_SUBKEY:
1269 return cdk_pk_get_fingerprint (pkt->pkt.secret_key->pk, fpr);
1270
1271 default:
1272 return CDK_Inv_Mode;
1273 }
1274 return 0;
1275}
1276
1277
1278/**
1279 * cdk_pubkey_to_sexp:
1280 * @pk: the public key
1281 * @sexp: where to store the S-expression
1282 * @len: the length of sexp
1283 *
1284 * Convert a public key to an S-expression. sexp is allocated by this
1285 * function, but you have to cdk_free() it yourself. The S-expression
1286 * is stored in canonical format as used by libgcrypt
1287 * (GCRYSEXP_FMT_CANON).
1288 **/
1289cdk_error_t
1290cdk_pubkey_to_sexp (cdk_pubkey_t pk, char **sexp, size_t * len)
1291{
1292 char *buf;
1293 size_t sexp_len;
1294 gcry_sexp_t pk_sexp;
1295 cdk_error_t rc;
1296
1297 if (!pk || !sexp)
1298 return CDK_Inv_Value;
1299
1300 rc = pubkey_to_sexp (&pk_sexp, pk);
1301 if (rc)
1302 return rc;
1303
1304 sexp_len = gcry_sexp_sprint (pk_sexp, GCRYSEXP_FMT_CANON, NULL, 0);
1305 if (!sexp_len)
1306 return CDK_Wrong_Format;
1307
1308 buf = (char *) cdk_malloc (sexp_len);
1309 if (!buf)
1310 {
1311 gcry_sexp_release (pk_sexp);
1312 return CDK_Out_Of_Core;
1313 }
1314
1315 sexp_len = gcry_sexp_sprint (pk_sexp, GCRYSEXP_FMT_CANON, buf, sexp_len);
1316 gcry_sexp_release (pk_sexp);
1317 if (!sexp_len)
1318 {
1319 cdk_free (buf);
1320 return CDK_Wrong_Format;
1321 }
1322
1323 if (len)
1324 *len = sexp_len;
1325 *sexp = buf;
1326 return CDK_Success;
1327}
1328
1329
1330/**
1331 * cdk_seckey_to_sexp:
1332 * @sk: the secret key
1333 * @sexp: where to store the S-expression
1334 * @len: the length of sexp
1335 *
1336 * Convert a public key to an S-expression. sexp is allocated by this
1337 * function, but you have to cdk_free() it yourself. The S-expression
1338 * is stored in canonical format as used by libgcrypt
1339 * (GCRYSEXP_FMT_CANON).
1340 **/
1341cdk_error_t
1342cdk_seckey_to_sexp (cdk_pkt_seckey_t sk, char **sexp, size_t * len)
1343{
1344 char *buf;
1345 size_t sexp_len;
1346 gcry_sexp_t sk_sexp;
1347 cdk_error_t rc;
1348
1349 if (!sk || !sexp)
1350 return CDK_Inv_Value;
1351
1352 rc = seckey_to_sexp (&sk_sexp, sk);
1353 if (rc)
1354 return rc;
1355
1356 sexp_len = gcry_sexp_sprint (sk_sexp, GCRYSEXP_FMT_CANON, NULL, 0);
1357 if (!sexp_len)
1358 return CDK_Wrong_Format;
1359
1360 buf = (char *) cdk_malloc (sexp_len);
1361 if (!buf)
1362 {
1363 gcry_sexp_release (sk_sexp);
1364 return CDK_Out_Of_Core;
1365 }
1366
1367 sexp_len = gcry_sexp_sprint (sk_sexp, GCRYSEXP_FMT_CANON, buf, sexp_len);
1368 gcry_sexp_release (sk_sexp);
1369 if (!sexp_len)
1370 {
1371 cdk_free (buf);
1372 return CDK_Wrong_Format;
1373 }
1374
1375 if (len)
1376 *len = sexp_len;
1377 *sexp = buf;
1378
1379 return CDK_Success;
1380}
diff --git a/src/daemon/https/opencdk/read-packet.c b/src/daemon/https/opencdk/read-packet.c
new file mode 100644
index 00000000..7c7a91af
--- /dev/null
+++ b/src/daemon/https/opencdk/read-packet.c
@@ -0,0 +1,1179 @@
1/* read-packet.c - Read OpenPGP packets
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19#include <string.h>
20#include <stdio.h>
21#include <time.h>
22#include <assert.h>
23
24#include "opencdk.h"
25#include "main.h"
26#include "packet.h"
27#include "types.h"
28
29
30/* The version of the MDC packet considering the lastest OpenPGP draft. */
31#define MDC_PKT_VER 1
32
33static int
34stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t * r_nread)
35{
36 *r_nread = cdk_stream_read (s, buf, buflen);
37 return *r_nread > 0 ? 0 : _cdk_stream_get_errno (s);
38}
39
40
41/* Try to read 4 octets from the stream. */
42static u32
43read_32 (cdk_stream_t s)
44{
45 byte buf[4];
46 size_t nread;
47
48 assert (s != NULL);
49
50 stream_read (s, buf, 4, &nread);
51 if (nread != 4)
52 return (u32) - 1;
53 return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
54}
55
56
57/* Try to read 2 octets from a stream. */
58static u16
59read_16 (cdk_stream_t s)
60{
61 byte buf[2];
62 size_t nread;
63
64 assert (s != NULL);
65
66 stream_read (s, buf, 2, &nread);
67 if (nread != 2)
68 return (u16) - 1;
69 return buf[0] << 8 | buf[1];
70}
71
72
73static int
74read_s2k (cdk_stream_t inp, cdk_s2k_t s2k)
75{
76 size_t nread;
77
78 if (!inp || !s2k)
79 return CDK_Inv_Value;
80
81 if (DEBUG_PKT)
82 _cdk_log_debug ("read_s2k:\n");
83
84 s2k->mode = cdk_stream_getc (inp);
85 if (cdk_stream_eof (inp))
86 return CDK_Inv_Packet;
87 if (s2k->mode != CDK_S2K_SIMPLE && s2k->mode != CDK_S2K_SALTED &&
88 s2k->mode != CDK_S2K_ITERSALTED)
89 return CDK_Inv_Packet;
90 s2k->hash_algo = cdk_stream_getc (inp);
91 if (s2k->mode == CDK_S2K_SIMPLE) /* No additional elements. */
92 memset (s2k->salt, 0, sizeof (s2k->salt));
93 else if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
94 {
95 if (stream_read (inp, s2k->salt, DIM (s2k->salt), &nread))
96 return CDK_Inv_Packet;
97 if (nread != DIM (s2k->salt))
98 return CDK_Inv_Packet;
99 if (s2k->mode == CDK_S2K_ITERSALTED)
100 {
101 s2k->count = cdk_stream_getc (inp);
102 if (cdk_stream_eof (inp))
103 return CDK_Inv_Packet;
104 }
105 }
106 else
107 return CDK_Inv_Mode;
108 return 0;
109}
110
111
112static cdk_error_t
113read_mpi (cdk_stream_t inp, gcry_mpi_t * ret_m, int secure)
114{
115 gcry_mpi_t m;
116 gcry_error_t err;
117 byte buf[MAX_MPI_BYTES + 2];
118 size_t nread, nbits;
119 cdk_error_t rc;
120
121 if (!inp || !ret_m)
122 return CDK_Inv_Value;
123
124 *ret_m = NULL;
125 nbits = read_16 (inp);
126 nread = (nbits + 7) / 8;
127
128 if (nbits > MAX_MPI_BITS || nbits == 0)
129 {
130 _cdk_log_debug ("read_mpi: too large %d bits\n", nbits);
131 return CDK_MPI_Error; /* Sanity check */
132 }
133
134 rc = stream_read (inp, buf + 2, nread, &nread);
135 if (!rc && nread != ((nbits + 7) / 8))
136 {
137 _cdk_log_debug ("read_mpi: too short %d < %d\n", nread,
138 (nbits + 7) / 8);
139 return CDK_MPI_Error;
140 }
141
142 buf[0] = nbits >> 8;
143 buf[1] = nbits >> 0;
144 err = gcry_mpi_scan (&m, GCRYMPI_FMT_PGP, buf, nread + 2, &nread);
145 if (err)
146 return map_gcry_error (err);
147 if (secure)
148 gcry_mpi_set_flag (m, GCRYMPI_FLAG_SECURE);
149 *ret_m = m;
150 return rc;
151}
152
153
154/* Read the encoded packet length directly from the file
155 object INP and return it. Reset RET_PARTIAL if this is
156 the last packet in block mode. */
157size_t
158_cdk_pkt_read_len (FILE * inp, size_t * ret_partial)
159{
160 int c1, c2;
161 size_t pktlen;
162
163 c1 = fgetc (inp);
164 if (c1 == EOF)
165 return (size_t) EOF;
166 if (c1 < 224 || c1 == 255)
167 *ret_partial = 0; /* End of partial data */
168 if (c1 < 192)
169 pktlen = c1;
170 else if (c1 >= 192 && c1 <= 223)
171 {
172 c2 = fgetc (inp);
173 if (c2 == EOF)
174 return (size_t) EOF;
175 pktlen = ((c1 - 192) << 8) + c2 + 192;
176 }
177 else if (c1 == 255)
178 {
179 pktlen = fgetc (inp) << 24;
180 pktlen |= fgetc (inp) << 16;
181 pktlen |= fgetc (inp) << 8;
182 pktlen |= fgetc (inp) << 0;
183 }
184 else
185 pktlen = 1 << (c1 & 0x1f);
186 return pktlen;
187}
188
189
190static cdk_error_t
191read_encrypted (cdk_stream_t inp, size_t pktlen, cdk_pkt_encrypted_t enc,
192 int is_partial, int is_mdc)
193{
194 if (!inp || !enc)
195 return CDK_Inv_Value;
196
197 if (DEBUG_PKT)
198 _cdk_log_debug ("read_encrypted: %d octets\n", pktlen);
199
200 if (is_mdc)
201 {
202 int version = cdk_stream_getc (inp);
203 if (version != MDC_PKT_VER)
204 return CDK_Inv_Packet;
205 enc->mdc_method = CDK_MD_SHA1;
206 pktlen--;
207 }
208 /* The packet must at least contain blocksize + 2 octets. */
209 if (pktlen < 10)
210 return CDK_Inv_Packet;
211 if (is_partial)
212 _cdk_stream_set_blockmode (inp, pktlen);
213 enc->len = pktlen;
214 enc->buf = inp;
215 return 0;
216}
217
218
219static cdk_error_t
220read_symkey_enc (cdk_stream_t inp, size_t pktlen, cdk_pkt_symkey_enc_t ske)
221{
222 cdk_s2k_t s2k;
223 size_t minlen;
224 size_t nread, nleft;
225
226 if (!inp || !ske)
227 return CDK_Inv_Value;
228
229 if (DEBUG_PKT)
230 _cdk_log_debug ("read_symkey_enc: %d octets\n", pktlen);
231
232 ske->version = cdk_stream_getc (inp);
233 if (ske->version != 4 || cdk_stream_eof (inp))
234 return CDK_Inv_Packet;
235
236 s2k = ske->s2k = cdk_calloc (1, sizeof *ske->s2k);
237 if (!ske->s2k)
238 return CDK_Out_Of_Core;
239
240 ske->cipher_algo = cdk_stream_getc (inp);
241 s2k->mode = cdk_stream_getc (inp);
242 switch (s2k->mode)
243 {
244 case CDK_S2K_SIMPLE:
245 minlen = 0;
246 break;
247 case CDK_S2K_SALTED:
248 minlen = 8;
249 break;
250 case CDK_S2K_ITERSALTED:
251 minlen = 9;
252 break;
253
254 default:
255 /* Invalid S2K mode. */
256 return CDK_Inv_Packet;
257 }
258
259 s2k->hash_algo = cdk_stream_getc (inp);
260 if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
261 {
262 if (stream_read (inp, s2k->salt, DIM (s2k->salt), &nread))
263 return CDK_Inv_Packet;
264 if (nread != DIM (s2k->salt))
265 return CDK_Inv_Packet;
266
267 if (s2k->mode == CDK_S2K_ITERSALTED)
268 s2k->count = cdk_stream_getc (inp);
269 }
270
271 ske->seskeylen = pktlen - 4 - minlen;
272 /* We check if there is an encrypted session key and if it fits into
273 the buffer. The maximal key length is 256-bit. */
274 if (ske->seskeylen > DIM (ske->seskey))
275 return CDK_Inv_Packet;
276 nleft = ske->seskeylen;
277 for (nread = 0; nread < ske->seskeylen; nread++)
278 {
279 ske->seskey[nread] = cdk_stream_getc (inp);
280 if (cdk_stream_eof (inp) && --nleft > 0)
281 return CDK_Inv_Packet;
282 }
283
284 return 0;
285}
286
287
288static cdk_error_t
289read_pubkey_enc (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_enc_t pke)
290{
291 size_t i, nenc;
292
293 if (!inp || !pke)
294 return CDK_Inv_Value;
295
296 if (DEBUG_PKT)
297 _cdk_log_debug ("read_pubkey_enc: %d octets\n", pktlen);
298
299 if (pktlen < 12)
300 return CDK_Inv_Packet;
301 pke->version = cdk_stream_getc (inp);
302 if (pke->version < 2 || pke->version > 3)
303 return CDK_Inv_Packet;
304 pke->keyid[0] = read_32 (inp);
305 pke->keyid[1] = read_32 (inp);
306 if (!pke->keyid[0] && !pke->keyid[1])
307 pke->throw_keyid = 1; /* RFC2440 "speculative" keyID */
308 pke->pubkey_algo = cdk_stream_getc (inp);
309 nenc = cdk_pk_get_nenc (pke->pubkey_algo);
310 if (!nenc)
311 return CDK_Inv_Algo;
312 for (i = 0; i < nenc; i++)
313 {
314 cdk_error_t rc = read_mpi (inp, &pke->mpi[i], 0);
315 if (rc)
316 return rc;
317 }
318
319 return 0;
320}
321
322
323
324static cdk_error_t
325read_mdc (cdk_stream_t inp, cdk_pkt_mdc_t mdc)
326{
327 size_t n;
328 cdk_error_t rc;
329
330 if (!inp || !mdc)
331 return CDK_Inv_Value;
332
333 if (DEBUG_PKT)
334 _cdk_log_debug ("read_mdc:\n");
335
336 rc = stream_read (inp, mdc->hash, DIM (mdc->hash), &n);
337 if (rc)
338 return rc;
339
340 return n != DIM (mdc->hash) ? CDK_Inv_Packet : 0;
341}
342
343
344static cdk_error_t
345read_compressed (cdk_stream_t inp, size_t pktlen, cdk_pkt_compressed_t c)
346{
347 if (!inp || !c)
348 return CDK_Inv_Value;
349
350 if (DEBUG_PKT)
351 _cdk_log_debug ("read_compressed: %d octets\n", pktlen);
352
353 c->algorithm = cdk_stream_getc (inp);
354 if (c->algorithm > 3)
355 return CDK_Inv_Packet;
356
357 /* don't know the size, so we read until EOF */
358 if (!pktlen)
359 {
360 c->len = 0;
361 c->buf = inp;
362 }
363
364 /* FIXME: Support partial bodies. */
365 return 0;
366}
367
368
369static cdk_error_t
370read_public_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_t pk)
371{
372 size_t i, ndays, npkey;
373
374 if (!inp || !pk)
375 return CDK_Inv_Value;
376
377 if (DEBUG_PKT)
378 _cdk_log_debug ("read_public_key: %d octets\n", pktlen);
379
380 pk->is_invalid = 1; /* default to detect missing self signatures */
381 pk->is_revoked = 0;
382 pk->has_expired = 0;
383
384 pk->version = cdk_stream_getc (inp);
385 if (pk->version < 2 || pk->version > 4)
386 return CDK_Inv_Packet_Ver;
387 pk->timestamp = read_32 (inp);
388 if (pk->version < 4)
389 {
390 ndays = read_16 (inp);
391 if (ndays)
392 pk->expiredate = pk->timestamp + ndays * 86400L;
393 }
394
395 pk->pubkey_algo = cdk_stream_getc (inp);
396 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
397 if (!npkey)
398 {
399 _cdk_log_debug ("invalid public key algorithm %d\n", pk->pubkey_algo);
400 return CDK_Inv_Algo;
401 }
402 for (i = 0; i < npkey; i++)
403 {
404 cdk_error_t rc = read_mpi (inp, &pk->mpi[i], 0);
405 if (rc)
406 return rc;
407 }
408
409 /* These values are just for the first run and should be
410 replaced with the actual key flags from the self signature. */
411 pk->pubkey_usage = _cdk_pk_algo_usage (pk->pubkey_algo);
412 return 0;
413}
414
415
416static cdk_error_t
417read_public_subkey (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_t pk)
418{
419 if (!inp || !pk)
420 return CDK_Inv_Value;
421 return read_public_key (inp, pktlen, pk);
422}
423
424
425static cdk_error_t
426read_secret_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_seckey_t sk)
427{
428 size_t p1, p2, nread;
429 int i, nskey;
430 int rc;
431
432 if (!inp || !sk || !sk->pk)
433 return CDK_Inv_Value;
434
435 if (DEBUG_PKT)
436 _cdk_log_debug ("read_secret_key: %d octets\n", pktlen);
437
438 p1 = cdk_stream_tell (inp);
439 rc = read_public_key (inp, pktlen, sk->pk);
440 if (rc)
441 return rc;
442
443 sk->s2k_usage = cdk_stream_getc (inp);
444 sk->protect.sha1chk = 0;
445 if (sk->s2k_usage == 254 || sk->s2k_usage == 255)
446 {
447 sk->protect.sha1chk = (sk->s2k_usage == 254);
448 sk->protect.algo = cdk_stream_getc (inp);
449 sk->protect.s2k = cdk_calloc (1, sizeof *sk->protect.s2k);
450 if (!sk->protect.s2k)
451 return CDK_Out_Of_Core;
452 rc = read_s2k (inp, sk->protect.s2k);
453 if (rc)
454 return rc;
455 sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo);
456 if (!sk->protect.ivlen)
457 return CDK_Inv_Packet;
458 rc = stream_read (inp, sk->protect.iv, sk->protect.ivlen, &nread);
459 if (rc)
460 return rc;
461 if (nread != sk->protect.ivlen)
462 return CDK_Inv_Packet;
463 }
464 else
465 sk->protect.algo = sk->s2k_usage;
466 if (sk->protect.algo == GCRY_CIPHER_NONE)
467 {
468 sk->csum = 0;
469 nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
470 if (!nskey)
471 return CDK_Inv_Algo;
472 for (i = 0; i < nskey; i++)
473 {
474 rc = read_mpi (inp, &sk->mpi[i], 1);
475 if (rc)
476 return rc;
477 }
478 sk->csum = read_16 (inp);
479 sk->is_protected = 0;
480 }
481 else if (sk->pk->version < 4)
482 {
483 /* The length of each multiprecision integer is stored in plaintext. */
484 nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
485 if (!nskey)
486 return CDK_Inv_Algo;
487 for (i = 0; i < nskey; i++)
488 {
489 rc = read_mpi (inp, &sk->mpi[i], 1);
490 if (rc)
491 return rc;
492 }
493 sk->csum = read_16 (inp);
494 sk->is_protected = 1;
495 }
496 else
497 {
498 /* We need to read the rest of the packet because we do not
499 have any information how long the encrypted mpi's are */
500 p2 = cdk_stream_tell (inp);
501 p2 -= p1;
502 sk->enclen = pktlen - p2;
503 if (sk->enclen < 2)
504 return CDK_Inv_Packet; /* at least 16 bits for the checksum! */
505 sk->encdata = cdk_calloc (1, sk->enclen + 1);
506 if (!sk->encdata)
507 return CDK_Out_Of_Core;
508 if (stream_read (inp, sk->encdata, sk->enclen, &nread))
509 return CDK_Inv_Packet;
510 nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
511 if (!nskey)
512 return CDK_Inv_Algo;
513 /* We mark each MPI entry with NULL to indicate a protected key. */
514 for (i = 0; i < nskey; i++)
515 sk->mpi[i] = NULL;
516 sk->is_protected = 1;
517 }
518
519 sk->is_primary = 1;
520 _cdk_copy_pk_to_sk (sk->pk, sk);
521 return 0;
522}
523
524
525static cdk_error_t
526read_secret_subkey (cdk_stream_t inp, size_t pktlen, cdk_pkt_seckey_t sk)
527{
528 cdk_error_t rc;
529
530 if (!inp || !sk || !sk->pk)
531 return CDK_Inv_Value;
532
533 rc = read_secret_key (inp, pktlen, sk);
534 sk->is_primary = 0;
535 return rc;
536}
537
538
539static cdk_error_t
540read_attribute (cdk_stream_t inp, size_t pktlen, cdk_pkt_userid_t attr)
541{
542 const byte *p;
543 byte *buf;
544 size_t len, nread;
545 cdk_error_t rc;
546
547 if (!inp || !attr || !pktlen)
548 return CDK_Inv_Value;
549
550 if (DEBUG_PKT)
551 _cdk_log_debug ("read_attribute: %d octets\n", pktlen);
552
553 strcpy (attr->name, "[attribute]");
554 attr->len = strlen (attr->name);
555 buf = cdk_calloc (1, pktlen);
556 if (!buf)
557 return CDK_Out_Of_Core;
558 rc = stream_read (inp, buf, pktlen, &nread);
559 if (rc)
560 {
561 cdk_free (buf);
562 return CDK_Inv_Packet;
563 }
564 p = buf;
565 len = *p++;
566 pktlen--;
567 if (len == 255)
568 {
569 len = _cdk_buftou32 (p);
570 p += 4;
571 pktlen -= 4;
572 }
573 else if (len >= 192)
574 {
575 if (pktlen < 2)
576 {
577 cdk_free (buf);
578 return CDK_Inv_Packet;
579 }
580 len = ((len - 192) << 8) + *p + 192;
581 p++;
582 pktlen--;
583 }
584
585 if (*p != 1) /* Currently only 1, meaning an image, is defined. */
586 {
587 cdk_free (buf);
588 return CDK_Inv_Packet;
589 }
590 p++;
591 len--;
592
593 if (pktlen - (len + 1) > 0)
594 return CDK_Inv_Packet;
595 attr->attrib_img = cdk_calloc (1, len);
596 if (!attr->attrib_img)
597 {
598 cdk_free (buf);
599 return CDK_Out_Of_Core;
600 }
601 attr->attrib_len = len;
602 memcpy (attr->attrib_img, p, len);
603 cdk_free (buf);
604 return rc;
605}
606
607
608static cdk_error_t
609read_user_id (cdk_stream_t inp, size_t pktlen, cdk_pkt_userid_t user_id)
610{
611 size_t nread;
612 cdk_error_t rc;
613
614 if (!inp || !user_id)
615 return CDK_Inv_Value;
616 if (!pktlen)
617 return CDK_Inv_Packet;
618
619 if (DEBUG_PKT)
620 _cdk_log_debug ("read_user_id: %lu octets\n", pktlen);
621
622 user_id->len = pktlen;
623 rc = stream_read (inp, user_id->name, pktlen, &nread);
624 if (rc)
625 return rc;
626 if (nread != pktlen)
627 return CDK_Inv_Packet;
628 user_id->name[nread] = '\0';
629 return rc;
630}
631
632
633static cdk_error_t
634read_subpkt (cdk_stream_t inp, cdk_subpkt_t * r_ctx, size_t * r_nbytes)
635{
636 byte c, c1;
637 size_t size, nread, n;
638 cdk_subpkt_t node;
639 cdk_error_t rc;
640
641 if (!inp || !r_nbytes)
642 return CDK_Inv_Value;
643
644 if (DEBUG_PKT)
645 _cdk_log_debug ("read_subpkt:\n");
646
647 n = 0;
648 *r_nbytes = 0;
649 c = cdk_stream_getc (inp);
650 n++;
651 if (c == 255)
652 {
653 size = read_32 (inp);
654 n += 4;
655 }
656 else if (c >= 192 && c < 255)
657 {
658 c1 = cdk_stream_getc (inp);
659 n++;
660 if (c1 == 0)
661 return 0;
662 size = ((c - 192) << 8) + c1 + 192;
663 }
664 else if (c < 192)
665 size = c;
666 else
667 return CDK_Inv_Packet;
668
669 node = cdk_subpkt_new (size);
670 if (!node)
671 return CDK_Out_Of_Core;
672 node->size = size;
673 node->type = cdk_stream_getc (inp);
674 if (DEBUG_PKT)
675 _cdk_log_debug (" %d octets %d type\n", node->size, node->type);
676 n++;
677 node->size--;
678 rc = stream_read (inp, node->d, node->size, &nread);
679 n += nread;
680 if (rc)
681 return rc;
682 *r_nbytes = n;
683 if (!*r_ctx)
684 *r_ctx = node;
685 else
686 cdk_subpkt_add (*r_ctx, node);
687 return rc;
688}
689
690
691static cdk_error_t
692read_onepass_sig (cdk_stream_t inp, size_t pktlen, cdk_pkt_onepass_sig_t sig)
693{
694 if (!inp || !sig)
695 return CDK_Inv_Value;
696
697 if (DEBUG_PKT)
698 _cdk_log_debug ("read_onepass_sig: %d octets\n", pktlen);
699
700 if (pktlen != 13)
701 return CDK_Inv_Packet;
702 sig->version = cdk_stream_getc (inp);
703 if (sig->version != 3)
704 return CDK_Inv_Packet_Ver;
705 sig->sig_class = cdk_stream_getc (inp);
706 sig->digest_algo = cdk_stream_getc (inp);
707 sig->pubkey_algo = cdk_stream_getc (inp);
708 sig->keyid[0] = read_32 (inp);
709 sig->keyid[1] = read_32 (inp);
710 sig->last = cdk_stream_getc (inp);
711 return 0;
712}
713
714
715static cdk_error_t
716parse_sig_subpackets (cdk_pkt_signature_t sig)
717{
718 cdk_subpkt_t node;
719
720 /* Setup the standard packet entries, so we can use V4
721 signatures similar to V3. */
722 for (node = sig->unhashed; node; node = node->next)
723 {
724 if (node->type == CDK_SIGSUBPKT_ISSUER && node->size >= 8)
725 {
726 sig->keyid[0] = _cdk_buftou32 (node->d);
727 sig->keyid[1] = _cdk_buftou32 (node->d + 4);
728 }
729 else if (node->type == CDK_SIGSUBPKT_EXPORTABLE && node->d[0] == 0)
730 {
731 /* Sometimes this packet might be placed in the unhashed area */
732 sig->flags.exportable = 0;
733 }
734 }
735 for (node = sig->hashed; node; node = node->next)
736 {
737 if (node->type == CDK_SIGSUBPKT_SIG_CREATED && node->size >= 4)
738 sig->timestamp = _cdk_buftou32 (node->d);
739 else if (node->type == CDK_SIGSUBPKT_SIG_EXPIRE && node->size >= 4)
740 {
741 sig->expiredate = _cdk_buftou32 (node->d);
742 if (sig->expiredate > 0 && sig->expiredate < (u32) time (NULL))
743 sig->flags.expired = 1;
744 }
745 else if (node->type == CDK_SIGSUBPKT_POLICY)
746 sig->flags.policy_url = 1;
747 else if (node->type == CDK_SIGSUBPKT_NOTATION)
748 sig->flags.notation = 1;
749 else if (node->type == CDK_SIGSUBPKT_REVOCABLE && node->d[0] == 0)
750 sig->flags.revocable = 0;
751 else if (node->type == CDK_SIGSUBPKT_EXPORTABLE && node->d[0] == 0)
752 sig->flags.exportable = 0;
753 }
754 if (sig->sig_class == 0x1F)
755 {
756 cdk_desig_revoker_t r, rnode;
757
758 for (node = sig->hashed; node; node = node->next)
759 {
760 if (node->type == CDK_SIGSUBPKT_REV_KEY)
761 {
762 if (node->size < 22)
763 continue;
764 rnode = cdk_calloc (1, sizeof *rnode);
765 if (!rnode)
766 return CDK_Out_Of_Core;
767 rnode->r_class = node->d[0];
768 rnode->algid = node->d[1];
769 memcpy (rnode->fpr, node->d + 2, KEY_FPR_LEN);
770 if (!sig->revkeys)
771 sig->revkeys = rnode;
772 else
773 {
774 for (r = sig->revkeys; r->next; r = r->next)
775 ;
776 r->next = rnode;
777 }
778 }
779 }
780 }
781
782 return 0;
783}
784
785
786static cdk_error_t
787read_signature (cdk_stream_t inp, size_t pktlen, cdk_pkt_signature_t sig)
788{
789 size_t nbytes;
790 size_t i, size, nsig;
791 cdk_error_t rc;
792
793 if (!inp || !sig)
794 return CDK_Inv_Value;
795
796 if (DEBUG_PKT)
797 _cdk_log_debug ("read_signature: %d octets\n", pktlen);
798
799 if (pktlen < 16)
800 return CDK_Inv_Packet;
801 sig->version = cdk_stream_getc (inp);
802 if (sig->version < 2 || sig->version > 4)
803 return CDK_Inv_Packet_Ver;
804
805 sig->flags.exportable = 1;
806 sig->flags.revocable = 1;
807
808 if (sig->version < 4)
809 {
810 if (cdk_stream_getc (inp) != 5)
811 return CDK_Inv_Packet;
812 sig->sig_class = cdk_stream_getc (inp);
813 sig->timestamp = read_32 (inp);
814 sig->keyid[0] = read_32 (inp);
815 sig->keyid[1] = read_32 (inp);
816 sig->pubkey_algo = cdk_stream_getc (inp);
817 sig->digest_algo = cdk_stream_getc (inp);
818 sig->digest_start[0] = cdk_stream_getc (inp);
819 sig->digest_start[1] = cdk_stream_getc (inp);
820 nsig = cdk_pk_get_nsig (sig->pubkey_algo);
821 if (!nsig)
822 return CDK_Inv_Algo;
823 for (i = 0; i < nsig; i++)
824 {
825 rc = read_mpi (inp, &sig->mpi[i], 0);
826 if (rc)
827 return rc;
828 }
829 }
830 else
831 {
832 sig->sig_class = cdk_stream_getc (inp);
833 sig->pubkey_algo = cdk_stream_getc (inp);
834 sig->digest_algo = cdk_stream_getc (inp);
835 sig->hashed_size = read_16 (inp);
836 size = sig->hashed_size;
837 sig->hashed = NULL;
838 while (size > 0)
839 {
840 rc = read_subpkt (inp, &sig->hashed, &nbytes);
841 if (rc)
842 return rc;
843 size -= nbytes;
844 }
845 sig->unhashed_size = read_16 (inp);
846 size = sig->unhashed_size;
847 sig->unhashed = NULL;
848 while (size > 0)
849 {
850 rc = read_subpkt (inp, &sig->unhashed, &nbytes);
851 if (rc)
852 return rc;
853 size -= nbytes;
854 }
855
856 rc = parse_sig_subpackets (sig);
857 if (rc)
858 return rc;
859
860 sig->digest_start[0] = cdk_stream_getc (inp);
861 sig->digest_start[1] = cdk_stream_getc (inp);
862 nsig = cdk_pk_get_nsig (sig->pubkey_algo);
863 if (!nsig)
864 return CDK_Inv_Algo;
865 for (i = 0; i < nsig; i++)
866 {
867 rc = read_mpi (inp, &sig->mpi[i], 0);
868 if (rc)
869 return rc;
870 }
871 }
872
873 return 0;
874}
875
876
877static cdk_error_t
878read_literal (cdk_stream_t inp, size_t pktlen,
879 cdk_pkt_literal_t * ret_pt, int is_partial)
880{
881 cdk_pkt_literal_t pt = *ret_pt;
882 size_t nread;
883 cdk_error_t rc;
884
885 if (!inp || !pt)
886 return CDK_Inv_Value;
887
888 if (DEBUG_PKT)
889 _cdk_log_debug ("read_literal: %d octets\n", pktlen);
890
891 pt->mode = cdk_stream_getc (inp);
892 if (pt->mode != 0x62 && pt->mode != 0x74 && pt->mode != 0x75)
893 return CDK_Inv_Packet;
894 if (cdk_stream_eof (inp))
895 return CDK_Inv_Packet;
896
897 pt->namelen = cdk_stream_getc (inp);
898 if (pt->namelen > 0)
899 {
900 *ret_pt = pt = cdk_realloc (pt, sizeof *pt + pt->namelen + 1);
901 if (!pt)
902 return CDK_Out_Of_Core;
903 rc = stream_read (inp, pt->name, pt->namelen, &nread);
904 if (rc)
905 return rc;
906 if (nread != pt->namelen)
907 return CDK_Inv_Packet;
908 pt->name[pt->namelen] = '\0';
909 }
910 pt->timestamp = read_32 (inp);
911 pktlen = pktlen - 6 - pt->namelen;
912 if (is_partial)
913 _cdk_stream_set_blockmode (inp, pktlen);
914 pt->buf = inp;
915 pt->len = pktlen;
916 return 0;
917}
918
919
920/* Read an old packet CTB and return the length of the body. */
921static void
922read_old_length (cdk_stream_t inp, int ctb, size_t * r_len, size_t * r_size)
923{
924 int llen = ctb & 0x03;
925
926 if (llen == 0)
927 {
928 *r_len = cdk_stream_getc (inp);
929 (*r_size)++;
930 }
931 else if (llen == 1)
932 {
933 *r_len = read_16 (inp);
934 (*r_size) += 2;
935 }
936 else if (llen == 2)
937 {
938 *r_len = read_32 (inp);
939 (*r_size) += 4;
940 }
941 else
942 {
943 *r_len = 0;
944 *r_size = 0;
945 }
946}
947
948
949/* Read a new CTB and decode the body length. */
950static void
951read_new_length (cdk_stream_t inp,
952 size_t * r_len, size_t * r_size, size_t * r_partial)
953{
954 int c, c1;
955
956 c = cdk_stream_getc (inp);
957 (*r_size)++;
958 if (c < 192)
959 *r_len = c;
960 else if (c >= 192 && c <= 223)
961 {
962 c1 = cdk_stream_getc (inp);
963 (*r_size)++;
964 *r_len = ((c - 192) << 8) + c1 + 192;
965 }
966 else if (c == 255)
967 {
968 *r_len = read_32 (inp);
969 (*r_size) += 4;
970 }
971 else
972 {
973 *r_len = 1 << (c & 0x1f);
974 *r_partial = 1;
975 }
976}
977
978
979/* Skip the current packet body. */
980static void
981skip_packet (cdk_stream_t inp, size_t pktlen)
982{
983 byte buf[BUFSIZE];
984 size_t nread, buflen = DIM (buf);
985
986 while (pktlen > 0)
987 {
988 stream_read (inp, buf, pktlen > buflen ? buflen : pktlen, &nread);
989 pktlen -= nread;
990 }
991
992 assert (pktlen == 0);
993}
994
995
996/**
997 * cdk_pkt_read:
998 * @inp: the input stream
999 * @pkt: allocated packet handle to store the packet
1000 *
1001 * Parse the next packet on the @inp stream and return its contents in @pkt.
1002 **/
1003cdk_error_t
1004cdk_pkt_read (cdk_stream_t inp, cdk_packet_t pkt)
1005{
1006 int use_mdc = 0;
1007 int ctb, is_newctb;
1008 int pkttype;
1009 size_t pktlen = 0, pktsize = 0, is_partial = 0;
1010 cdk_error_t rc;
1011
1012 if (!inp || !pkt)
1013 return CDK_Inv_Value;
1014
1015 ctb = cdk_stream_getc (inp);
1016 if (cdk_stream_eof (inp) || ctb == EOF)
1017 return CDK_EOF;
1018 else if (!ctb)
1019 return CDK_Inv_Packet;
1020
1021 pktsize++;
1022 if (!(ctb & 0x80))
1023 {
1024 _cdk_log_info ("cdk_pkt_read: no openpgp data found. "
1025 "(ctb=%02X; fpos=%02X)\n", ctb, cdk_stream_tell (inp));
1026 return CDK_Inv_Packet;
1027 }
1028
1029 if (ctb & 0x40) /* RFC2440 packet format. */
1030 {
1031 pkttype = ctb & 0x3f;
1032 is_newctb = 1;
1033 }
1034 else /* the old RFC1991 packet format. */
1035 {
1036 pkttype = ctb & 0x3f;
1037 pkttype >>= 2;
1038 is_newctb = 0;
1039 }
1040
1041 if (pkttype > 63)
1042 {
1043 _cdk_log_info ("cdk_pkt_read: unknown type %d\n", pkttype);
1044 return CDK_Inv_Packet;
1045 }
1046
1047 if (is_newctb)
1048 read_new_length (inp, &pktlen, &pktsize, &is_partial);
1049 else
1050 read_old_length (inp, ctb, &pktlen, &pktsize);
1051
1052 pkt->pkttype = pkttype;
1053 pkt->pktlen = pktlen;
1054 pkt->pktsize = pktsize + pktlen;
1055 pkt->old_ctb = is_newctb ? 0 : 1;
1056
1057 rc = 0;
1058 switch (pkt->pkttype)
1059 {
1060 case CDK_PKT_ATTRIBUTE:
1061 pkt->pkt.user_id = cdk_calloc (1, sizeof *pkt->pkt.user_id
1062 + pkt->pktlen + 16 + 1);
1063 if (!pkt->pkt.user_id)
1064 return CDK_Out_Of_Core;
1065 rc = read_attribute (inp, pktlen, pkt->pkt.user_id);
1066 pkt->pkttype = CDK_PKT_ATTRIBUTE;
1067 break;
1068
1069 case CDK_PKT_USER_ID:
1070 pkt->pkt.user_id = cdk_calloc (1, sizeof *pkt->pkt.user_id
1071 + pkt->pktlen);
1072 if (!pkt->pkt.user_id)
1073 return CDK_Out_Of_Core;
1074 rc = read_user_id (inp, pktlen, pkt->pkt.user_id);
1075 break;
1076
1077 case CDK_PKT_PUBLIC_KEY:
1078 pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
1079 if (!pkt->pkt.public_key)
1080 return CDK_Out_Of_Core;
1081 rc = read_public_key (inp, pktlen, pkt->pkt.public_key);
1082 break;
1083
1084 case CDK_PKT_PUBLIC_SUBKEY:
1085 pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
1086 if (!pkt->pkt.public_key)
1087 return CDK_Out_Of_Core;
1088 rc = read_public_subkey (inp, pktlen, pkt->pkt.public_key);
1089 break;
1090
1091 case CDK_PKT_SECRET_KEY:
1092 pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
1093 if (!pkt->pkt.secret_key)
1094 return CDK_Out_Of_Core;
1095 pkt->pkt.secret_key->pk = cdk_calloc (1,
1096 sizeof *pkt->pkt.secret_key->pk);
1097 if (!pkt->pkt.secret_key->pk)
1098 return CDK_Out_Of_Core;
1099 rc = read_secret_key (inp, pktlen, pkt->pkt.secret_key);
1100 break;
1101
1102 case CDK_PKT_SECRET_SUBKEY:
1103 pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
1104 if (!pkt->pkt.secret_key)
1105 return CDK_Out_Of_Core;
1106 pkt->pkt.secret_key->pk = cdk_calloc (1,
1107 sizeof *pkt->pkt.secret_key->pk);
1108 if (!pkt->pkt.secret_key->pk)
1109 return CDK_Out_Of_Core;
1110 rc = read_secret_subkey (inp, pktlen, pkt->pkt.secret_key);
1111 break;
1112
1113 case CDK_PKT_LITERAL:
1114 pkt->pkt.literal = cdk_calloc (1, sizeof *pkt->pkt.literal);
1115 if (!pkt->pkt.literal)
1116 return CDK_Out_Of_Core;
1117 rc = read_literal (inp, pktlen, &pkt->pkt.literal, is_partial);
1118 break;
1119
1120 case CDK_PKT_ONEPASS_SIG:
1121 pkt->pkt.onepass_sig = cdk_calloc (1, sizeof *pkt->pkt.onepass_sig);
1122 if (!pkt->pkt.onepass_sig)
1123 return CDK_Out_Of_Core;
1124 rc = read_onepass_sig (inp, pktlen, pkt->pkt.onepass_sig);
1125 break;
1126
1127 case CDK_PKT_SIGNATURE:
1128 pkt->pkt.signature = cdk_calloc (1, sizeof *pkt->pkt.signature);
1129 if (!pkt->pkt.signature)
1130 return CDK_Out_Of_Core;
1131 rc = read_signature (inp, pktlen, pkt->pkt.signature);
1132 break;
1133
1134 case CDK_PKT_ENCRYPTED_MDC:
1135 case CDK_PKT_ENCRYPTED:
1136 pkt->pkt.encrypted = cdk_calloc (1, sizeof *pkt->pkt.encrypted);
1137 if (!pkt->pkt.encrypted)
1138 return CDK_Out_Of_Core;
1139 use_mdc = (pkt->pkttype == CDK_PKT_ENCRYPTED_MDC) ? 1 : 0;
1140 rc = read_encrypted (inp, pktlen, pkt->pkt.encrypted,
1141 is_partial, use_mdc);
1142 break;
1143
1144 case CDK_PKT_SYMKEY_ENC:
1145 pkt->pkt.symkey_enc = cdk_calloc (1, sizeof *pkt->pkt.symkey_enc);
1146 if (!pkt->pkt.symkey_enc)
1147 return CDK_Out_Of_Core;
1148 rc = read_symkey_enc (inp, pktlen, pkt->pkt.symkey_enc);
1149 break;
1150
1151 case CDK_PKT_PUBKEY_ENC:
1152 pkt->pkt.pubkey_enc = cdk_calloc (1, sizeof *pkt->pkt.pubkey_enc);
1153 if (!pkt->pkt.pubkey_enc)
1154 return CDK_Out_Of_Core;
1155 rc = read_pubkey_enc (inp, pktlen, pkt->pkt.pubkey_enc);
1156 break;
1157
1158 case CDK_PKT_COMPRESSED:
1159 pkt->pkt.compressed = cdk_calloc (1, sizeof *pkt->pkt.compressed);
1160 if (!pkt->pkt.compressed)
1161 return CDK_Out_Of_Core;
1162 rc = read_compressed (inp, pktlen, pkt->pkt.compressed);
1163 break;
1164
1165 case CDK_PKT_MDC:
1166 pkt->pkt.mdc = cdk_calloc (1, sizeof *pkt->pkt.mdc);
1167 if (!pkt->pkt.mdc)
1168 return CDK_Out_Of_Core;
1169 rc = read_mdc (inp, pkt->pkt.mdc);
1170 break;
1171
1172 default:
1173 /* Skip all packets we don't understand */
1174 skip_packet (inp, pktlen);
1175 break;
1176 }
1177
1178 return rc;
1179}
diff --git a/src/daemon/https/opencdk/seskey.c b/src/daemon/https/opencdk/seskey.c
new file mode 100644
index 00000000..54c25af2
--- /dev/null
+++ b/src/daemon/https/opencdk/seskey.c
@@ -0,0 +1,717 @@
1/* seskey.c - Session key routines
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 * Copyright (C) 1998-2000, 2002 Free Software Foundation, Inc.
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <assert.h>
21#include <stdio.h>
22#include <gcrypt.h>
23
24#include "opencdk.h"
25#include "main.h"
26#include "packet.h"
27
28
29/* We encode the MD in this way:
30 *
31 * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
32 *
33 * PAD consists of FF bytes.
34 */
35static cdk_error_t
36do_encode_md (byte ** r_frame, size_t * r_flen, const byte * md, int algo,
37 size_t len, unsigned nbits, const byte * asn, size_t asnlen)
38{
39 byte *frame = NULL;
40 size_t nframe = (nbits + 7) / 8;
41 size_t i, n = 0;
42
43 if (!asn || !md || !r_frame || !r_flen)
44 return CDK_Inv_Value;
45
46 if (len + asnlen + 4 > nframe)
47 return CDK_General_Error;
48
49 frame = cdk_calloc (1, nframe);
50 if (!frame)
51 return CDK_Out_Of_Core;
52 frame[n++] = 0;
53 frame[n++] = 1;
54 i = nframe - len - asnlen - 3;
55 if (i < 0)
56 {
57 cdk_free (frame);
58 return CDK_Inv_Value;
59 }
60 memset (frame + n, 0xFF, i);
61 n += i;
62 frame[n++] = 0;
63 memcpy (frame + n, asn, asnlen);
64 n += asnlen;
65 memcpy (frame + n, md, len);
66 n += len;
67 if (n != nframe)
68 {
69 cdk_free (frame);
70 return CDK_Inv_Value;
71 }
72 *r_frame = frame;
73 *r_flen = n;
74 return 0;
75}
76
77
78
79/* RFC2437 format:
80 *
81 * 0 2 RND(n bytes) 0 [A DEK(k bytes) CSUM(2 bytes)]
82 *
83 * RND - randomized bytes for padding.
84 * A - cipher algorithm.
85 * DEK - random session key.
86 * CKSUM - algebraic checksum of the DEK.
87 */
88
89/**
90 * cdk_dek_encode_pkcs1
91 * @dek: DEK object
92 * @nbits: size of the multi precision integer frame
93 * @r_enc: output of the encoded multiprecision integer
94 *
95 * Encode the given random session key in the DEK object
96 * into a multiprecision integer.
97 **/
98cdk_error_t
99cdk_dek_encode_pkcs1 (cdk_dek_t dek, size_t nbits, gcry_mpi_t * r_enc)
100{
101 gcry_mpi_t a = NULL;
102 gcry_error_t err;
103 byte *p, *frame;
104 size_t n;
105 size_t nframe;
106 size_t i;
107 u16 chksum;
108
109 if (!r_enc || !dek)
110 return CDK_Inv_Value;
111
112 *r_enc = NULL;
113 chksum = 0;
114 for (i = 0; i < dek->keylen; i++)
115 chksum += dek->key[i];
116 nframe = (nbits + 7) / 8;
117 frame = cdk_salloc (nframe + 1, 1);
118 if (!frame)
119 return CDK_Out_Of_Core;
120 n = 0;
121 frame[n++] = 0x00;
122 frame[n++] = 0x02;
123 i = nframe - 6 - dek->keylen;
124 p = gcry_random_bytes (i, GCRY_STRONG_RANDOM);
125 /* Replace zero bytes by new values */
126 for (;;)
127 {
128 size_t j, k;
129 byte *pp;
130
131 /* count the zero bytes */
132 for (j = k = 0; j < i; j++)
133 {
134 if (!p[j])
135 k++;
136 }
137 if (!k)
138 break; /* No zeroes remain. */
139 k += k / 128; /* better get some more */
140 pp = gcry_random_bytes (k, GCRY_STRONG_RANDOM);
141 for (j = 0; j < i && k; j++)
142 {
143 if (!p[j])
144 p[j] = pp[--k];
145 }
146 cdk_free (pp);
147 }
148 memcpy (frame + n, p, i);
149 cdk_free (p);
150 n += i;
151 frame[n++] = 0;
152 frame[n++] = dek->algo;
153 memcpy (frame + n, dek->key, dek->keylen);
154 n += dek->keylen;
155 frame[n++] = chksum >> 8;
156 frame[n++] = chksum;
157 err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, nframe, &nframe);
158 cdk_free (frame);
159 if (err)
160 return map_gcry_error (err);
161 *r_enc = a;
162 return 0;
163}
164
165
166/**
167 * cdk_dek_decode_pkcs1:
168 * @ret_dek: the decoded DEK object
169 * @esk: the pkcs#1 encoded session key.
170 *
171 * Decode the given multi precision integer in pkcs#1 and
172 * store it into the DEK object.
173 **/
174cdk_error_t
175cdk_dek_decode_pkcs1 (cdk_dek_t * ret_dek, gcry_mpi_t esk)
176{
177 cdk_dek_t dek;
178 byte frame[MAX_MPI_BYTES + 2 + 1];
179 size_t nframe, n;
180 u16 csum, csum2;
181 gcry_error_t err;
182
183 if (!ret_dek || !esk)
184 return CDK_Inv_Value;
185
186 *ret_dek = NULL; /* reset */
187 nframe = DIM (frame) - 1;
188 err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, esk);
189 if (err)
190 return map_gcry_error (err);
191 dek = cdk_salloc (sizeof *dek, 1);
192 if (!dek)
193 return CDK_Out_Of_Core;
194
195 /* Now get the DEK (data encryption key) from the frame
196 *
197 * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
198 *
199 * (gcry_mpi_print already removed the leading zero).
200 *
201 * RND are non-zero randow bytes.
202 * A is the cipher algorithm
203 * DEK is the encryption key (session key) with length k
204 * CSUM
205 */
206 n = 0;
207 if (frame[n] != 2)
208 {
209 cdk_free (dek);
210 return CDK_Inv_Mode;
211 }
212 for (n++; n < nframe && frame[n]; n++)
213 ;
214 n++;
215 dek->keylen = nframe - (n + 1) - 2;
216 dek->algo = frame[n++];
217 if (dek->keylen != gcry_cipher_get_algo_keylen (dek->algo))
218 {
219 _cdk_log_debug ("pkcs1 decode: invalid cipher keylen %d\n",
220 dek->keylen);
221 cdk_free (dek);
222 return CDK_Inv_Algo;
223 }
224 csum = frame[nframe - 2] << 8;
225 csum |= frame[nframe - 1];
226 memcpy (dek->key, frame + n, dek->keylen);
227 csum2 = 0;
228 for (n = 0; n < dek->keylen; n++)
229 csum2 += dek->key[n];
230 if (csum != csum2)
231 {
232 _cdk_log_debug ("pkcs decode: checksum does not match\n");
233 cdk_free (dek);
234 return CDK_Chksum_Error;
235 }
236 *ret_dek = dek;
237 return 0;
238}
239
240
241/* Encode the given digest into a pkcs#1 compatible format. */
242cdk_error_t
243_cdk_digest_encode_pkcs1 (byte ** r_md, size_t * r_mdlen, int pk_algo,
244 const byte * md, int digest_algo, unsigned nbits)
245{
246 gcry_error_t err;
247 size_t dlen;
248
249 if (!md || !r_md || !r_mdlen)
250 return CDK_Inv_Value;
251
252 dlen = gcry_md_get_algo_dlen (digest_algo);
253 if (!dlen)
254 return CDK_Inv_Algo;
255 if (is_DSA (pk_algo)) /* DSS does not use a special encoding. */
256 {
257 *r_md = cdk_malloc (dlen + 1);
258 if (!*r_md)
259 return CDK_Out_Of_Core;
260 *r_mdlen = dlen;
261 memcpy (*r_md, md, dlen);
262 return 0;
263 }
264 else
265 {
266 byte *asn;
267 size_t asnlen;
268 cdk_error_t rc;
269
270 err = gcry_md_get_asnoid (digest_algo, NULL, &asnlen);
271 if (err)
272 return map_gcry_error (err);
273 asn = cdk_malloc (asnlen + 1);
274 if (!asn)
275 return CDK_Out_Of_Core;
276 err = gcry_md_get_asnoid (digest_algo, asn, &asnlen);
277 if (err)
278 {
279 cdk_free (asn);
280 return map_gcry_error (err);
281 }
282 rc = do_encode_md (r_md, r_mdlen, md, digest_algo, dlen,
283 nbits, asn, asnlen);
284 cdk_free (asn);
285 return rc;
286 }
287 return 0;
288}
289
290
291/* FIXME: The prompt should be provided in a more generic way.
292 Like: (keyid, algorithm, [user-id]) */
293static char *
294passphrase_prompt (cdk_pkt_seckey_t sk)
295{
296 u32 keyid = cdk_pk_get_keyid (sk->pk, NULL);
297 int bits = cdk_pk_get_nbits (sk->pk), pk_algo = sk->pubkey_algo;
298 const char *algo = "???", *fmt;
299 char *p;
300
301 if (is_RSA (pk_algo))
302 algo = "RSA";
303 else if (is_ELG (pk_algo))
304 algo = "ELG";
305 else if (is_DSA (pk_algo))
306 algo = "DSA";
307
308 fmt = "%d-bit %s key, ID %08lX\nEnter Passphrase: ";
309 p = cdk_calloc (1, 64 + strlen (fmt) + strlen (algo) + 1);
310 if (!p)
311 return NULL;
312 sprintf (p, fmt, bits, algo, keyid);
313 return p;
314}
315
316
317/* Try to unprotect the secret key, if needed, automatically.
318 The passphrase callback is used to get the passphrase directly
319 from the user. */
320cdk_error_t
321_cdk_sk_unprotect_auto (cdk_ctx_t hd, cdk_pkt_seckey_t sk)
322{
323 char *pw, *p;
324 cdk_error_t rc;
325
326 if (!sk->is_protected)
327 return 0;
328
329 p = passphrase_prompt (sk);
330 pw = _cdk_passphrase_get (hd, p);
331 cdk_free (p);
332 if (!pw)
333 return CDK_No_Passphrase;
334
335 rc = cdk_sk_unprotect (sk, pw);
336
337 wipemem (pw, strlen (pw));
338 cdk_free (pw);
339 return rc;
340}
341
342
343/**
344 * cdk_dek_extract:
345 * @ret_dek: the raw DEK object
346 * @hd: the session handle
347 * @enc: the public key encrypted packet
348 * @sk: the secret key.
349 *
350 * Try to extract the DEK from the public key encrypted packet.
351 **/
352cdk_error_t
353cdk_dek_extract (cdk_dek_t * ret_dek, cdk_ctx_t hd,
354 cdk_pkt_pubkey_enc_t enc, cdk_pkt_seckey_t sk)
355{
356 gcry_mpi_t skey = NULL;
357 cdk_dek_t dek;
358 cdk_error_t rc;
359
360 if (!enc || !sk || !ret_dek)
361 return CDK_Inv_Value;
362
363 /* FIXME: it is not very elegant that we need the session handle here. */
364 if (sk->is_protected)
365 {
366 rc = _cdk_sk_unprotect_auto (hd, sk);
367 if (rc)
368 return rc;
369 }
370
371 rc = cdk_pk_decrypt (sk, enc, &skey);
372 if (rc)
373 return rc;
374
375 rc = cdk_dek_decode_pkcs1 (&dek, skey);
376 gcry_mpi_release (skey);
377 if (rc)
378 {
379 cdk_dek_free (dek);
380 dek = NULL;
381 }
382 *ret_dek = dek;
383 return rc;
384}
385
386
387/**
388 * cdk_dek_new:
389 * @r_dek: the new DEK object
390 *
391 * Create a new DEK object.
392 **/
393cdk_error_t
394cdk_dek_new (cdk_dek_t * r_dek)
395{
396 cdk_dek_t dek;
397
398 if (!r_dek)
399 return CDK_Inv_Value;
400 *r_dek = NULL;
401 dek = cdk_salloc (sizeof *dek, 1);
402 if (!dek)
403 return CDK_Out_Of_Core;
404 *r_dek = dek;
405 return 0;
406}
407
408
409/**
410 * cdk_dek_set_cipher:
411 * @dek: the DEK object
412 * @algo: the cipher algorithm to use
413 *
414 * Set the cipher for the given DEK object.
415 **/
416cdk_error_t
417cdk_dek_set_cipher (cdk_dek_t dek, int algo)
418{
419 if (!dek)
420 return CDK_Inv_Value;
421
422 if (!algo)
423 algo = GCRY_CIPHER_AES128;
424 if (gcry_cipher_test_algo (algo))
425 return CDK_Inv_Algo;
426 dek->algo = algo;
427 dek->keylen = gcry_cipher_get_algo_keylen (dek->algo);
428 return 0;
429}
430
431cdk_error_t
432cdk_dek_get_cipher (cdk_dek_t dek, int *r_algo)
433{
434 if (!dek || !r_algo)
435 return CDK_Inv_Value;
436
437
438 *r_algo = dek->algo;
439 return 0;
440}
441
442
443/**
444 * cdk_dek_set_key:
445 * @dek: the DEK object
446 * @key: the random session key
447 * @keylen: the length of the session key.
448 *
449 * Set the random session key for the given DEK object.
450 * If @key and @keylen is NULL (0) a random key will be generated.
451 * In any case, cdk_dek_set_cipher must be called first.
452 **/
453cdk_error_t
454cdk_dek_set_key (cdk_dek_t dek, const byte * key, size_t keylen)
455{
456 gcry_cipher_hd_t hd;
457 size_t i;
458
459 if (!dek)
460 return CDK_Inv_Value;
461
462 /* The given key must be compatible with the symmetric
463 cipher algorithm set before. */
464 if (keylen > 0 && keylen != dek->keylen)
465 return CDK_Inv_Mode;
466
467 if (!key && !keylen)
468 {
469 gcry_error_t err;
470
471 /* Used to generate a random session key. The extra code is used
472 to detect weak keys, if they are possible at all. */
473 err = gcry_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB,
474 GCRY_CIPHER_ENABLE_SYNC);
475 if (err)
476 return map_gcry_error (err);
477 gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM);
478 for (i = 0; i < 8; i++)
479 {
480 if (!gcry_cipher_setkey (hd, dek->key, dek->keylen))
481 {
482 gcry_cipher_close (hd);
483 return 0;
484 }
485 gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM);
486 }
487 gcry_cipher_close (hd);
488 return CDK_Weak_Key;
489 }
490
491 memcpy (dek->key, key, dek->keylen);
492 return 0;
493}
494
495
496/**
497 * cdk_dek_set_mdc_flag:
498 * @dek: the DEK object
499 * @val: value to enable or disable the use
500 *
501 * Enable or disable the MDC flag for the given DEK object.
502 **/
503void
504cdk_dek_set_mdc_flag (cdk_dek_t dek, int val)
505{
506 if (dek)
507 dek->use_mdc = val;
508}
509
510
511int
512cdk_dek_get_mdc_flag (cdk_dek_t dek)
513{
514 if (!dek)
515 return 0;
516 return dek->use_mdc;
517}
518
519
520/**
521 * cdk_dek_free:
522 * @dek: the DEK object
523 *
524 * Release the DEK object.
525 **/
526void
527cdk_dek_free (cdk_dek_t dek)
528{
529 if (!dek)
530 return;
531
532 /* Make sure sentensive data is overwritten. */
533 wipemem (dek->key, sizeof (dek->key));
534 cdk_free (dek);
535}
536
537
538/* Hash the passphrase to produce the a DEK.
539 If create is set, a random salt will be generated. */
540static cdk_error_t
541hash_passphrase (cdk_dek_t dek, const char *pw, cdk_s2k_t s2k, int create)
542{
543 gcry_md_hd_t md;
544 byte zero[1] = { 0x00 };
545 int pass, i;
546 int used = 0, pwlen;
547 gcry_error_t err;
548
549 if (!dek || !pw || !s2k)
550 return CDK_Inv_Value;
551
552 if (!s2k->hash_algo)
553 s2k->hash_algo = GCRY_MD_SHA1;
554 pwlen = strlen (pw);
555
556 dek->keylen = gcry_cipher_get_algo_keylen (dek->algo);
557 err = gcry_md_open (&md, s2k->hash_algo, 0);
558 if (err)
559 return map_gcry_error (err);
560
561 for (pass = 0; used < dek->keylen; pass++)
562 {
563 if (pass)
564 {
565 gcry_md_reset (md);
566 for (i = 0; i < pass; i++) /* preset the hash context */
567 gcry_md_write (md, zero, 1);
568 }
569 if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
570 {
571 int len2 = pwlen + 8;
572 u32 count = len2;
573 if (create && !pass)
574 {
575 gcry_randomize (s2k->salt, 8, GCRY_STRONG_RANDOM);
576 if (s2k->mode == 3)
577 s2k->count = 96; /* 65536 iterations */
578 }
579 if (s2k->mode == 3)
580 {
581 count = (16ul + (s2k->count & 15)) << ((s2k->count >> 4) + 6);
582 if (count < len2)
583 count = len2;
584 }
585 /* a little bit complicated because we need a ulong for count */
586 while (count > len2)
587 { /* maybe iterated+salted */
588 gcry_md_write (md, s2k->salt, 8);
589 gcry_md_write (md, pw, pwlen);
590 count -= len2;
591 }
592 if (count < 8)
593 gcry_md_write (md, s2k->salt, count);
594 else
595 {
596 gcry_md_write (md, s2k->salt, 8);
597 count -= 8;
598 gcry_md_write (md, pw, count);
599 }
600 }
601 else
602 gcry_md_write (md, pw, pwlen);
603 gcry_md_final (md);
604 i = gcry_md_get_algo_dlen (s2k->hash_algo);
605 if (i > dek->keylen - used)
606 i = dek->keylen - used;
607 memcpy (dek->key + used, gcry_md_read (md, s2k->hash_algo), i);
608 used += i;
609 }
610 gcry_md_close (md);
611 return 0;
612}
613
614
615/**
616 * cdk_dek_from_passphrase:
617 * @ret_dek: the new DEK.
618 * @cipher_algo: symmetric key algorithm to use
619 * @s2k: the S2K to use
620 * @rndsalt: 1=create random salt
621 * @pw: the passphrase.
622 *
623 * Transform a passphrase into a DEK object.
624 */
625cdk_error_t
626cdk_dek_from_passphrase (cdk_dek_t * ret_dek, int cipher_algo, cdk_s2k_t s2k,
627 int rndsalt, const char *pw)
628{
629 cdk_dek_t dek;
630 cdk_error_t rc;
631
632 if (!ret_dek)
633 return CDK_Inv_Value;
634
635 *ret_dek = NULL;
636 rc = cdk_dek_new (&dek);
637 if (rc)
638 return rc;
639 rc = cdk_dek_set_cipher (dek, cipher_algo);
640 if (!rc)
641 rc = hash_passphrase (dek, pw, s2k, rndsalt);
642 if (rc)
643 {
644 cdk_dek_free (dek);
645 return rc;
646 }
647
648 *ret_dek = dek;
649 return 0;
650}
651
652
653/**
654 * cdk_s2k_new:
655 * @ret_s2k: output for the new S2K object
656 * @mode: the S2K mode (simple, salted, iter+salted)
657 * @digest_algo: the hash algorithm
658 * @salt: random salt
659 *
660 * Create a new S2K object with the given parameter.
661 * The @salt parameter must be always 8 octets.
662 **/
663cdk_error_t
664cdk_s2k_new (cdk_s2k_t * ret_s2k, int mode, int digest_algo,
665 const byte * salt)
666{
667 cdk_s2k_t s2k;
668
669 if (!ret_s2k)
670 return CDK_Inv_Value;
671
672 if (mode != 0x00 && mode != 0x01 && mode != 0x03)
673 return CDK_Inv_Mode;
674
675 if (gcry_md_test_algo (digest_algo))
676 return CDK_Inv_Algo;
677
678 s2k = cdk_calloc (1, sizeof *s2k);
679 if (!s2k)
680 return CDK_Out_Of_Core;
681 s2k->mode = mode;
682 s2k->hash_algo = digest_algo;
683 if (salt)
684 memcpy (s2k->salt, salt, 8);
685 *ret_s2k = s2k;
686 return 0;
687}
688
689
690/**
691 * cdk_s2k_free:
692 * @s2k: the S2K object
693 *
694 * Release the given S2K object.
695 **/
696void
697cdk_s2k_free (cdk_s2k_t s2k)
698{
699 cdk_free (s2k);
700}
701
702
703/* Make a copy of the source s2k into R_DST. */
704cdk_error_t
705_cdk_s2k_copy (cdk_s2k_t * r_dst, cdk_s2k_t src)
706{
707 cdk_s2k_t dst;
708 cdk_error_t err;
709
710 err = cdk_s2k_new (&dst, src->mode, src->hash_algo, src->salt);
711 if (err)
712 return err;
713 dst->count = src->count;
714 *r_dst = dst;
715
716 return 0;
717}
diff --git a/src/daemon/https/opencdk/sig-check.c b/src/daemon/https/opencdk/sig-check.c
new file mode 100644
index 00000000..f1ad5b2f
--- /dev/null
+++ b/src/daemon/https/opencdk/sig-check.c
@@ -0,0 +1,489 @@
1/* sig-check.c - Check signatures
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 * Copyright (C) 1998-2002 Free Software Foundation, Inc.
4 *
5 * This file is part of OpenCDK.
6 *
7 * OpenCDK 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.
11 *
12 * OpenCDK 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.
16 */
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdio.h>
21#include <time.h>
22#include <gcrypt.h>
23#include <assert.h>
24
25#include "opencdk.h"
26#include "main.h"
27#include "packet.h"
28
29
30/* Hash all multi precision integers of the key PK with the given
31 message digest context MD. */
32static int
33hash_mpibuf (cdk_pubkey_t pk, gcry_md_hd_t md, int usefpr)
34{
35 byte buf[MAX_MPI_BYTES]; /* FIXME: do not use hardcoded length. */
36 size_t nbytes;
37 size_t i, npkey;
38 gcry_error_t err;
39
40 /* We have to differ between two modes for v3 keys. To form the
41 fingerprint, we hash the MPI values without the length prefix.
42 But if we calculate the hash for verifying/signing we use all data. */
43 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
44 for (i = 0; i < npkey; i++)
45 {
46 err = gcry_mpi_print (GCRYMPI_FMT_PGP, buf, MAX_MPI_BYTES,
47 &nbytes, pk->mpi[i]);
48 if (err)
49 return map_gcry_error (err);
50 if (!usefpr || pk->version == 4)
51 gcry_md_write (md, buf, nbytes);
52 else /* without the prefix. */
53 gcry_md_write (md, buf + 2, nbytes - 2);
54 }
55 return 0;
56}
57
58
59/* Hash an entire public key PK with the given message digest context
60 MD. The @usefpr param is only valid for version 3 keys because of
61 the different way to calculate the fingerprint. */
62cdk_error_t
63_cdk_hash_pubkey (cdk_pubkey_t pk, gcry_md_hd_t md, int usefpr)
64{
65 byte buf[12];
66 size_t i, n, npkey;
67
68 if (!pk || !md)
69 return CDK_Inv_Value;
70
71 if (usefpr && pk->version < 4 && is_RSA (pk->pubkey_algo))
72 return hash_mpibuf (pk, md, 1);
73
74 /* The version 4 public key packet does not have the 2 octets for
75 the expiration date. */
76 n = pk->version < 4 ? 8 : 6;
77 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
78 for (i = 0; i < npkey; i++)
79 n = n + (gcry_mpi_get_nbits (pk->mpi[i]) + 7) / 8 + 2;
80
81 i = 0;
82 buf[i++] = 0x99;
83 buf[i++] = n >> 8;
84 buf[i++] = n >> 0;
85 buf[i++] = pk->version;
86 buf[i++] = pk->timestamp >> 24;
87 buf[i++] = pk->timestamp >> 16;
88 buf[i++] = pk->timestamp >> 8;
89 buf[i++] = pk->timestamp >> 0;
90
91 if (pk->version < 4)
92 {
93 u16 a = 0;
94
95 /* Convert the expiration date into days. */
96 if (pk->expiredate)
97 a = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
98 buf[i++] = a >> 8;
99 buf[i++] = a;
100 }
101 buf[i++] = pk->pubkey_algo;
102 gcry_md_write (md, buf, i);
103 return hash_mpibuf (pk, md, 0);
104}
105
106
107/* Hash the user ID @uid with the given message digest @md.
108 Use openpgp mode if @is_v4 is 1. */
109cdk_error_t
110_cdk_hash_userid (cdk_pkt_userid_t uid, int is_v4, gcry_md_hd_t md)
111{
112 const byte *data;
113 byte buf[5];
114 u32 dlen;
115
116 if (!uid || !md)
117 return CDK_Inv_Value;
118
119 if (!is_v4)
120 {
121 gcry_md_write (md, (byte *) uid->name, uid->len);
122 return 0;
123 }
124
125 dlen = uid->attrib_img ? uid->attrib_len : uid->len;
126 data = uid->attrib_img ? uid->attrib_img : (byte *) uid->name;
127 buf[0] = uid->attrib_img ? 0xD1 : 0xB4;
128 buf[1] = dlen >> 24;
129 buf[2] = dlen >> 16;
130 buf[3] = dlen >> 8;
131 buf[4] = dlen >> 0;
132 gcry_md_write (md, buf, 5);
133 gcry_md_write (md, data, dlen);
134 return 0;
135}
136
137
138/* Hash all parts of the signature which are needed to derive
139 the correct message digest to verify the sig. */
140cdk_error_t
141_cdk_hash_sig_data (cdk_pkt_signature_t sig, gcry_md_hd_t md)
142{
143 byte buf[4];
144
145 if (!sig || !md)
146 return CDK_Inv_Value;
147
148 if (sig->version == 4)
149 gcry_md_putc (md, sig->version);
150 gcry_md_putc (md, sig->sig_class);
151 if (sig->version < 4)
152 {
153 buf[0] = sig->timestamp >> 24;
154 buf[1] = sig->timestamp >> 16;
155 buf[2] = sig->timestamp >> 8;
156 buf[3] = sig->timestamp >> 0;
157 gcry_md_write (md, buf, 4);
158 }
159 else
160 {
161 size_t n;
162
163 gcry_md_putc (md, sig->pubkey_algo);
164 gcry_md_putc (md, sig->digest_algo);
165 if (sig->hashed != NULL)
166 {
167 byte *p = _cdk_subpkt_get_array (sig->hashed, 0, &n);
168 assert (p != NULL);
169 buf[0] = n >> 8;
170 buf[1] = n >> 0;
171 gcry_md_write (md, buf, 2);
172 gcry_md_write (md, p, n);
173 cdk_free (p);
174 sig->hashed_size = n;
175 n = sig->hashed_size + 6;
176 }
177 else
178 {
179 gcry_md_putc (md, 0x00);
180 gcry_md_putc (md, 0x00);
181 n = 6;
182 }
183 gcry_md_putc (md, sig->version);
184 gcry_md_putc (md, 0xFF);
185 buf[0] = n >> 24;
186 buf[1] = n >> 16;
187 buf[2] = n >> 8;
188 buf[3] = n >> 0;
189 gcry_md_write (md, buf, 4);
190 }
191 return 0;
192}
193
194
195/* Cache the signature result and store it inside the sig. */
196static void
197cache_sig_result (cdk_pkt_signature_t sig, int res)
198{
199 sig->flags.checked = 0;
200 sig->flags.valid = 0;
201 if (res == 0)
202 {
203 sig->flags.checked = 1;
204 sig->flags.valid = 1;
205 }
206 else if (res == CDK_Bad_Sig)
207 {
208 sig->flags.checked = 1;
209 sig->flags.valid = 0;
210 }
211}
212
213
214/* Check the given signature @sig with the public key @pk.
215 Use the digest handle @digest. */
216cdk_error_t
217_cdk_sig_check (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
218 gcry_md_hd_t digest, int *r_expired)
219{
220 cdk_error_t rc;
221 byte md[MAX_DIGEST_LEN];
222 time_t cur_time = (u32) time (NULL);
223
224 if (!pk || !sig || !digest)
225 return CDK_Inv_Value;
226
227 if (sig->flags.checked)
228 return sig->flags.valid ? 0 : CDK_Bad_Sig;
229 if (!KEY_CAN_SIGN (pk->pubkey_algo))
230 return CDK_Inv_Algo;
231 if (pk->timestamp > sig->timestamp || pk->timestamp > cur_time)
232 return CDK_Time_Conflict;
233
234 if (r_expired && pk->expiredate
235 && (pk->expiredate + pk->timestamp) > cur_time)
236 *r_expired = 1;
237
238 _cdk_hash_sig_data (sig, digest);
239 gcry_md_final (digest);
240 memcpy (md, gcry_md_read (digest, sig->digest_algo),
241 gcry_md_get_algo_dlen (sig->digest_algo));
242
243 if (md[0] != sig->digest_start[0] || md[1] != sig->digest_start[1])
244 return CDK_Chksum_Error;
245
246 rc = cdk_pk_verify (pk, sig, md);
247 cache_sig_result (sig, rc);
248 return rc;
249}
250
251
252/* Check the given key signature.
253 @knode is the key node and @snode the signature node. */
254cdk_error_t
255_cdk_pk_check_sig (cdk_keydb_hd_t keydb,
256 cdk_kbnode_t knode, cdk_kbnode_t snode, int *is_selfsig)
257{
258 gcry_md_hd_t md;
259 gcry_error_t err;
260 cdk_pubkey_t pk;
261 cdk_pkt_signature_t sig;
262 cdk_kbnode_t node;
263 cdk_error_t rc = 0;
264 int is_expired;
265
266 if (!knode || !snode)
267 return CDK_Inv_Value;
268
269 if (is_selfsig)
270 *is_selfsig = 0;
271 if (knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY ||
272 snode->pkt->pkttype != CDK_PKT_SIGNATURE)
273 return CDK_Inv_Value;
274 pk = knode->pkt->pkt.public_key;
275 sig = snode->pkt->pkt.signature;
276
277 err = gcry_md_open (&md, sig->digest_algo, 0);
278 if (err)
279 return map_gcry_error (err);
280
281 is_expired = 0;
282 if (sig->sig_class == 0x20)
283 { /* key revocation */
284 cdk_kbnode_hash (knode, md, 0, 0, 0);
285 rc = _cdk_sig_check (pk, sig, md, &is_expired);
286 }
287 else if (sig->sig_class == 0x28)
288 { /* subkey revocation */
289 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
290 if (!node)
291 { /* no subkey for subkey revocation packet */
292 rc = CDK_Error_No_Key;
293 goto fail;
294 }
295 cdk_kbnode_hash (knode, md, 0, 0, 0);
296 cdk_kbnode_hash (node, md, 0, 0, 0);
297 rc = _cdk_sig_check (pk, sig, md, &is_expired);
298 }
299 else if (sig->sig_class == 0x18 || sig->sig_class == 0x19)
300 { /* primary/secondary key binding */
301 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
302 if (!node)
303 { /* no subkey for subkey binding packet */
304 rc = CDK_Error_No_Key;
305 goto fail;
306 }
307 cdk_kbnode_hash (knode, md, 0, 0, 0);
308 cdk_kbnode_hash (node, md, 0, 0, 0);
309 rc = _cdk_sig_check (pk, sig, md, &is_expired);
310 }
311 else if (sig->sig_class == 0x1F)
312 { /* direct key signature */
313 cdk_kbnode_hash (knode, md, 0, 0, 0);
314 rc = _cdk_sig_check (pk, sig, md, &is_expired);
315 }
316 else
317 { /* all other classes */
318 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_USER_ID);
319 if (!node)
320 { /* no user ID for key signature packet */
321 rc = CDK_Error_No_Key;
322 goto fail;
323 }
324 cdk_kbnode_hash (knode, md, 0, 0, 0);
325 cdk_kbnode_hash (node, md, sig->version == 4, 0, 0);
326 if (pk->keyid[0] == sig->keyid[0] && pk->keyid[1] == sig->keyid[1])
327 {
328 rc = _cdk_sig_check (pk, sig, md, &is_expired);
329 if (is_selfsig)
330 *is_selfsig = 1;
331 }
332 else if (keydb != NULL)
333 {
334 cdk_pubkey_t sig_pk;
335
336 rc = cdk_keydb_get_pk (keydb, sig->keyid, &sig_pk);
337 if (!rc)
338 rc = _cdk_sig_check (sig_pk, sig, md, &is_expired);
339 cdk_pk_release (sig_pk);
340 }
341 }
342fail:
343 gcry_md_close (md);
344 return rc;
345}
346
347
348/**
349 * cdk_pk_check_sigs:
350 * @key: the public key
351 * @hd: an optinal key database handle
352 * @r_status: variable to store the status of the key
353 *
354 * Check all signatures. When no key is available for checking, the
355 * sigstat is marked as 'NOKEY'. The @r_status contains the key flags
356 * which are or-ed or zero when there are no flags.
357 **/
358cdk_error_t
359cdk_pk_check_sigs (cdk_kbnode_t key, cdk_keydb_hd_t keydb, int *r_status)
360{
361 cdk_pkt_signature_t sig;
362 cdk_kbnode_t node;
363 cdk_error_t rc;
364 u32 keyid;
365 int key_status, is_selfsig = 0;
366 int no_signer, n_sigs = 0;
367
368 if (!key || !r_status)
369 return CDK_Inv_Value;
370
371 *r_status = 0;
372 node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
373 if (!node)
374 return CDK_Error_No_Key;
375
376 key_status = 0;
377 /* Continue with the signature check but adjust the
378 key status flags accordingly. */
379 if (node->pkt->pkt.public_key->is_revoked)
380 key_status |= CDK_KEY_REVOKED;
381 if (node->pkt->pkt.public_key->has_expired)
382 key_status |= CDK_KEY_EXPIRED;
383
384 rc = 0;
385 no_signer = 0;
386 keyid = cdk_pk_get_keyid (node->pkt->pkt.public_key, NULL);
387 for (node = key; node; node = node->next)
388 {
389 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
390 continue;
391 sig = node->pkt->pkt.signature;
392 rc = _cdk_pk_check_sig (keydb, key, node, &is_selfsig);
393 if (IS_UID_SIG (sig))
394 {
395 if (is_selfsig == 0)
396 n_sigs++;
397 }
398 if (rc && IS_UID_SIG (sig) && rc == CDK_Error_No_Key)
399 {
400 /* We do not consider it a problem when the signing key
401 is not avaiable. We just mark the signature accordingly
402 and contine. */
403 sig->flags.missing_key = 1;
404 no_signer++;
405 }
406 else if (rc && rc != CDK_Error_No_Key)
407 {
408 /* It might be possible that a single signature has been
409 corrupted, thus we do not consider it a problem when
410 one ore more signatures are bad. But at least the self
411 signature has to be valid. */
412 if (is_selfsig)
413 {
414 key_status |= CDK_KEY_INVALID;
415 break;
416 }
417 }
418 _cdk_log_debug ("signature %s: signer %08lX keyid %08lX\n",
419 rc == CDK_Bad_Sig ? "BAD" : "good", sig->keyid[1],
420 keyid);
421 }
422
423 if (n_sigs == no_signer)
424 key_status |= CDK_KEY_NOSIGNER;
425 *r_status = key_status;
426 if (rc == CDK_Error_No_Key)
427 rc = 0;
428 return rc;
429}
430
431
432/**
433 * cdk_pk_check_self_sig:
434 * @key: the key node
435 * @r_status: output the status of the key.
436 *
437 * A convenient function to make sure the key is valid.
438 * Valid means the self signature is ok.
439 **/
440cdk_error_t
441cdk_pk_check_self_sig (cdk_kbnode_t key, int *r_status)
442{
443 cdk_pkt_signature_t sig;
444 cdk_kbnode_t node;
445 cdk_error_t rc;
446 u32 keyid[2], sigid[2];
447 int is_selfsig, sig_ok;
448
449 if (!key || !r_status)
450 return CDK_Inv_Value;
451
452 node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
453 if (!node)
454 return CDK_Error_No_Key;
455 /* FIXME: we should set expire/revoke here also but callers
456 expect CDK_KEY_VALID=0 if the key is okay. */
457 cdk_pk_get_keyid (key->pkt->pkt.public_key, keyid);
458 sig_ok = 0;
459 for (node = key; node; node = node->next)
460 {
461 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
462 continue;
463 sig = node->pkt->pkt.signature;
464 if (!IS_UID_SIG (sig))
465 continue;
466 cdk_sig_get_keyid (sig, sigid);
467 if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
468 continue;
469 /* FIXME: Now we check all self signatures. */
470 rc = _cdk_pk_check_sig (NULL, key, node, &is_selfsig);
471 if (rc)
472 {
473 *r_status = CDK_KEY_INVALID;
474 return rc;
475 }
476 else /* For each valid self sig we increase this counter. */
477 sig_ok++;
478 }
479
480 /* A key without a self signature is not valid. */
481 if (!sig_ok)
482 {
483 *r_status = CDK_KEY_INVALID;
484 return CDK_General_Error;
485 }
486 /* No flags indicate a valid key. */
487 *r_status = CDK_KEY_VALID;
488 return 0;
489}
diff --git a/src/daemon/https/opencdk/stream.c b/src/daemon/https/opencdk/stream.c
new file mode 100644
index 00000000..8389401f
--- /dev/null
+++ b/src/daemon/https/opencdk/stream.c
@@ -0,0 +1,1446 @@
1/* stream.c - The stream implementation
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19#include <assert.h>
20#include <stdio.h>
21#include <sys/stat.h>
22#include <string.h>
23#include <stdlib.h>
24#include <errno.h>
25#ifdef HAVE_UNISTD_H
26# include <unistd.h>
27#endif
28
29#include "opencdk.h"
30#include "main.h"
31#include "filters.h"
32#include "stream.h"
33#include "types.h"
34
35/* This is the maximal amount of bytes we map. */
36#define MAX_MAP_SIZE 16777216
37
38static int stream_flush (cdk_stream_t s);
39static int stream_filter_write (cdk_stream_t s);
40static int stream_cache_flush (cdk_stream_t s, FILE * fp);
41
42/* Customized tmpfile() version from misc.c */
43FILE *my_tmpfile (void);
44
45
46/* FIXME: The read/write/putc/getc function cannot directly
47 return an error code. It is stored in an error variable
48 inside the string. Right now there is no code to
49 return the error code or to reset it. */
50
51/**
52 * cdk_stream_open:
53 * @file: The file to open
54 * @ret_s: The new STREAM object
55 *
56 * Create a new stream based on an existing file. The stream is
57 * opened in read-only mode.
58 **/
59cdk_error_t
60cdk_stream_open (const char *file, cdk_stream_t * ret_s)
61{
62 return _cdk_stream_open_mode (file, "rb", ret_s);
63}
64
65
66/* Helper function to allow to open a stream in different modes. */
67cdk_error_t
68_cdk_stream_open_mode (const char *file, const char *mode,
69 cdk_stream_t * ret_s)
70{
71 cdk_stream_t s;
72
73 if (!file || !ret_s)
74 return CDK_Inv_Value;
75
76 _cdk_log_debug ("open stream `%s'\n", file);
77 *ret_s = NULL;
78 s = cdk_calloc (1, sizeof *s);
79 if (!s)
80 return CDK_Out_Of_Core;
81 s->fname = cdk_strdup (file);
82 if (!s->fname)
83 {
84 cdk_free (s);
85 return CDK_Out_Of_Core;
86 }
87 s->fp = fopen (file, mode);
88 if (!s->fp)
89 {
90 cdk_free (s->fname);
91 cdk_free (s);
92 return CDK_File_Error;
93 }
94 _cdk_log_debug ("open stream fd=%d\n", fileno (s->fp));
95 s->flags.write = 0;
96 *ret_s = s;
97 return 0;
98}
99
100
101/**
102 * cdk_stream_new_from_cbs:
103 * @cbs: the callback context with all user callback functions
104 * @opa: opaque handle which is passed to all callbacks.
105 * @ret_s: the allocated stream
106 *
107 * This function creates a stream which uses user callback
108 * for the core operations (open, close, read, write, seek).
109 */
110cdk_error_t
111cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa,
112 cdk_stream_t * ret_s)
113{
114 cdk_stream_t s;
115
116 if (!cbs || !opa || !ret_s)
117 return CDK_Inv_Value;
118
119 *ret_s = NULL;
120 s = cdk_calloc (1, sizeof *s);
121 if (!s)
122 return CDK_Out_Of_Core;
123
124 s->cbs.read = cbs->read;
125 s->cbs.write = cbs->write;
126 s->cbs.seek = cbs->seek;
127 s->cbs.release = cbs->release;
128 s->cbs.open = cbs->open;
129 s->cbs_hd = opa;
130 *ret_s = s;
131
132 /* If there is a user callback for open, we need to call it
133 here because read/write expects an open stream. */
134 if (s->cbs.open)
135 return s->cbs.open (s->cbs_hd);
136 return 0;
137}
138
139
140/**
141 * cdk_stream_new: Create a new stream into into the given file.
142 * @file: The name of the new file
143 * @ret_s: The new STREAM object
144 **/
145cdk_error_t
146cdk_stream_new (const char *file, cdk_stream_t * ret_s)
147{
148 cdk_stream_t s;
149
150 if (!ret_s)
151 return CDK_Inv_Value;
152
153 _cdk_log_debug ("new stream `%s'\n", file ? file : "[temp]");
154 *ret_s = NULL;
155 s = cdk_calloc (1, sizeof *s);
156 if (!s)
157 return CDK_Out_Of_Core;
158 s->flags.write = 1;
159 if (!file)
160 s->flags.temp = 1;
161 else
162 {
163 s->fname = cdk_strdup (file);
164 if (!s->fname)
165 {
166 cdk_free (s);
167 return CDK_Out_Of_Core;
168 }
169 }
170 s->fp = my_tmpfile ();
171 if (!s->fp)
172 {
173 cdk_free (s->fname);
174 cdk_free (s);
175 return CDK_File_Error;
176 }
177 _cdk_log_debug ("new stream fd=%d\n", fileno (s->fp));
178 *ret_s = s;
179 return 0;
180}
181
182
183/**
184 * cdk_stream_create: create a new stream.
185 * @file: the filename
186 * @ret_s: the object
187 *
188 * The difference to cdk_stream_new is, that no filtering can be used with
189 * this kind of stream and everything is written directly to the stream.
190 **/
191cdk_error_t
192cdk_stream_create (const char *file, cdk_stream_t * ret_s)
193{
194 cdk_stream_t s;
195
196 if (!file || !ret_s)
197 return CDK_Inv_Value;
198
199 _cdk_log_debug ("create stream `%s'\n", file);
200 *ret_s = NULL;
201 s = cdk_calloc (1, sizeof *s);
202 if (!s)
203 return CDK_Out_Of_Core;
204 s->flags.write = 1;
205 s->flags.filtrated = 1;
206 s->fname = cdk_strdup (file);
207 if (!s->fname)
208 {
209 cdk_free (s);
210 return CDK_Out_Of_Core;
211 }
212 s->fp = fopen (file, "w+b");
213 if (!s->fp)
214 {
215 cdk_free (s->fname);
216 cdk_free (s);
217 return CDK_File_Error;
218 }
219 _cdk_log_debug ("stream create fd=%d\n", fileno (s->fp));
220 *ret_s = s;
221 return 0;
222}
223
224
225/**
226 * cdk_stream_tmp_new:
227 * @r_out: the new temp stream.
228 *
229 * Allocate a new tempory stream which is not associated with a file.
230 */
231cdk_error_t
232cdk_stream_tmp_new (cdk_stream_t * r_out)
233{
234 return cdk_stream_new (NULL, r_out);
235}
236
237
238
239/**
240 * cdk_stream_tmp_from_mem:
241 * @buf: the buffer which shall be written to the temp stream.
242 * @buflen: how large the buffer is
243 * @r_out: the new stream with the given contents.
244 *
245 * Create a new tempory stream with the given contests.
246 */
247cdk_error_t
248cdk_stream_tmp_from_mem (const void *buf, size_t buflen, cdk_stream_t * r_out)
249{
250 cdk_stream_t s;
251 cdk_error_t rc;
252 int nwritten;
253
254 *r_out = NULL;
255 rc = cdk_stream_tmp_new (&s);
256 if (rc)
257 return rc;
258
259 nwritten = cdk_stream_write (s, buf, buflen);
260 if (nwritten == EOF)
261 {
262 cdk_stream_close (s);
263 return s->error;
264 }
265 cdk_stream_seek (s, 0);
266 *r_out = s;
267 return 0;
268}
269
270
271cdk_error_t
272_cdk_stream_fpopen (FILE * fp, unsigned write_mode, cdk_stream_t * ret_out)
273{
274 cdk_stream_t s;
275
276 *ret_out = NULL;
277 s = cdk_calloc (1, sizeof *s);
278 if (!s)
279 return CDK_Out_Of_Core;
280
281 _cdk_log_debug ("stream ref fd=%d\n", fileno (fp));
282 s->fp = fp;
283 s->fp_ref = 1;
284 s->flags.filtrated = 1;
285 s->flags.write = write_mode;
286
287 *ret_out = s;
288 return 0;
289}
290
291
292cdk_error_t
293_cdk_stream_append (const char *file, cdk_stream_t * ret_s)
294{
295 cdk_stream_t s;
296 cdk_error_t rc;
297
298 if (!ret_s)
299 return CDK_Inv_Value;
300 *ret_s = NULL;
301
302 rc = _cdk_stream_open_mode (file, "a+b", &s);
303 if (rc)
304 return rc;
305
306 /* In the append mode, we need to write to the flag. */
307 s->flags.write = 1;
308 *ret_s = s;
309 return 0;
310}
311
312
313/**
314 * cdk_stream_is_compressed:
315 * @s: the stream
316 *
317 * Return 0 if the stream is uncompressed, otherwise the
318 * compression algorithm.
319 */
320int
321cdk_stream_is_compressed (cdk_stream_t s)
322{
323 if (!s)
324 return 0;
325 return s->flags.compressed;
326}
327
328void
329_cdk_stream_set_compress_algo (cdk_stream_t s, int algo)
330{
331 if (!s)
332 return;
333 s->flags.compressed = algo;
334}
335
336
337cdk_error_t
338cdk_stream_flush (cdk_stream_t s)
339{
340 cdk_error_t rc;
341
342 if (!s)
343 return CDK_Inv_Value;
344
345 /* The user callback does not support flush */
346 if (s->cbs_hd)
347 return 0;
348
349 /* For read-only streams, no flush is needed. */
350 if (!s->flags.write)
351 return 0;
352
353 if (!s->flags.filtrated)
354 {
355 if (!cdk_stream_get_length (s))
356 return 0;
357 rc = cdk_stream_seek (s, 0);
358 if (!rc)
359 rc = stream_flush (s);
360 if (!rc)
361 rc = stream_filter_write (s);
362 s->flags.filtrated = 1;
363 if (rc)
364 {
365 s->error = rc;
366 return rc;
367 }
368 }
369 return 0;
370}
371
372
373void
374cdk_stream_tmp_set_mode (cdk_stream_t s, int val)
375{
376 if (s && s->flags.temp)
377 s->fmode = val;
378}
379
380
381/**
382 * cdk_stream_close: Close a stream and flush all buffers.
383 * @s: The STREAM object.
384 *
385 * This function work different for read or write streams. When the
386 * stream is for reading, the filtering is already done and we can
387 * simply close the file and all buffers.
388 * But for the case it's a write stream, we need to apply all registered
389 * filters now. The file is closed in the filter function and not here.
390 **/
391cdk_error_t
392cdk_stream_close (cdk_stream_t s)
393{
394 struct stream_filter_s *f, *f2;
395 cdk_error_t rc;
396
397 if (!s)
398 return CDK_Inv_Value;
399
400 _cdk_log_debug ("close stream ref=%d `%s'\n",
401 s->fp_ref, s->fname ? s->fname : "[temp]");
402
403 /* In the user callback mode, we call the release cb if possible
404 and just free the stream. */
405 if (s->cbs_hd)
406 {
407 if (s->cbs.release)
408 rc = s->cbs.release (s->cbs_hd);
409 else
410 rc = 0;
411 cdk_free (s);
412 return rc;
413 }
414
415
416 rc = 0;
417 if (!s->flags.filtrated && !s->error)
418 rc = cdk_stream_flush (s);
419 if (!s->fp_ref && (s->fname || s->flags.temp))
420 {
421 int err;
422
423 _cdk_log_debug ("close stream fd=%d\n", fileno (s->fp));
424 err = fclose (s->fp);
425 s->fp = NULL;
426 if (err)
427 rc = CDK_File_Error;
428 }
429
430 /* Iterate over the filter list and use the cleanup flag to
431 free the allocated internal structures. */
432 f = s->filters;
433 while (f)
434 {
435 f2 = f->next;
436 if (f->fnct)
437 f->fnct (f->opaque, STREAMCTL_FREE, NULL, NULL);
438 cdk_free (f);
439 f = f2;
440 }
441
442 if (s->fname)
443 {
444 cdk_free (s->fname);
445 s->fname = NULL;
446 }
447
448 cdk_free (s->cache.buf);
449 s->cache.alloced = 0;
450
451 cdk_free (s);
452 return rc;
453}
454
455
456/**
457 * cdk_stream_eof: Return if the associated file handle was set to EOF.
458 * @s: The STREAM object.
459 *
460 * This function will only work with read streams.
461 **/
462int
463cdk_stream_eof (cdk_stream_t s)
464{
465 return s ? s->flags.eof : -1;
466}
467
468
469const char *
470_cdk_stream_get_fname (cdk_stream_t s)
471{
472 if (!s)
473 return NULL;
474 if (s->flags.temp)
475 return NULL;
476 return s->fname ? s->fname : NULL;
477}
478
479
480/* Return the underlying FP of the stream.
481 WARNING: This handle should not be closed. */
482FILE *
483_cdk_stream_get_fp (cdk_stream_t s)
484{
485 return s ? s->fp : NULL;
486}
487
488
489int
490_cdk_stream_get_errno (cdk_stream_t s)
491{
492 return s ? s->error : CDK_Inv_Value;
493}
494
495
496/**
497 * cdk_stream_get_length: Return the length of the associated file handle.
498 * @s: The STREAM object.
499 *
500 * This function should work for both read and write streams. For write
501 * streams an additional flush is used to write possible pending data.
502 **/
503off_t
504cdk_stream_get_length (cdk_stream_t s)
505{
506 struct stat statbuf;
507 cdk_error_t rc;
508
509 if (!s)
510 return (off_t) - 1;
511
512 /* The user callback does not support stat. */
513 if (s->cbs_hd)
514 return 0;
515
516 rc = stream_flush (s);
517 if (rc)
518 {
519 s->error = rc;
520 return (off_t) - 1;
521 }
522
523 if (fstat (fileno (s->fp), &statbuf))
524 {
525 s->error = CDK_File_Error;
526 return (off_t) - 1;
527 }
528
529 return statbuf.st_size;
530}
531
532
533static struct stream_filter_s *
534filter_add2 (cdk_stream_t s)
535{
536 struct stream_filter_s *f;
537
538 assert (s);
539
540 f = cdk_calloc (1, sizeof *f);
541 if (!f)
542 return NULL;
543 f->next = s->filters;
544 s->filters = f;
545 return f;
546}
547
548
549static struct stream_filter_s *
550filter_search (cdk_stream_t s, filter_fnct_t fnc)
551{
552 struct stream_filter_s *f;
553
554 assert (s);
555
556 for (f = s->filters; f; f = f->next)
557 {
558 if (f->fnct == fnc)
559 return f;
560 }
561
562 return NULL;
563}
564
565
566struct stream_filter_s *
567filter_add (cdk_stream_t s, filter_fnct_t fnc, int type)
568{
569 struct stream_filter_s *f;
570
571 assert (s);
572
573 s->flags.filtrated = 0;
574 f = filter_search (s, fnc);
575 if (f)
576 return f;
577 f = filter_add2 (s);
578 if (!f)
579 return NULL;
580 f->fnct = fnc;
581 f->flags.enabled = 1;
582 f->tmp = NULL;
583 f->type = type;
584 switch (type)
585 {
586 case fARMOR:
587 f->opaque = &f->u.afx;
588 break;
589 case fCIPHER:
590 f->opaque = &f->u.cfx;
591 break;
592 case fLITERAL:
593 f->opaque = &f->u.pfx;
594 break;
595 case fCOMPRESS:
596 f->opaque = &f->u.zfx;
597 break;
598 case fHASH:
599 f->opaque = &f->u.mfx;
600 break;
601 case fTEXT:
602 f->opaque = &f->u.tfx;
603 break;
604 default:
605 f->opaque = NULL;
606 }
607
608 return f;
609}
610
611
612static int
613stream_get_mode (cdk_stream_t s)
614{
615 assert (s);
616
617 if (s->flags.temp)
618 return s->fmode;
619 return s->flags.write;
620}
621
622
623static filter_fnct_t
624stream_id_to_filter (int type)
625{
626 switch (type)
627 {
628 case fARMOR:
629 return _cdk_filter_armor;
630 case fLITERAL:
631 return _cdk_filter_literal;
632 case fTEXT:
633 return _cdk_filter_text;
634 case fCIPHER:
635 return _cdk_filter_cipher;
636 case fCOMPRESS:
637 return _cdk_filter_compress;
638 default:
639 return NULL;
640 }
641}
642
643
644/**
645 * cdk_stream_filter_disable: Disable the filter with the type 'type'
646 * @s: The STREAM object
647 * @type: The numberic filter ID.
648 *
649 **/
650cdk_error_t
651cdk_stream_filter_disable (cdk_stream_t s, int type)
652{
653 struct stream_filter_s *f;
654 filter_fnct_t fnc;
655
656 if (!s)
657 return CDK_Inv_Value;
658
659 fnc = stream_id_to_filter (type);
660 if (!fnc)
661 return CDK_Inv_Value;
662 f = filter_search (s, fnc);
663 if (f)
664 f->flags.enabled = 0;
665 return 0;
666}
667
668
669/* WARNING: tmp should not be closed by the caller. */
670static cdk_error_t
671stream_fp_replace (cdk_stream_t s, FILE ** tmp)
672{
673 int rc;
674
675 assert (s);
676
677 _cdk_log_debug ("replace stream fd=%d with fd=%d\n",
678 fileno (s->fp), fileno (*tmp));
679 rc = fclose (s->fp);
680 if (rc)
681 return CDK_File_Error;
682 s->fp = *tmp;
683 *tmp = NULL;
684 return 0;
685}
686
687
688/* This function is exactly like filter_read, except the fact that we can't
689 use tmpfile () all the time. That's why we open the real file when there
690 is no last filter. */
691static cdk_error_t
692stream_filter_write (cdk_stream_t s)
693{
694 struct stream_filter_s *f;
695 cdk_error_t rc = 0;
696
697 assert (s);
698
699 if (s->flags.filtrated)
700 return CDK_Inv_Value;
701
702 for (f = s->filters; f; f = f->next)
703 {
704 if (!f->flags.enabled)
705 continue;
706 /* if there is no next filter, create the final output file */
707 _cdk_log_debug ("filter [write]: last filter=%d fname=%s\n",
708 f->next ? 1 : 0, s->fname);
709 if (!f->next && s->fname)
710 f->tmp = fopen (s->fname, "w+b");
711 else
712 f->tmp = my_tmpfile ();
713 if (!f->tmp)
714 {
715 rc = CDK_File_Error;
716 break;
717 }
718 /* If there is no next filter, flush the cache. We also do this
719 when the next filter is the armor filter because this filter
720 is special and before it starts, all data should be written. */
721 if ((!f->next || f->next->type == fARMOR) && s->cache.size)
722 {
723 rc = stream_cache_flush (s, f->tmp);
724 if (rc)
725 break;
726 }
727 rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
728 _cdk_log_debug ("filter [write]: type=%d rc=%d\n", f->type, rc);
729 if (!rc)
730 rc = stream_fp_replace (s, &f->tmp);
731 if (!rc)
732 rc = cdk_stream_seek (s, 0);
733 if (rc)
734 {
735 _cdk_log_debug ("filter [close]: fd=%d\n", fileno (f->tmp));
736 fclose (f->tmp);
737 break;
738 }
739 }
740 return rc;
741}
742
743
744/* Here all data from the file handle is passed through all filters.
745 The scheme works like this:
746 Create a tempfile and use it for the output of the filter. Then the
747 original file handle will be closed and replace with the temp handle.
748 The file pointer will be set to the begin and the game starts again. */
749static cdk_error_t
750stream_filter_read (cdk_stream_t s)
751{
752 struct stream_filter_s *f;
753 cdk_error_t rc = 0;
754
755 assert (s);
756
757 if (s->flags.filtrated)
758 return 0;
759
760 for (f = s->filters; f; f = f->next)
761 {
762 if (!f->flags.enabled)
763 continue;
764 if (f->flags.error)
765 {
766 _cdk_log_debug ("filter %s [read]: has the error flag; skipped\n",
767 s->fname ? s->fname : "[temp]");
768 continue;
769 }
770
771 f->tmp = my_tmpfile ();
772 if (!f->tmp)
773 {
774 rc = CDK_File_Error;
775 break;
776 }
777 rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
778 _cdk_log_debug ("filter %s [read]: type=%d rc=%d\n",
779 s->fname ? s->fname : "[temp]", f->type, rc);
780 if (rc)
781 {
782 f->flags.error = 1;
783 break;
784 }
785
786 f->flags.error = 0;
787 /* If the filter is read-only, do not replace the FP because
788 the contents were not altered in any way. */
789 if (!f->flags.rdonly)
790 {
791 rc = stream_fp_replace (s, &f->tmp);
792 if (rc)
793 break;
794 }
795 else
796 {
797 fclose (f->tmp);
798 f->tmp = NULL;
799 }
800 rc = cdk_stream_seek (s, 0);
801 if (rc)
802 break;
803 /* Disable the filter after it was successfully used. The idea
804 is the following: let's say the armor filter was pushed and
805 later more filters were added. The second time the filter code
806 will be executed, only the new filter should be started but
807 not the old because we already used it. */
808 f->flags.enabled = 0;
809 }
810
811 return rc;
812}
813
814
815void *
816_cdk_stream_get_opaque (cdk_stream_t s, int fid)
817{
818 struct stream_filter_s *f;
819
820 if (!s)
821 return NULL;
822
823 for (f = s->filters; f; f = f->next)
824 {
825 if (f->type == fid)
826 return f->opaque;
827 }
828 return NULL;
829}
830
831
832/**
833 * cdk_stream_read: Try to read count bytes from the STREAM object.
834 * @s: The STREAM object.
835 * @buf: The buffer to insert the readed bytes.
836 * @count: Request so much bytes.
837 *
838 * When this function is called the first time, it can take a while
839 * because all filters need to be processed. Please remember that you
840 * need to add the filters in reserved order.
841 **/
842int
843cdk_stream_read (cdk_stream_t s, void *buf, size_t buflen)
844{
845 int nread;
846 int rc;
847
848 if (!s)
849 {
850 s->error = CDK_Inv_Value;
851 return EOF;
852 }
853
854 if (s->cbs_hd)
855 {
856 if (s->cbs.read)
857 return s->cbs.read (s->cbs_hd, buf, buflen);
858 return 0;
859 }
860
861 if (s->flags.write && !s->flags.temp)
862 {
863 s->error = CDK_Inv_Mode;
864 return EOF; /* This is a write stream */
865 }
866
867 if (!s->flags.no_filter && !s->cache.on && !s->flags.filtrated)
868 {
869 rc = stream_filter_read (s);
870 if (rc)
871 {
872 s->error = rc;
873 if (feof (s->fp))
874 s->flags.eof = 1;
875 return EOF;
876 }
877 s->flags.filtrated = 1;
878 }
879 if (!buf && !buflen)
880 return 0;
881 nread = fread (buf, 1, buflen, s->fp);
882 if (!nread)
883 nread = EOF;
884 if (feof (s->fp))
885 {
886 s->error = 0;
887 s->flags.eof = 1;
888 }
889 return nread;
890}
891
892
893int
894cdk_stream_getc (cdk_stream_t s)
895{
896 unsigned char buf[2];
897 int nread;
898
899 if (!s)
900 {
901 s->error = CDK_Inv_Value;
902 return EOF;
903 }
904 nread = cdk_stream_read (s, buf, 1);
905 if (nread == EOF)
906 {
907 s->error = CDK_File_Error;
908 return EOF;
909 }
910 return buf[0];
911}
912
913
914/**
915 * cdk_stream_write: Try to write count bytes into the stream.
916 * @s: The STREAM object
917 * @buf: The buffer with the values to write.
918 * @count: The size of the buffer.
919 *
920 * In this function we simply write the bytes to the stream. We can't
921 * use the filters here because it would mean they have to support
922 * partial flushing.
923 **/
924int
925cdk_stream_write (cdk_stream_t s, const void *buf, size_t count)
926{
927 int nwritten;
928
929 if (!s)
930 {
931 s->error = CDK_Inv_Value;
932 return EOF;
933 }
934
935 if (s->cbs_hd)
936 {
937 if (s->cbs.write)
938 return s->cbs.write (s->cbs_hd, buf, count);
939 return 0;
940 }
941
942 if (!s->flags.write)
943 {
944 s->error = CDK_Inv_Mode; /* this is a read stream */
945 return EOF;
946 }
947
948 if (!buf && !count)
949 return stream_flush (s);
950
951 if (s->cache.on)
952 {
953 /* We need to resize the buffer if the additional data wouldn't
954 fit into it. We allocate more memory to avoid to resize it the
955 next time the function is used. */
956 if (s->cache.size + count > s->cache.alloced)
957 {
958 byte *old = s->cache.buf;
959
960 s->cache.buf =
961 cdk_calloc (1, s->cache.alloced + count + STREAM_BUFSIZE);
962 s->cache.alloced += (count + STREAM_BUFSIZE);
963 memcpy (s->cache.buf, old, s->cache.size);
964 cdk_free (old);
965 _cdk_log_debug ("stream: enlarge cache to %d octets\n",
966 s->cache.alloced);
967 }
968 memcpy (s->cache.buf + s->cache.size, buf, count);
969 s->cache.size += count;
970 return count;
971 }
972
973 nwritten = fwrite (buf, 1, count, s->fp);
974 if (!nwritten)
975 nwritten = EOF;
976 return nwritten;
977}
978
979
980int
981cdk_stream_putc (cdk_stream_t s, int c)
982{
983 byte buf[2];
984 int nwritten;
985
986 if (!s)
987 {
988 s->error = CDK_Inv_Value;
989 return EOF;
990 }
991 buf[0] = c;
992 nwritten = cdk_stream_write (s, buf, 1);
993 if (nwritten == EOF)
994 return EOF;
995 return 0;
996}
997
998
999off_t
1000cdk_stream_tell (cdk_stream_t s)
1001{
1002 return s ? ftell (s->fp) : (off_t) - 1;
1003}
1004
1005
1006cdk_error_t
1007cdk_stream_seek (cdk_stream_t s, off_t offset)
1008{
1009 off_t len;
1010
1011 if (!s)
1012 return CDK_Inv_Value;
1013
1014 if (s->cbs_hd)
1015 {
1016 if (s->cbs.seek)
1017 return s->cbs.seek (s->cbs_hd, offset);
1018 return 0;
1019 }
1020
1021 /* Set or reset the EOF flag. */
1022 len = cdk_stream_get_length (s);
1023 if (len == offset)
1024 s->flags.eof = 1;
1025 else
1026 s->flags.eof = 0;
1027
1028 if (fseek (s->fp, offset, SEEK_SET))
1029 return CDK_File_Error;
1030 return 0;
1031}
1032
1033
1034static cdk_error_t
1035stream_flush (cdk_stream_t s)
1036{
1037 assert (s);
1038
1039 /* For some constellations it cannot be assured that the
1040 return value is defined, thus we ignore it for now. */
1041 (void) fflush (s->fp);
1042 return 0;
1043}
1044
1045
1046/**
1047 * cdk_stream_set_armor_flag:
1048 * @s: the stream object
1049 * @type: the type of armor to use
1050 *
1051 * If the file is in read-mode, no armor type needs to be
1052 * defined (armor_type=0) because the armor filter will be
1053 * used for decoding existing armor data.
1054 * For the write mode, @armor_type can be set to any valid
1055 * armor type (message, key, sig).
1056 **/
1057cdk_error_t
1058cdk_stream_set_armor_flag (cdk_stream_t s, int armor_type)
1059{
1060 struct stream_filter_s *f;
1061
1062 if (!s)
1063 return CDK_Inv_Value;
1064 f = filter_add (s, _cdk_filter_armor, fARMOR);
1065 if (!f)
1066 return CDK_Out_Of_Core;
1067 f->u.afx.idx = f->u.afx.idx2 = armor_type;
1068 f->ctl = stream_get_mode (s);
1069 return 0;
1070}
1071
1072
1073/**
1074 * cdk_stream_set_literal_flag:
1075 * @s: the stream object
1076 * @mode: the mode to use (binary, text, unicode)
1077 * @fname: the file name to store in the packet.
1078 *
1079 * In read mode it kicks off the literal decoding routine to
1080 * unwrap the data from the packet. The @mode parameter is ignored.
1081 * In write mode the function can be used to wrap the stream data
1082 * into a literal packet with the given mode and file name.
1083 **/
1084cdk_error_t
1085cdk_stream_set_literal_flag (cdk_stream_t s, cdk_lit_format_t mode,
1086 const char *fname)
1087{
1088 struct stream_filter_s *f;
1089 const char *orig_fname;
1090
1091 _cdk_log_debug ("stream: enable literal mode.\n");
1092
1093 if (!s)
1094 return CDK_Inv_Value;
1095
1096 orig_fname = _cdk_stream_get_fname (s);
1097 f = filter_add (s, _cdk_filter_literal, fLITERAL);
1098 if (!f)
1099 return CDK_Out_Of_Core;
1100 f->u.pfx.mode = mode;
1101 f->u.pfx.filename = fname ? cdk_strdup (fname) : NULL;
1102 f->u.pfx.orig_filename = orig_fname ? cdk_strdup (orig_fname) : NULL;
1103 f->ctl = stream_get_mode (s);
1104 if (s->blkmode > 0)
1105 {
1106 f->u.pfx.blkmode.on = 1;
1107 f->u.pfx.blkmode.size = s->blkmode;
1108 }
1109 return 0;
1110}
1111
1112
1113/**
1114 * cdk_stream_set_cipher_flag:
1115 * @s: the stream object
1116 * @dek: the data encryption key
1117 * @use_mdc: 1 means to use the MDC mode
1118 *
1119 * In read mode it kicks off the cipher filter to decrypt the data
1120 * from the stream with the key given in @dek.
1121 * In write mode the stream data will be encrypted with the DEK object
1122 * and optionally, the @use_mdc parameter can be used to enable the MDC mode.
1123 **/
1124cdk_error_t
1125cdk_stream_set_cipher_flag (cdk_stream_t s, cdk_dek_t dek, int use_mdc)
1126{
1127 struct stream_filter_s *f;
1128
1129 _cdk_log_debug ("stream: enable cipher mode\n");
1130 if (!s)
1131 return CDK_Inv_Value;
1132 f = filter_add (s, _cdk_filter_cipher, fCIPHER);
1133 if (!f)
1134 return CDK_Out_Of_Core;
1135 dek->use_mdc = use_mdc;
1136 f->ctl = stream_get_mode (s);
1137 f->u.cfx.dek = dek;
1138 f->u.cfx.mdc_method = use_mdc ? GCRY_MD_SHA1 : 0;
1139 if (s->blkmode > 0)
1140 {
1141 f->u.cfx.blkmode.on = 1;
1142 f->u.cfx.blkmode.size = s->blkmode;
1143 }
1144 return 0;
1145}
1146
1147
1148/**
1149 * cdk_stream_set_compress_flag:
1150 * @s: the stream object
1151 * @algo: the compression algo
1152 * @level: level of compression (0..9)
1153 *
1154 * In read mode it kicks off the decompression filter to retrieve
1155 * the uncompressed data.
1156 * In write mode the stream data will be compressed with the
1157 * given algorithm at the given level.
1158 **/
1159cdk_error_t
1160cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level)
1161{
1162 struct stream_filter_s *f;
1163
1164 if (!s)
1165 return CDK_Inv_Value;
1166 f = filter_add (s, _cdk_filter_compress, fCOMPRESS);
1167 if (!f)
1168 return CDK_Out_Of_Core;
1169 f->ctl = stream_get_mode (s);
1170 f->u.zfx.algo = algo;
1171 f->u.zfx.level = level;
1172 return 0;
1173}
1174
1175
1176/**
1177 * cdk_stream_set_text_flag:
1178 * @s: the stream object
1179 * @lf: line ending
1180 *
1181 * Pushes the text filter to store the stream data in cannoncial format.
1182 **/
1183cdk_error_t
1184cdk_stream_set_text_flag (cdk_stream_t s, const char *lf)
1185{
1186 struct stream_filter_s *f;
1187
1188 if (!s)
1189 return CDK_Inv_Value;
1190 f = filter_add (s, _cdk_filter_text, fTEXT);
1191 if (!f)
1192 return CDK_Out_Of_Core;
1193 f->ctl = stream_get_mode (s);
1194 f->u.tfx.lf = lf;
1195 return 0;
1196}
1197
1198
1199/**
1200 * cdk_stream_set_hash_flag:
1201 * @s: the stream object
1202 * @digest_algo: the digest algorithm to use
1203 *
1204 * This is for read-only streams. It pushes a digest filter to
1205 * calculate the digest of the given stream data.
1206 **/
1207cdk_error_t
1208cdk_stream_set_hash_flag (cdk_stream_t s, int digest_algo)
1209{
1210 struct stream_filter_s *f;
1211
1212 if (!s)
1213 return CDK_Inv_Value;
1214 if (stream_get_mode (s))
1215 return CDK_Inv_Mode;
1216 f = filter_add (s, _cdk_filter_hash, fHASH);
1217 if (!f)
1218 return CDK_Out_Of_Core;
1219 f->ctl = stream_get_mode (s);
1220 f->u.mfx.digest_algo = digest_algo;
1221 f->flags.rdonly = 1;
1222 return 0;
1223}
1224
1225
1226/**
1227 * cdk_stream_enable_cache:
1228 * @s: the stream object
1229 * @val: 1=on, 0=off
1230 *
1231 * Enable or disable the cache section of a stream object.
1232 **/
1233cdk_error_t
1234cdk_stream_enable_cache (cdk_stream_t s, int val)
1235{
1236 if (!s)
1237 return CDK_Inv_Value;
1238 if (!s->flags.write)
1239 return CDK_Inv_Mode;
1240 s->cache.on = val;
1241 if (!s->cache.buf)
1242 {
1243 s->cache.buf = cdk_calloc (1, STREAM_BUFSIZE);
1244 s->cache.alloced = STREAM_BUFSIZE;
1245 _cdk_log_debug ("stream: allocate cache of %d octets\n",
1246 STREAM_BUFSIZE);
1247 }
1248 return 0;
1249}
1250
1251
1252static int
1253stream_cache_flush (cdk_stream_t s, FILE * fp)
1254{
1255 int nwritten;
1256
1257 assert (s);
1258
1259 /* FIXME: We should find a way to use cdk_stream_write here. */
1260 if (s->cache.size > 0)
1261 {
1262 nwritten = fwrite (s->cache.buf, 1, s->cache.size, fp);
1263 if (!nwritten)
1264 return CDK_File_Error;
1265 s->cache.size = 0;
1266 s->cache.on = 0;
1267 wipemem (s->cache.buf, s->cache.alloced);
1268 }
1269 return 0;
1270}
1271
1272
1273/**
1274 * cdk_stream_kick_off:
1275 * @inp: the input stream
1276 * @out: the output stream.
1277 *
1278 * Passes the entire data from @inp into the output stream @out
1279 * with all the activated filters.
1280 */
1281cdk_error_t
1282cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out)
1283{
1284 byte buf[BUFSIZE];
1285 int nread, nwritten;
1286 cdk_error_t rc;
1287
1288 if (!inp || !out)
1289 return CDK_Inv_Value;
1290 rc = CDK_Success;
1291 while (!cdk_stream_eof (inp))
1292 {
1293 nread = cdk_stream_read (inp, buf, DIM (buf));
1294 if (!nread || nread == EOF)
1295 break;
1296 nwritten = cdk_stream_write (out, buf, nread);
1297 if (!nwritten || nwritten == EOF)
1298 { /* In case of errors, we leave the loop. */
1299 rc = inp->error;
1300 break;
1301 }
1302 }
1303
1304 wipemem (buf, sizeof (buf));
1305 return rc;
1306}
1307
1308
1309/**
1310 * cdk_stream_mmap_part:
1311 * @s: the stream
1312 * @off: the offset where to start
1313 * @len: how much bytes shall be mapped
1314 * @ret_buf: the buffer to store the content
1315 * @ret_buflen: length of the buffer
1316 *
1317 * Map the data of the given stream into a memory section. @ret_count
1318 * contains the length of the buffer.
1319 **/
1320cdk_error_t
1321cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len,
1322 byte ** ret_buf, size_t * ret_buflen)
1323{
1324 off_t oldpos;
1325 int n;
1326 cdk_error_t rc;
1327
1328 if (!s || !ret_buf || !ret_buflen)
1329 return CDK_Inv_Value;
1330 if (s->cbs_hd)
1331 return CDK_Inv_Mode;
1332
1333 *ret_buflen = 0;
1334 *ret_buf = NULL;
1335 oldpos = cdk_stream_tell (s);
1336 rc = cdk_stream_flush (s);
1337 if (!rc)
1338 rc = cdk_stream_seek (s, off);
1339 if (rc)
1340 return rc;
1341 if (!len)
1342 len = cdk_stream_get_length (s);
1343 if (!len || len > MAX_MAP_SIZE)
1344 return 0;
1345 *ret_buf = cdk_calloc (1, len + 1);
1346 *ret_buflen = len;
1347 n = cdk_stream_read (s, *ret_buf, len);
1348 if (n != len)
1349 *ret_buflen = n;
1350 rc = cdk_stream_seek (s, oldpos);
1351 return rc;
1352}
1353
1354
1355cdk_error_t
1356cdk_stream_mmap (cdk_stream_t inp, byte ** buf, size_t * buflen)
1357{
1358 off_t len;
1359
1360 /* We need to make sure all data is flushed before we retrieve the size. */
1361 cdk_stream_flush (inp);
1362 len = cdk_stream_get_length (inp);
1363 return cdk_stream_mmap_part (inp, 0, len, buf, buflen);
1364}
1365
1366
1367/**
1368 * cdk_stream_peek:
1369 * @inp: the input stream handle
1370 * @s: buffer
1371 * @count: number of bytes to peek
1372 *
1373 * The function acts like cdk_stream_read with the difference that
1374 * the file pointer is moved to the old position after the bytes were read.
1375 **/
1376int
1377cdk_stream_peek (cdk_stream_t inp, byte * buf, size_t buflen)
1378{
1379 off_t off;
1380 int nbytes;
1381
1382 if (!inp || !buf)
1383 return 0;
1384 if (inp->cbs_hd)
1385 return 0;
1386
1387 off = cdk_stream_tell (inp);
1388 nbytes = cdk_stream_read (inp, buf, buflen);
1389 if (nbytes == -1)
1390 return 0;
1391 if (cdk_stream_seek (inp, off))
1392 return 0;
1393 return nbytes;
1394}
1395
1396
1397/* Try to read a line from the given stream. */
1398int
1399_cdk_stream_gets (cdk_stream_t s, char *buf, size_t count)
1400{
1401 int c, i;
1402
1403 assert (s);
1404
1405 i = 0;
1406 while (!cdk_stream_eof (s) && count > 0)
1407 {
1408 c = cdk_stream_getc (s);
1409 if (c == EOF || c == '\r' || c == '\n')
1410 {
1411 buf[i++] = '\0';
1412 break;
1413 }
1414 buf[i++] = c;
1415 count--;
1416 }
1417 return i;
1418}
1419
1420
1421/* Try to write string into the stream @s. */
1422int
1423_cdk_stream_puts (cdk_stream_t s, const char *buf)
1424{
1425 return cdk_stream_write (s, buf, strlen (buf));
1426}
1427
1428
1429/* Activate the block mode for the given stream. */
1430cdk_error_t
1431_cdk_stream_set_blockmode (cdk_stream_t s, size_t nbytes)
1432{
1433 assert (s);
1434
1435 _cdk_log_debug ("stream: activate block mode with blocksize %d\n", nbytes);
1436 s->blkmode = nbytes;
1437 return 0;
1438}
1439
1440
1441/* Return the block mode state of the given stream. */
1442int
1443_cdk_stream_get_blockmode (cdk_stream_t s)
1444{
1445 return s ? s->blkmode : 0;
1446}
diff --git a/src/daemon/https/opencdk/stream.h b/src/daemon/https/opencdk/stream.h
new file mode 100644
index 00000000..df44c6c6
--- /dev/null
+++ b/src/daemon/https/opencdk/stream.h
@@ -0,0 +1,88 @@
1/* stream.h - internal definiton for the STREAM object
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifndef CDK_STREAM_H
17#define CDK_STREAM_H
18
19/* The default buffer size for the stream. */
20#define STREAM_BUFSIZE 8192
21
22enum {
23 fDUMMY = 0,
24 fARMOR = 1,
25 fCIPHER = 2,
26 fLITERAL = 3,
27 fCOMPRESS= 4,
28 fHASH = 5,
29 fTEXT = 6
30};
31
32/* Type definition for the filter function. */
33typedef int (*filter_fnct_t) (void * opaque, int ctl, FILE * in, FILE * out);
34
35/* The stream filter context structure. */
36struct stream_filter_s
37{
38 struct stream_filter_s *next;
39 filter_fnct_t fnct;
40 void *opaque;
41 FILE *tmp;
42 union {
43 armor_filter_t afx;
44 cipher_filter_t cfx;
45 literal_filter_t pfx;
46 compress_filter_t zfx;
47 text_filter_t tfx;
48 md_filter_t mfx;
49 } u;
50 struct {
51 unsigned enabled:1;
52 unsigned rdonly:1;
53 unsigned error:1;
54 } flags;
55 unsigned type;
56 unsigned ctl;
57};
58
59
60/* The stream context structure. */
61struct cdk_stream_s {
62 struct stream_filter_s *filters;
63 int fmode;
64 int error;
65 size_t blkmode;
66 struct {
67 unsigned filtrated:1;
68 unsigned eof:1;
69 unsigned write:1;
70 unsigned temp:1;
71 unsigned reset:1;
72 unsigned no_filter:1;
73 unsigned compressed:3;
74 } flags;
75 struct {
76 unsigned char *buf;
77 unsigned on:1;
78 size_t size;
79 size_t alloced;
80 } cache;
81 char *fname;
82 FILE *fp;
83 unsigned int fp_ref:1;
84 struct cdk_stream_cbs_s cbs;
85 void *cbs_hd;
86};
87
88#endif /* CDK_STREAM_H */
diff --git a/src/daemon/https/opencdk/types.h b/src/daemon/https/opencdk/types.h
new file mode 100644
index 00000000..c53a0850
--- /dev/null
+++ b/src/daemon/https/opencdk/types.h
@@ -0,0 +1,44 @@
1/* types.h - Some type definitions
2 * Copyright (C) 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifndef CDK_TYPES_H
17#define CDK_TYPES_H
18
19#include <gcrypt.h>
20
21#ifndef HAVE_BYTE_TYPEDEF
22# undef byte
23 typedef unsigned char byte;
24# define HAVE_BYTE_TYPEDEF
25#endif
26
27#ifndef HAVE_U16_TYPEDEF
28# undef u16
29 typedef unsigned short u16;
30# define HAVE_U16_TYPEDEF
31#endif
32
33#ifndef HAVE_U32_TYPEDEF
34# undef u32
35 typedef unsigned int u32;
36# define HAVE_U32_TYPEDEF
37#endif
38
39#ifndef DIM
40# define DIM(v) (sizeof (v)/sizeof ((v)[0]))
41# define DIMof(type, member) DIM(((type *)0)->member)
42#endif
43
44#endif /* CDK_TYPES_H */
diff --git a/src/daemon/https/opencdk/verify.c b/src/daemon/https/opencdk/verify.c
new file mode 100644
index 00000000..71b4c237
--- /dev/null
+++ b/src/daemon/https/opencdk/verify.c
@@ -0,0 +1,306 @@
1/* verify.c - Verify signatures
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17# include <config.h>
18#endif
19#include <stdio.h>
20#include <string.h>
21#include <assert.h>
22#include <sys/stat.h>
23
24#include "opencdk.h"
25#include "main.h"
26#include "filters.h"
27#include "packet.h"
28
29
30/* Table of all supported digest algorithms and their names. */
31struct
32{
33 const char *name;
34 int algo;
35} digest_table[] =
36{
37 {
38 "MD5", GCRY_MD_MD5},
39 {
40 "SHA1", GCRY_MD_SHA1},
41 {
42 "RIPEMD160", GCRY_MD_RMD160},
43 {
44 "SHA256", GCRY_MD_SHA256},
45 {
46 "SHA384", GCRY_MD_SHA384},
47 {
48 "SHA512", GCRY_MD_SHA512},
49 {
50 NULL, 0}
51};
52
53
54static int file_verify_clearsign (cdk_ctx_t, const char *, const char *);
55
56
57/**
58 * cdk_stream_verify:
59 * @hd: session handle
60 * @inp: the input stream
61 * @data: for detached signatures, this is the data stream @inp is the sig
62 * @out: where the output shall be written.
63 */
64cdk_error_t
65cdk_stream_verify (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t data,
66 cdk_stream_t out)
67{
68 /* FIXME: out is not currently used. */
69 if (cdk_armor_filter_use (inp))
70 cdk_stream_set_armor_flag (inp, 0);
71 return _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL);
72}
73
74
75/**
76 * cdk_file_verify:
77 * @hd: the session handle
78 * @file: the input file
79 * @data_file: for detached signature this is the data file and @file is the sig.
80 * @output: the output file
81 *
82 * Verify a signature.
83 **/
84cdk_error_t
85cdk_file_verify (cdk_ctx_t hd, const char *file, const char *data_file,
86 const char *output)
87{
88 struct stat stbuf;
89 cdk_stream_t inp, data;
90 char buf[4096];
91 int n;
92 cdk_error_t rc;
93
94 if (!hd || !file)
95 return CDK_Inv_Value;
96 if (output && !hd->opt.overwrite && !stat (output, &stbuf))
97 return CDK_Inv_Mode;
98
99 rc = cdk_stream_open (file, &inp);
100 if (rc)
101 return rc;
102 if (cdk_armor_filter_use (inp))
103 {
104 n = cdk_stream_peek (inp, (byte *) buf, DIM (buf) - 1);
105 if (!n || n == -1)
106 return CDK_EOF;
107 buf[n] = '\0';
108 if (strstr (buf, "BEGIN PGP SIGNED MESSAGE"))
109 {
110 cdk_stream_close (inp);
111 return file_verify_clearsign (hd, file, output);
112 }
113 cdk_stream_set_armor_flag (inp, 0);
114 }
115
116 if (data_file)
117 {
118 rc = cdk_stream_open (data_file, &data);
119 if (rc)
120 {
121 cdk_stream_close (inp);
122 return rc;
123 }
124 }
125 else
126 data = NULL;
127
128 rc = _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL);
129
130 if (data != NULL)
131 cdk_stream_close (data);
132 cdk_stream_close (inp);
133 return rc;
134}
135
136
137void
138_cdk_result_verify_free (cdk_verify_result_t res)
139{
140 if (!res)
141 return;
142 cdk_free (res->policy_url);
143 cdk_free (res->sig_data);
144 cdk_free (res);
145}
146
147
148cdk_verify_result_t
149_cdk_result_verify_new (void)
150{
151 cdk_verify_result_t res;
152
153 res = cdk_calloc (1, sizeof *res);
154 if (!res)
155 return NULL;
156 return res;
157}
158
159
160static cdk_error_t
161file_verify_clearsign (cdk_ctx_t hd, const char *file, const char *output)
162{
163 cdk_stream_t inp = NULL, out = NULL, tmp = NULL;
164 gcry_md_hd_t md = NULL;
165 char buf[512], chk[512];
166 const char *s;
167 int i, is_signed = 0, nbytes;
168 int digest_algo = 0;
169 gcry_error_t err;
170 cdk_error_t rc;
171
172 if (output)
173 {
174 rc = cdk_stream_create (output, &out);
175 if (rc)
176 return rc;
177 }
178
179 rc = cdk_stream_open (file, &inp);
180 if (rc)
181 {
182 if (output)
183 cdk_stream_close (out);
184 return rc;
185 }
186
187 s = "-----BEGIN PGP SIGNED MESSAGE-----";
188 while (!cdk_stream_eof (inp))
189 {
190 nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
191 if (!nbytes || nbytes == -1)
192 break;
193 if (!strncmp (buf, s, strlen (s)))
194 {
195 is_signed = 1;
196 break;
197 }
198 }
199
200 if (cdk_stream_eof (inp) && !is_signed)
201 {
202 rc = CDK_Armor_Error;
203 goto leave;
204 }
205
206 while (!cdk_stream_eof (inp))
207 {
208 nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
209 if (!nbytes || nbytes == -1)
210 break;
211 if (nbytes == 1) /* Empty line */
212 break;
213 else if (!strncmp (buf, "Hash: ", 6))
214 {
215 for (i = 0; digest_table[i].name; i++)
216 {
217 if (!strcmp (buf + 6, digest_table[i].name))
218 {
219 digest_algo = digest_table[i].algo;
220 break;
221 }
222 }
223 }
224 }
225
226 if (digest_algo && gcry_md_test_algo (digest_algo))
227 {
228 rc = CDK_Inv_Algo;
229 goto leave;
230 }
231
232 if (!digest_algo)
233 digest_algo = GCRY_MD_MD5;
234
235 err = gcry_md_open (&md, digest_algo, 0);
236 if (err)
237 {
238 rc = map_gcry_error (err);
239 goto leave;
240 }
241
242 s = "-----BEGIN PGP SIGNATURE-----";
243 while (!cdk_stream_eof (inp))
244 {
245 nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
246 if (!nbytes || nbytes == -1)
247 break;
248 if (!strncmp (buf, s, strlen (s)))
249 break;
250 else
251 {
252 cdk_stream_peek (inp, (byte *) chk, DIM (chk) - 1);
253 i = strncmp (chk, s, strlen (s));
254 if (strlen (buf) == 0 && i == 0)
255 continue; /* skip last '\n' */
256 _cdk_trim_string (buf, i == 0 ? 0 : 1);
257 gcry_md_write (md, buf, strlen (buf));
258 }
259 if (!strncmp (buf, "- ", 2)) /* FIXME: handle it recursive. */
260 memmove (buf, buf + 2, nbytes - 2);
261 if (out)
262 {
263 if (strstr (buf, "\r\n"))
264 buf[strlen (buf) - 2] = '\0';
265 cdk_stream_write (out, buf, strlen (buf));
266 _cdk_stream_puts (out, _cdk_armor_get_lineend ());
267 }
268 }
269
270 /* We create a temporary stream object to store the
271 signature data in there. */
272 rc = cdk_stream_tmp_new (&tmp);
273 if (rc)
274 goto leave;
275
276 s = "-----BEGIN PGP SIGNATURE-----\n";
277 _cdk_stream_puts (tmp, s);
278 while (!cdk_stream_eof (inp))
279 {
280 nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
281 if (!nbytes || nbytes == -1)
282 break;
283 if (nbytes < (DIM (buf) - 3))
284 {
285 buf[nbytes - 1] = '\n';
286 buf[nbytes] = '\0';
287 }
288 cdk_stream_write (tmp, buf, nbytes);
289 }
290
291 /* FIXME: This code is not very elegant. */
292 cdk_stream_tmp_set_mode (tmp, STREAMCTL_READ);
293 cdk_stream_seek (tmp, 0);
294 cdk_stream_set_armor_flag (tmp, 0);
295 cdk_stream_read (tmp, NULL, 0);
296
297 /* the digest handle will be closed there. */
298 rc = _cdk_proc_packets (hd, tmp, NULL, NULL, NULL, md);
299
300leave:
301 gcry_md_close (md);
302 cdk_stream_close (out);
303 cdk_stream_close (tmp);
304 cdk_stream_close (inp);
305 return rc;
306}
diff --git a/src/daemon/https/opencdk/write-packet.c b/src/daemon/https/opencdk/write-packet.c
new file mode 100644
index 00000000..46d239dd
--- /dev/null
+++ b/src/daemon/https/opencdk/write-packet.c
@@ -0,0 +1,947 @@
1/* write-packet.c - Write OpenPGP packets
2 * Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
3 *
4 * This file is part of OpenCDK.
5 *
6 * OpenCDK is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenCDK is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19#include <string.h>
20#include <stdio.h>
21#include <assert.h>
22
23#include "opencdk.h"
24#include "main.h"
25
26
27static int
28stream_write (cdk_stream_t s, const void *buf, size_t buflen)
29{
30 int nwritten;
31
32 nwritten = cdk_stream_write (s, buf, buflen);
33 if (nwritten == EOF)
34 return _cdk_stream_get_errno (s);
35 return 0;
36}
37
38
39static int
40stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t * r_nread)
41{
42 int nread;
43
44 assert (r_nread);
45
46 nread = cdk_stream_read (s, buf, buflen);
47 if (nread == EOF)
48 return _cdk_stream_get_errno (s);
49 *r_nread = nread;
50 return 0;
51}
52
53
54static int
55stream_putc (cdk_stream_t s, int c)
56{
57 int nwritten = cdk_stream_putc (s, c);
58 if (nwritten == EOF)
59 return _cdk_stream_get_errno (s);
60 return 0;
61}
62
63
64static int
65write_32 (cdk_stream_t out, u32 u)
66{
67 byte buf[4];
68
69 buf[0] = u >> 24;
70 buf[1] = u >> 16;
71 buf[2] = u >> 8;
72 buf[3] = u;
73 return stream_write (out, buf, 4);
74}
75
76
77static int
78write_16 (cdk_stream_t out, u16 u)
79{
80 byte buf[2];
81
82 buf[0] = u >> 8;
83 buf[1] = u;
84 return stream_write (out, buf, 2);
85}
86
87
88static size_t
89calc_mpisize (gcry_mpi_t mpi[MAX_CDK_PK_PARTS], size_t ncount)
90{
91 size_t size, i;
92
93 size = 0;
94 for (i = 0; i < ncount; i++)
95 size += (gcry_mpi_get_nbits (mpi[i]) + 7) / 8 + 2;
96 return size;
97}
98
99
100static int
101write_mpi (cdk_stream_t out, gcry_mpi_t m)
102{
103 byte buf[MAX_MPI_BYTES + 2];
104 size_t nbits, nread;
105 gcry_error_t err;
106
107 if (!out || !m)
108 return CDK_Inv_Value;
109 nbits = gcry_mpi_get_nbits (m);
110 if (nbits > MAX_MPI_BITS || nbits < 1)
111 return CDK_MPI_Error;
112 err = gcry_mpi_print (GCRYMPI_FMT_PGP, buf, MAX_MPI_BYTES + 2, &nread, m);
113 if (err)
114 return map_gcry_error (err);
115 return stream_write (out, buf, nread);
116}
117
118
119static cdk_error_t
120write_mpibuf (cdk_stream_t out, gcry_mpi_t mpi[MAX_CDK_PK_PARTS],
121 size_t count)
122{
123 size_t i;
124 cdk_error_t rc;
125
126 for (i = 0; i < count; i++)
127 {
128 rc = write_mpi (out, mpi[i]);
129 if (rc)
130 return rc;
131 }
132 return 0;
133}
134
135
136static cdk_error_t
137pkt_encode_len (cdk_stream_t out, size_t pktlen)
138{
139 cdk_error_t rc;
140
141 assert (out);
142
143 rc = 0;
144 if (!pktlen)
145 {
146 /* Block mode, partial bodies, with 'DEF_BLOCKSIZE' from main.h */
147 rc = stream_putc (out, (0xE0 | DEF_BLOCKBITS));
148 }
149 else if (pktlen < 192)
150 rc = stream_putc (out, pktlen);
151 else if (pktlen < 8384)
152 {
153 pktlen -= 192;
154 rc = stream_putc (out, (pktlen / 256) + 192);
155 if (!rc)
156 rc = stream_putc (out, (pktlen % 256));
157 }
158 else
159 {
160 rc = stream_putc (out, 255);
161 if (!rc)
162 rc = write_32 (out, pktlen);
163 }
164
165 return rc;
166}
167
168
169static cdk_error_t
170write_head_new (cdk_stream_t out, size_t size, int type)
171{
172 cdk_error_t rc;
173
174 assert (out);
175
176 if (type < 0 || type > 63)
177 return CDK_Inv_Packet;
178 rc = stream_putc (out, (0xC0 | type));
179 if (!rc)
180 rc = pkt_encode_len (out, size);
181 return rc;
182}
183
184
185static cdk_error_t
186write_head_old (cdk_stream_t out, size_t size, int type)
187{
188 cdk_error_t rc;
189 int ctb;
190
191 assert (out);
192
193 if (type < 0 || type > 16)
194 return CDK_Inv_Packet;
195 ctb = 0x80 | (type << 2);
196 if (!size)
197 ctb |= 3;
198 else if (size < 256)
199 ;
200 else if (size < 65536)
201 ctb |= 1;
202 else
203 ctb |= 2;
204 rc = stream_putc (out, ctb);
205 if (!size)
206 return rc;
207 if (!rc)
208 {
209 if (size < 256)
210 rc = stream_putc (out, size);
211 else if (size < 65536)
212 rc = write_16 (out, size);
213 else
214 rc = write_32 (out, size);
215 }
216
217 return rc;
218}
219
220
221/* Write special PGP2 packet header. PGP2 (wrongly) uses two byte header
222 length for signatures and keys even if the size is < 256. */
223static cdk_error_t
224pkt_write_head2 (cdk_stream_t out, size_t size, int type)
225{
226 cdk_error_t rc;
227
228 rc = cdk_stream_putc (out, 0x80 | (type << 2) | 1);
229 if (!rc)
230 rc = cdk_stream_putc (out, size >> 8);
231 if (!rc)
232 rc = cdk_stream_putc (out, size & 0xff);
233 return rc;
234}
235
236
237static int
238pkt_write_head (cdk_stream_t out, int old_ctb, size_t size, int type)
239{
240 if (old_ctb)
241 return write_head_old (out, size, type);
242 return write_head_new (out, size, type);
243}
244
245
246static cdk_error_t
247write_encrypted (cdk_stream_t out, cdk_pkt_encrypted_t enc, int old_ctb)
248{
249 size_t nbytes;
250 cdk_error_t rc;
251
252 assert (out);
253 assert (enc);
254
255 if (DEBUG_PKT)
256 _cdk_log_debug ("write_encrypted: %lu bytes\n", enc->len);
257
258 nbytes = enc->len ? (enc->len + enc->extralen) : 0;
259 rc = pkt_write_head (out, old_ctb, nbytes, CDK_PKT_ENCRYPTED);
260 /* The rest of the packet is ciphertext */
261 return rc;
262}
263
264
265static int
266write_encrypted_mdc (cdk_stream_t out, cdk_pkt_encrypted_t enc)
267{
268 size_t nbytes;
269 cdk_error_t rc;
270
271 assert (out);
272 assert (enc);
273
274 if (!enc->mdc_method)
275 return CDK_Inv_Packet;
276
277 if (DEBUG_PKT)
278 _cdk_log_debug ("write_encrypted_mdc: %lu bytes\n", enc->len);
279
280 nbytes = enc->len ? (enc->len + enc->extralen + 1) : 0;
281 rc = pkt_write_head (out, 0, nbytes, CDK_PKT_ENCRYPTED_MDC);
282 if (!rc)
283 rc = stream_putc (out, 1); /* version */
284 /* The rest of the packet is ciphertext */
285 return rc;
286}
287
288
289static cdk_error_t
290write_symkey_enc (cdk_stream_t out, cdk_pkt_symkey_enc_t ske)
291{
292 cdk_s2k_t s2k;
293 size_t size = 0, s2k_size = 0;
294 cdk_error_t rc;
295
296 assert (out);
297 assert (ske);
298
299 if (ske->version != 4)
300 return CDK_Inv_Packet;
301
302 if (DEBUG_PKT)
303 _cdk_log_debug ("write_symkey_enc:\n");
304
305 s2k = ske->s2k;
306 if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
307 s2k_size = 8;
308 if (s2k->mode == CDK_S2K_ITERSALTED)
309 s2k_size++;
310 size = 4 + s2k_size + ske->seskeylen;
311 rc = pkt_write_head (out, 0, size, CDK_PKT_SYMKEY_ENC);
312 if (!rc)
313 rc = stream_putc (out, ske->version);
314 if (!rc)
315 rc = stream_putc (out, ske->cipher_algo);
316 if (!rc)
317 rc = stream_putc (out, s2k->mode);
318 if (!rc)
319 rc = stream_putc (out, s2k->hash_algo);
320 if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
321 {
322 rc = stream_write (out, s2k->salt, 8);
323 if (!rc)
324 {
325 if (s2k->mode == CDK_S2K_ITERSALTED)
326 rc = stream_putc (out, s2k->count);
327 }
328 }
329 return rc;
330}
331
332
333static int
334write_pubkey_enc (cdk_stream_t out, cdk_pkt_pubkey_enc_t pke, int old_ctb)
335{
336 size_t size;
337 int rc, nenc;
338
339 assert (out);
340 assert (pke);
341
342 if (pke->version < 2 || pke->version > 3)
343 return CDK_Inv_Packet;
344 if (!KEY_CAN_ENCRYPT (pke->pubkey_algo))
345 return CDK_Inv_Algo;
346
347 if (DEBUG_PKT)
348 _cdk_log_debug ("write_pubkey_enc:\n");
349
350 nenc = cdk_pk_get_nenc (pke->pubkey_algo);
351 size = 10 + calc_mpisize (pke->mpi, nenc);
352 rc = pkt_write_head (out, old_ctb, size, CDK_PKT_PUBKEY_ENC);
353 if (rc)
354 return rc;
355
356 rc = stream_putc (out, pke->version);
357 if (!rc)
358 rc = write_32 (out, pke->keyid[0]);
359 if (!rc)
360 rc = write_32 (out, pke->keyid[1]);
361 if (!rc)
362 rc = stream_putc (out, pke->pubkey_algo);
363 if (!rc)
364 rc = write_mpibuf (out, pke->mpi, nenc);
365 return rc;
366}
367
368
369static cdk_error_t
370write_mdc (cdk_stream_t out, cdk_pkt_mdc_t mdc)
371{
372 cdk_error_t rc;
373
374 assert (mdc);
375 assert (out);
376
377 if (DEBUG_PKT)
378 _cdk_log_debug ("write_mdc:\n");
379
380 /* This packet requires a fixed header encoding */
381 rc = stream_putc (out, 0xD3); /* packet ID and 1 byte length */
382 if (!rc)
383 rc = stream_putc (out, 0x14);
384 if (!rc)
385 rc = stream_write (out, mdc->hash, DIM (mdc->hash));
386 return rc;
387}
388
389
390static size_t
391calc_subpktsize (cdk_subpkt_t s)
392{
393 size_t nbytes;
394
395 /* In the count mode, no buffer is returned. */
396 _cdk_subpkt_get_array (s, 1, &nbytes);
397 return nbytes;
398}
399
400
401static cdk_error_t
402write_v3_sig (cdk_stream_t out, cdk_pkt_signature_t sig, int nsig)
403{
404 size_t size;
405 cdk_error_t rc;
406
407 size = 19 + calc_mpisize (sig->mpi, nsig);
408 if (is_RSA (sig->pubkey_algo))
409 rc = pkt_write_head2 (out, size, CDK_PKT_SIGNATURE);
410 else
411 rc = pkt_write_head (out, 1, size, CDK_PKT_SIGNATURE);
412 if (!rc)
413 rc = stream_putc (out, sig->version);
414 if (!rc)
415 rc = stream_putc (out, 5);
416 if (!rc)
417 rc = stream_putc (out, sig->sig_class);
418 if (!rc)
419 rc = write_32 (out, sig->timestamp);
420 if (!rc)
421 rc = write_32 (out, sig->keyid[0]);
422 if (!rc)
423 rc = write_32 (out, sig->keyid[1]);
424 if (!rc)
425 rc = stream_putc (out, sig->pubkey_algo);
426 if (!rc)
427 rc = stream_putc (out, sig->digest_algo);
428 if (!rc)
429 rc = stream_putc (out, sig->digest_start[0]);
430 if (!rc)
431 rc = stream_putc (out, sig->digest_start[1]);
432 if (!rc)
433 rc = write_mpibuf (out, sig->mpi, nsig);
434 return rc;
435}
436
437
438static cdk_error_t
439write_signature (cdk_stream_t out, cdk_pkt_signature_t sig, int old_ctb)
440{
441 byte *buf;
442 size_t nbytes, size, nsig;
443 cdk_error_t rc;
444
445 assert (out);
446 assert (sig);
447
448 if (!KEY_CAN_SIGN (sig->pubkey_algo))
449 return CDK_Inv_Algo;
450 if (sig->version < 2 || sig->version > 4)
451 return CDK_Inv_Packet;
452
453 if (DEBUG_PKT)
454 _cdk_log_debug ("write_signature:\n");
455
456 nsig = cdk_pk_get_nsig (sig->pubkey_algo);
457 if (!nsig)
458 return CDK_Inv_Algo;
459 if (sig->version < 4)
460 return write_v3_sig (out, sig, nsig);
461
462 size = 10 + calc_subpktsize (sig->hashed)
463 + calc_subpktsize (sig->unhashed) + calc_mpisize (sig->mpi, nsig);
464 rc = pkt_write_head (out, 0, size, CDK_PKT_SIGNATURE);
465 if (!rc)
466 rc = stream_putc (out, 4);
467 if (!rc)
468 rc = stream_putc (out, sig->sig_class);
469 if (!rc)
470 rc = stream_putc (out, sig->pubkey_algo);
471 if (!rc)
472 rc = stream_putc (out, sig->digest_algo);
473 if (!rc)
474 rc = write_16 (out, sig->hashed_size);
475 if (!rc)
476 {
477 buf = _cdk_subpkt_get_array (sig->hashed, 0, &nbytes);
478 if (!buf)
479 return CDK_Out_Of_Core;
480 rc = stream_write (out, buf, nbytes);
481 cdk_free (buf);
482 }
483 if (!rc)
484 rc = write_16 (out, sig->unhashed_size);
485 if (!rc)
486 {
487 buf = _cdk_subpkt_get_array (sig->unhashed, 0, &nbytes);
488 if (!buf)
489 return CDK_Out_Of_Core;
490 rc = stream_write (out, buf, nbytes);
491 cdk_free (buf);
492 }
493 if (!rc)
494 rc = stream_putc (out, sig->digest_start[0]);
495 if (!rc)
496 rc = stream_putc (out, sig->digest_start[1]);
497 if (!rc)
498 rc = write_mpibuf (out, sig->mpi, nsig);
499 return rc;
500}
501
502
503static cdk_error_t
504write_public_key (cdk_stream_t out, cdk_pkt_pubkey_t pk,
505 int is_subkey, int old_ctb)
506{
507 int pkttype, ndays = 0;
508 size_t npkey = 0, size = 6;
509 cdk_error_t rc;
510
511 assert (out);
512 assert (pk);
513
514 if (pk->version < 2 || pk->version > 4)
515 return CDK_Inv_Packet;
516
517 if (DEBUG_PKT)
518 _cdk_log_debug ("write_public_key: subkey=%d\n", is_subkey);
519
520 pkttype = is_subkey ? CDK_PKT_PUBLIC_SUBKEY : CDK_PKT_PUBLIC_KEY;
521 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
522 if (!npkey)
523 return CDK_Inv_Algo;
524 if (pk->version < 4)
525 size += 2; /* expire date */
526 if (is_subkey)
527 old_ctb = 0;
528 size += calc_mpisize (pk->mpi, npkey);
529 if (old_ctb)
530 rc = pkt_write_head2 (out, size, pkttype);
531 else
532 rc = pkt_write_head (out, old_ctb, size, pkttype);
533 if (!rc)
534 rc = stream_putc (out, pk->version);
535 if (!rc)
536 rc = write_32 (out, pk->timestamp);
537 if (!rc && pk->version < 4)
538 {
539 if (pk->expiredate)
540 ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
541 rc = write_16 (out, ndays);
542 }
543 if (!rc)
544 rc = stream_putc (out, pk->pubkey_algo);
545 if (!rc)
546 rc = write_mpibuf (out, pk->mpi, npkey);
547 return rc;
548}
549
550
551static int
552calc_s2ksize (cdk_pkt_seckey_t sk)
553{
554 size_t nbytes = 0;
555
556 if (!sk->is_protected)
557 return 0;
558 switch (sk->protect.s2k->mode)
559 {
560 case CDK_S2K_SIMPLE:
561 nbytes = 2;
562 break;
563 case CDK_S2K_SALTED:
564 nbytes = 10;
565 break;
566 case CDK_S2K_ITERSALTED:
567 nbytes = 11;
568 break;
569 }
570 nbytes += sk->protect.ivlen;
571 nbytes++; /* single cipher byte */
572 return nbytes;
573}
574
575
576static cdk_error_t
577write_secret_key (cdk_stream_t out, cdk_pkt_seckey_t sk,
578 int is_subkey, int old_ctb)
579{
580 cdk_pkt_pubkey_t pk = NULL;
581 size_t size = 6, npkey, nskey;
582 int pkttype, s2k_mode;
583 cdk_error_t rc;
584
585 assert (out);
586 assert (sk);
587
588 if (!sk->pk)
589 return CDK_Inv_Value;
590 pk = sk->pk;
591 if (pk->version < 2 || pk->version > 4)
592 return CDK_Inv_Packet;
593
594 if (DEBUG_PKT)
595 _cdk_log_debug ("write_secret_key:\n");
596
597 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
598 nskey = cdk_pk_get_nskey (pk->pubkey_algo);
599 if (!npkey || !nskey)
600 return CDK_Inv_Algo;
601 if (pk->version < 4)
602 size += 2;
603 /* If the key is unprotected, the 1 extra byte:
604 1 octet - cipher algorithm byte (0x00)
605 the other bytes depend on the mode:
606 a) simple checksum - 2 octets
607 b) sha-1 checksum - 20 octets */
608 size = !sk->is_protected ? size + 1 : size + 1 + calc_s2ksize (sk);
609 size += calc_mpisize (pk->mpi, npkey);
610 if (sk->version == 3 || !sk->is_protected)
611 {
612 if (sk->version == 3)
613 {
614 size += 2; /* force simple checksum */
615 sk->protect.sha1chk = 0;
616 }
617 else
618 size += sk->protect.sha1chk ? 20 : 2;
619 size += calc_mpisize (sk->mpi, nskey);
620 }
621 else /* We do not know anything about the encrypted mpi's so we
622 treat the data as opaque. */
623 size += sk->enclen;
624
625 pkttype = is_subkey ? CDK_PKT_SECRET_SUBKEY : CDK_PKT_SECRET_KEY;
626 rc = pkt_write_head (out, old_ctb, size, pkttype);
627 if (!rc)
628 rc = stream_putc (out, pk->version);
629 if (!rc)
630 rc = write_32 (out, pk->timestamp);
631 if (!rc && pk->version < 4)
632 {
633 u16 ndays = 0;
634 if (pk->expiredate)
635 ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
636 rc = write_16 (out, ndays);
637 }
638 if (!rc)
639 rc = stream_putc (out, pk->pubkey_algo);
640 if (!rc)
641 rc = write_mpibuf (out, pk->mpi, npkey);
642 if (sk->is_protected == 0)
643 rc = stream_putc (out, 0x00);
644 else
645 {
646 if (is_RSA (pk->pubkey_algo) && pk->version < 4)
647 stream_putc (out, sk->protect.algo);
648 else if (sk->protect.s2k)
649 {
650 s2k_mode = sk->protect.s2k->mode;
651 rc = stream_putc (out, sk->protect.sha1chk ? 0xFE : 0xFF);
652 if (!rc)
653 rc = stream_putc (out, sk->protect.algo);
654 if (!rc)
655 rc = stream_putc (out, sk->protect.s2k->mode);
656 if (!rc)
657 rc = stream_putc (out, sk->protect.s2k->hash_algo);
658 if (!rc && (s2k_mode == 1 || s2k_mode == 3))
659 {
660 rc = stream_write (out, sk->protect.s2k->salt, 8);
661 if (!rc && s2k_mode == 3)
662 rc = stream_putc (out, sk->protect.s2k->count);
663 }
664 }
665 else
666 return CDK_Inv_Value;
667 rc = stream_write (out, sk->protect.iv, sk->protect.ivlen);
668 }
669 if (!rc && sk->is_protected && pk->version == 4)
670 {
671 if (sk->encdata && sk->enclen)
672 rc = stream_write (out, sk->encdata, sk->enclen);
673 }
674 else
675 {
676 if (!rc)
677 rc = write_mpibuf (out, sk->mpi, nskey);
678 if (!rc)
679 {
680 if (!sk->csum)
681 sk->csum = _cdk_sk_get_csum (sk);
682 rc = write_16 (out, sk->csum);
683 }
684 }
685
686 return rc;
687}
688
689
690static cdk_error_t
691write_compressed (cdk_stream_t out, cdk_pkt_compressed_t cd)
692{
693 cdk_error_t rc;
694
695 assert (out);
696 assert (cd);
697
698 if (DEBUG_PKT)
699 _cdk_log_debug ("packet: write_compressed\n");
700
701 /* Use an old (RFC1991) header for this packet. */
702 rc = pkt_write_head (out, 1, 0, CDK_PKT_COMPRESSED);
703 if (!rc)
704 rc = stream_putc (out, cd->algorithm);
705 return rc;
706}
707
708
709static cdk_error_t
710write_literal (cdk_stream_t out, cdk_pkt_literal_t pt, int old_ctb)
711{
712 byte buf[BUFSIZE];
713 size_t size;
714 cdk_error_t rc;
715
716 assert (out);
717 assert (pt);
718
719 /* We consider a packet without a body as an invalid packet.
720 At least one octet must be present. */
721 if (!pt->len)
722 return CDK_Inv_Packet;
723
724 if (DEBUG_PKT)
725 _cdk_log_debug ("write_literal:\n");
726
727 size = 6 + pt->namelen + pt->len;
728 rc = pkt_write_head (out, old_ctb, size, CDK_PKT_LITERAL);
729 if (rc)
730 return rc;
731
732 rc = stream_putc (out, pt->mode);
733 if (rc)
734 return rc;
735 rc = stream_putc (out, pt->namelen);
736 if (rc)
737 return rc;
738
739 if (pt->namelen > 0)
740 rc = stream_write (out, pt->name, pt->namelen);
741 if (!rc)
742 rc = write_32 (out, pt->timestamp);
743 if (rc)
744 return rc;
745
746 while (!cdk_stream_eof (pt->buf) && !rc)
747 {
748 rc = stream_read (pt->buf, buf, DIM (buf), &size);
749 if (!rc)
750 rc = stream_write (out, buf, size);
751 }
752
753 wipemem (buf, sizeof (buf));
754 return rc;
755}
756
757
758static cdk_error_t
759write_onepass_sig (cdk_stream_t out, cdk_pkt_onepass_sig_t sig)
760{
761 cdk_error_t rc;
762
763 assert (out);
764 assert (sig);
765
766 if (sig->version != 3)
767 return CDK_Inv_Packet;
768
769 if (DEBUG_PKT)
770 _cdk_log_debug ("write_onepass_sig:\n");
771
772 rc = pkt_write_head (out, 0, 13, CDK_PKT_ONEPASS_SIG);
773 if (!rc)
774 rc = stream_putc (out, sig->version);
775 if (!rc)
776 rc = stream_putc (out, sig->sig_class);
777 if (!rc)
778 rc = stream_putc (out, sig->digest_algo);
779 if (!rc)
780 rc = stream_putc (out, sig->pubkey_algo);
781 if (!rc)
782 rc = write_32 (out, sig->keyid[0]);
783 if (!rc)
784 rc = write_32 (out, sig->keyid[1]);
785 if (!rc)
786 rc = stream_putc (out, sig->last);
787 return rc;
788}
789
790
791static cdk_error_t
792write_user_id (cdk_stream_t out, cdk_pkt_userid_t id, int old_ctb,
793 int pkttype)
794{
795 cdk_error_t rc;
796
797 if (!out || !id)
798 return CDK_Inv_Value;
799
800 if (pkttype == CDK_PKT_ATTRIBUTE)
801 {
802 if (!id->attrib_img)
803 return CDK_Inv_Value;
804 rc =
805 pkt_write_head (out, old_ctb, id->attrib_len + 6, CDK_PKT_ATTRIBUTE);
806 if (rc)
807 return rc;
808 /* Write subpacket part. */
809 stream_putc (out, 255);
810 write_32 (out, id->attrib_len + 1);
811 stream_putc (out, 1);
812 rc = stream_write (out, id->attrib_img, id->attrib_len);
813 }
814 else
815 {
816 if (!id->name)
817 return CDK_Inv_Value;
818 rc = pkt_write_head (out, old_ctb, id->len, CDK_PKT_USER_ID);
819 if (!rc)
820 rc = stream_write (out, id->name, id->len);
821 }
822
823 return rc;
824}
825
826
827/**
828 * cdk_pkt_write:
829 * @out: the output stream handle
830 * @pkt: the packet itself
831 *
832 * Write the contents of @pkt into the @out stream.
833 * Return 0 on success.
834 **/
835cdk_error_t
836cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt)
837{
838 cdk_error_t rc;
839
840 if (!out || !pkt)
841 return CDK_Inv_Value;
842
843 _cdk_log_debug ("write packet pkttype=%d\n", pkt->pkttype);
844 switch (pkt->pkttype)
845 {
846 case CDK_PKT_LITERAL:
847 rc = write_literal (out, pkt->pkt.literal, pkt->old_ctb);
848 break;
849 case CDK_PKT_ONEPASS_SIG:
850 rc = write_onepass_sig (out, pkt->pkt.onepass_sig);
851 break;
852 case CDK_PKT_MDC:
853 rc = write_mdc (out, pkt->pkt.mdc);
854 break;
855 case CDK_PKT_SYMKEY_ENC:
856 rc = write_symkey_enc (out, pkt->pkt.symkey_enc);
857 break;
858 case CDK_PKT_ENCRYPTED:
859 rc = write_encrypted (out, pkt->pkt.encrypted, pkt->old_ctb);
860 break;
861 case CDK_PKT_ENCRYPTED_MDC:
862 rc = write_encrypted_mdc (out, pkt->pkt.encrypted);
863 break;
864 case CDK_PKT_PUBKEY_ENC:
865 rc = write_pubkey_enc (out, pkt->pkt.pubkey_enc, pkt->old_ctb);
866 break;
867 case CDK_PKT_SIGNATURE:
868 rc = write_signature (out, pkt->pkt.signature, pkt->old_ctb);
869 break;
870 case CDK_PKT_PUBLIC_KEY:
871 rc = write_public_key (out, pkt->pkt.public_key, 0, pkt->old_ctb);
872 break;
873 case CDK_PKT_PUBLIC_SUBKEY:
874 rc = write_public_key (out, pkt->pkt.public_key, 1, pkt->old_ctb);
875 break;
876 case CDK_PKT_COMPRESSED:
877 rc = write_compressed (out, pkt->pkt.compressed);
878 break;
879 case CDK_PKT_SECRET_KEY:
880 rc = write_secret_key (out, pkt->pkt.secret_key, 0, pkt->old_ctb);
881 break;
882 case CDK_PKT_SECRET_SUBKEY:
883 rc = write_secret_key (out, pkt->pkt.secret_key, 1, pkt->old_ctb);
884 break;
885 case CDK_PKT_USER_ID:
886 case CDK_PKT_ATTRIBUTE:
887 rc = write_user_id (out, pkt->pkt.user_id, pkt->old_ctb, pkt->pkttype);
888 break;
889 default:
890 rc = CDK_Inv_Packet;
891 break;
892 }
893
894 if (DEBUG_PKT)
895 _cdk_log_debug ("write_packet rc=%d pkttype=%d\n", rc, pkt->pkttype);
896 return rc;
897}
898
899
900cdk_error_t
901_cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx)
902{
903 cdk_packet_t pkt;
904 cdk_error_t rc;
905
906 rc = cdk_pkt_new (&pkt);
907 if (rc)
908 return rc;
909
910 switch (pkttype)
911 {
912 case CDK_PKT_PUBLIC_KEY:
913 case CDK_PKT_PUBLIC_SUBKEY:
914 pkt->pkt.public_key = pktctx;
915 break;
916 case CDK_PKT_SIGNATURE:
917 pkt->pkt.signature = pktctx;
918 break;
919 case CDK_PKT_SECRET_KEY:
920 case CDK_PKT_SECRET_SUBKEY:
921 pkt->pkt.secret_key = pktctx;
922 break;
923
924 case CDK_PKT_USER_ID:
925 pkt->pkt.user_id = pktctx;
926 break;
927 }
928 pkt->pkttype = pkttype;
929 rc = cdk_pkt_write (out, pkt);
930 cdk_free (pkt);
931 return rc;
932}
933
934
935cdk_error_t
936_cdk_pkt_write_fp (FILE * out, cdk_packet_t pkt)
937{
938 cdk_stream_t so;
939 cdk_error_t rc;
940
941 rc = _cdk_stream_fpopen (out, 1, &so);
942 if (rc)
943 return rc;
944 rc = cdk_pkt_write (so, pkt);
945 cdk_stream_close (so);
946 return rc;
947}