diff options
author | lv-426 <oxcafebaby@yahoo.com> | 2008-06-22 18:20:35 +0000 |
---|---|---|
committer | lv-426 <oxcafebaby@yahoo.com> | 2008-06-22 18:20:35 +0000 |
commit | a0339d2458867dbe9485499265641ff205063445 (patch) | |
tree | 055b38828b3696520408a32edf81df5bb37400f0 /src/daemon/https/opencdk | |
parent | 97c026da05495b83f1511906c2ca027e12ef6cf7 (diff) | |
download | libmicrohttpd-a0339d2458867dbe9485499265641ff205063445.tar.gz libmicrohttpd-a0339d2458867dbe9485499265641ff205063445.zip |
initial GNU TLS import - this should reduce in size considerable
Diffstat (limited to 'src/daemon/https/opencdk')
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 @@ | |||
1 | AM_CPPFLAGS = -I$(top_srcdir)/lib \ | ||
2 | -I$(top_srcdir)/lgl \ | ||
3 | -I$(GCRYPT_CPPFLAGS) | ||
4 | |||
5 | noinst_LTLIBRARIES = libopencdk.la | ||
6 | |||
7 | libopencdk_la_LDFLAGS = -lgcrypt | ||
8 | |||
9 | libopencdk_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 @@ | |||
1 | This is a stripped down mirror of the files in OpenCDK | ||
2 | src/. To avoid to link proc-packets.c, dummy.c is included. | ||
3 | |||
4 | In Makefile.am libminiopencdk_la_SOURCES contains the list | ||
5 | of 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 | |||
46 | static 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 | |||
113 | static 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 | |||
121 | static 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 | |||
129 | static const char *valid_headers[] = { | ||
130 | "Comment", | ||
131 | "Version", | ||
132 | "MessageID", | ||
133 | "Hash", | ||
134 | "Charset", | ||
135 | NULL | ||
136 | }; | ||
137 | |||
138 | static char b64chars[] = | ||
139 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
140 | |||
141 | static 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 */ | ||
154 | static int | ||
155 | base64_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. */ | ||
190 | static int | ||
191 | base64_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. */ | ||
239 | static int | ||
240 | compress_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 | |||
272 | static int | ||
273 | check_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 | |||
295 | static int | ||
296 | is_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 | |||
321 | static u32 | ||
322 | update_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 | |||
336 | static cdk_error_t | ||
337 | armor_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 | **/ | ||
398 | int | ||
399 | cdk_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 | |||
420 | static int | ||
421 | search_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 | |||
437 | const char * | ||
438 | _cdk_armor_get_lineend (void) | ||
439 | { | ||
440 | return LF; | ||
441 | } | ||
442 | |||
443 | |||
444 | static cdk_error_t | ||
445 | armor_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 | **/ | ||
566 | cdk_error_t | ||
567 | cdk_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 | **/ | ||
611 | cdk_error_t | ||
612 | cdk_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 | |||
653 | int | ||
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 | **/ | ||
686 | cdk_error_t | ||
687 | cdk_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 | |||
33 | static off_t | ||
34 | fp_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 | |||
44 | static cdk_error_t | ||
45 | hash_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 | |||
77 | cdk_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 | |||
97 | static cdk_error_t | ||
98 | write_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 | |||
183 | static cdk_error_t | ||
184 | write_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 | |||
207 | static inline int | ||
208 | num2bits (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 | |||
218 | static cdk_error_t | ||
219 | write_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 | |||
289 | static cdk_error_t | ||
290 | cipher_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 | |||
336 | static cdk_error_t | ||
337 | read_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 | |||
393 | static cdk_error_t | ||
394 | finalize_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 | |||
420 | static cdk_error_t | ||
421 | cipher_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 | |||
468 | static cdk_error_t | ||
469 | cipher_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 | |||
486 | static cdk_error_t | ||
487 | cipher_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 | |||
507 | cdk_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 | ||
31 | static int | ||
32 | compress_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 | |||
59 | static int | ||
60 | decompress_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 | |||
98 | static cdk_error_t | ||
99 | compress_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 | |||
143 | static cdk_error_t | ||
144 | compress_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 | |||
211 | cdk_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 | ||
233 | cdk_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 | |||
21 | struct 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 | |||
34 | struct cdk_s2k_s { | ||
35 | int mode; | ||
36 | byte hash_algo; | ||
37 | byte salt[8]; | ||
38 | u32 count; | ||
39 | }; | ||
40 | |||
41 | |||
42 | struct 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 | |||
79 | struct cdk_prefitem_s { | ||
80 | byte type; | ||
81 | byte value; | ||
82 | }; | ||
83 | |||
84 | struct 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 | |||
91 | struct cdk_subpkt_s { | ||
92 | struct cdk_subpkt_s * next; | ||
93 | u32 size; | ||
94 | byte type; | ||
95 | byte d[1]; | ||
96 | }; | ||
97 | |||
98 | struct 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 | |||
108 | struct cdk_dek_s { | ||
109 | int algo; | ||
110 | int keylen; | ||
111 | int use_mdc; | ||
112 | byte key[32]; /* 256-bit */ | ||
113 | }; | ||
114 | |||
115 | struct 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 | |||
9 | cdk_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 | |||
19 | enum { | ||
20 | STREAMCTL_READ = 0, | ||
21 | STREAMCTL_WRITE = 1, | ||
22 | STREAMCTL_FREE = 2 | ||
23 | }; | ||
24 | |||
25 | typedef 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 | |||
39 | typedef struct { | ||
40 | int digest_algo; | ||
41 | gcry_md_hd_t md; | ||
42 | } md_filter_t; | ||
43 | |||
44 | typedef 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 | |||
52 | typedef 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 | |||
63 | typedef 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 | |||
72 | typedef struct { | ||
73 | const char * lf; | ||
74 | } text_filter_t; | ||
75 | |||
76 | |||
77 | /*-- armor.c -*/ | ||
78 | int _cdk_filter_armor( void * opaque, int ctl, FILE * in, FILE * out ); | ||
79 | |||
80 | /*-- cipher.c --*/ | ||
81 | cdk_error_t _cdk_filter_hash( void * opaque, int ctl, FILE * in, FILE * out ); | ||
82 | cdk_error_t _cdk_filter_cipher( void * opaque, int ctl, | ||
83 | FILE * in, FILE * out ); | ||
84 | |||
85 | /*-- literal.c --*/ | ||
86 | int _cdk_filter_literal( void * opaque, int ctl, FILE * in, FILE * out ); | ||
87 | int _cdk_filter_text( void * opaque, int ctl, FILE * in, FILE * out ); | ||
88 | |||
89 | /*-- compress.c --*/ | ||
90 | cdk_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 | **/ | ||
36 | cdk_kbnode_t | ||
37 | cdk_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 | |||
49 | void | ||
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 | **/ | ||
65 | void | ||
66 | cdk_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 | **/ | ||
87 | void | ||
88 | cdk_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! */ | ||
96 | void | ||
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 | **/ | ||
116 | void | ||
117 | cdk_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 | **/ | ||
151 | cdk_kbnode_t | ||
152 | cdk_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 | **/ | ||
177 | cdk_kbnode_t | ||
178 | cdk_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 | **/ | ||
207 | cdk_kbnode_t | ||
208 | cdk_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 | **/ | ||
226 | cdk_packet_t | ||
227 | cdk_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 | */ | ||
242 | cdk_kbnode_t | ||
243 | cdk_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 | */ | ||
274 | int | ||
275 | cdk_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 | */ | ||
307 | void | ||
308 | cdk_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 | */ | ||
339 | void | ||
340 | cdk_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 | **/ | ||
375 | cdk_packet_t | ||
376 | cdk_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 | **/ | ||
392 | cdk_error_t | ||
393 | cdk_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 | */ | ||
420 | cdk_error_t | ||
421 | cdk_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 | **/ | ||
478 | cdk_error_t | ||
479 | cdk_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 | **/ | ||
542 | cdk_error_t | ||
543 | cdk_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. */ | ||
38 | struct key_idx_s | ||
39 | { | ||
40 | off_t offset; | ||
41 | u32 keyid[2]; | ||
42 | byte fpr[KEY_FPR_LEN]; | ||
43 | }; | ||
44 | typedef struct key_idx_s *key_idx_t; | ||
45 | |||
46 | |||
47 | /* Internal handle for the search operation. */ | ||
48 | struct 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 | }; | ||
58 | typedef struct cdk_dbsearch_s *cdk_dbsearch_t; | ||
59 | |||
60 | /* Internal key cache to associate a key with an file offset. */ | ||
61 | struct key_table_s | ||
62 | { | ||
63 | struct key_table_s *next; | ||
64 | off_t offset; | ||
65 | cdk_dbsearch_t desc; | ||
66 | }; | ||
67 | typedef struct key_table_s *key_table_t; | ||
68 | |||
69 | /* Internal key database handle. */ | ||
70 | struct 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 | |||
94 | static void keydb_cache_free (key_table_t cache); | ||
95 | static int keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src); | ||
96 | static void keydb_search_free (cdk_dbsearch_t dbs); | ||
97 | static int classify_data (const byte * buf, size_t len); | ||
98 | static cdk_kbnode_t find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk); | ||
99 | |||
100 | |||
101 | static char * | ||
102 | keydb_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 | */ | ||
126 | static cdk_error_t | ||
127 | keydb_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 | **/ | ||
196 | cdk_error_t | ||
197 | cdk_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 | |||
234 | static cdk_error_t | ||
235 | keydb_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 | |||
264 | static cdk_error_t | ||
265 | keydb_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 | */ | ||
308 | cdk_error_t | ||
309 | cdk_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 | */ | ||
344 | cdk_error_t | ||
345 | cdk_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 | |||
367 | cdk_error_t | ||
368 | cdk_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 | **/ | ||
399 | cdk_error_t | ||
400 | cdk_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 | **/ | ||
428 | void | ||
429 | cdk_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 | |||
463 | cdk_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 | |||
531 | leave: | ||
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 | |||
542 | static int | ||
543 | find_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 | |||
578 | static int | ||
579 | find_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 | |||
605 | static int | ||
606 | find_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 | |||
646 | static void | ||
647 | keydb_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 | |||
658 | static void | ||
659 | keydb_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 | |||
674 | static key_table_t | ||
675 | keydb_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 | |||
713 | static cdk_error_t | ||
714 | keydb_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 | |||
736 | static cdk_error_t | ||
737 | keydb_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 | **/ | ||
781 | cdk_error_t | ||
782 | cdk_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 | |||
897 | static cdk_error_t | ||
898 | keydb_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 | **/ | ||
954 | cdk_error_t | ||
955 | cdk_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 | |||
1042 | cdk_error_t | ||
1043 | cdk_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 | |||
1057 | cdk_error_t | ||
1058 | cdk_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 | |||
1073 | cdk_error_t | ||
1074 | cdk_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 | |||
1089 | static int | ||
1090 | keydb_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. */ | ||
1118 | static cdk_kbnode_t | ||
1119 | kbnode_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 | |||
1135 | static cdk_kbnode_t | ||
1136 | keydb_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 | |||
1179 | static cdk_kbnode_t | ||
1180 | keydb_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 | |||
1198 | cdk_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 | |||
1268 | cdk_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 | **/ | ||
1338 | cdk_error_t | ||
1339 | cdk_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 | **/ | ||
1388 | cdk_error_t | ||
1389 | cdk_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 | |||
1424 | static int | ||
1425 | is_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. */ | ||
1442 | static cdk_kbnode_t | ||
1443 | find_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 | |||
1466 | static cdk_error_t | ||
1467 | keydb_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 | |||
1588 | static cdk_error_t | ||
1589 | keydb_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 | |||
1745 | cdk_error_t | ||
1746 | cdk_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. */ | ||
1866 | static int | ||
1867 | classify_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 | **/ | ||
1919 | cdk_error_t | ||
1920 | cdk_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 | |||
1976 | static cdk_packet_t | ||
1977 | find_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. */ | ||
1993 | static int | ||
1994 | is_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 | |||
2015 | cdk_error_t | ||
2016 | cdk_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 | |||
2087 | cdk_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 | **/ | ||
2136 | cdk_error_t | ||
2137 | cdk_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 | **/ | ||
2186 | cdk_error_t | ||
2187 | cdk_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 | **/ | ||
2231 | void | ||
2232 | cdk_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 | **/ | ||
2252 | cdk_error_t | ||
2253 | cdk_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 | |||
2299 | int | ||
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. */ | ||
29 | static char * | ||
30 | dup_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 | |||
43 | static cdk_error_t | ||
44 | literal_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 | |||
148 | static char | ||
149 | intmode_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 | |||
167 | static cdk_error_t | ||
168 | literal_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 | |||
219 | int | ||
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 | |||
243 | static int | ||
244 | text_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 | |||
266 | static int | ||
267 | text_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 | |||
290 | int | ||
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. */ | ||
44 | static void *(*alloc_func) (size_t n) = gcry_xmalloc; | ||
45 | static void *(*alloc_secure_func) (size_t n) = gcry_malloc_secure; | ||
46 | static void *(*realloc_func) (void *p, size_t n) = gcry_realloc; | ||
47 | static void *(*calloc_func) (size_t m, size_t n) = gcry_calloc; | ||
48 | static void (*free_func) (void *) = gcry_free; | ||
49 | static int malloc_hooks = 0; | ||
50 | static int secmem_init = 0; | ||
51 | |||
52 | /* Global settings for the logging. */ | ||
53 | static cdk_log_fnc_t log_handler = NULL; | ||
54 | static void *log_handler_value = NULL; | ||
55 | static 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 | **/ | ||
64 | const char * | ||
65 | cdk_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 | |||
137 | static void | ||
138 | out_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 | */ | ||
154 | void | ||
155 | cdk_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 | **/ | ||
175 | int | ||
176 | cdk_malloc_hook_initialized (void) | ||
177 | { | ||
178 | return malloc_hooks; | ||
179 | } | ||
180 | |||
181 | |||
182 | void * | ||
183 | cdk_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 | **/ | ||
199 | void * | ||
200 | cdk_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. */ | ||
210 | static void | ||
211 | _secmem_finish (void) | ||
212 | { | ||
213 | gcry_control (GCRYCTL_DROP_PRIVS); | ||
214 | } | ||
215 | |||
216 | |||
217 | /* Initialize the secure memory. */ | ||
218 | static 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. */ | ||
240 | static 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 | ||
251 | static void | ||
252 | init_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 | |||
265 | static void | ||
266 | deinit_sockets (void) | ||
267 | { | ||
268 | WSACleanup (); | ||
269 | } | ||
270 | #else | ||
271 | void | ||
272 | init_sockets (void) | ||
273 | { | ||
274 | } | ||
275 | void | ||
276 | deinit_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 | */ | ||
288 | void | ||
289 | cdk_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 | */ | ||
304 | void | ||
305 | cdk_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 | */ | ||
318 | void * | ||
319 | cdk_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 | |||
335 | void * | ||
336 | cdk_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 | |||
345 | char * | ||
346 | cdk_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 | |||
355 | void | ||
356 | cdk_free (void *ptr) | ||
357 | { | ||
358 | if (ptr) | ||
359 | free_func (ptr); | ||
360 | } | ||
361 | |||
362 | |||
363 | /* Internal logging routine. */ | ||
364 | static 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 | **/ | ||
388 | void | ||
389 | cdk_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 | **/ | ||
402 | void | ||
403 | cdk_set_log_level (int level) | ||
404 | { | ||
405 | log_level = level; | ||
406 | } | ||
407 | |||
408 | |||
409 | /* Return the current log level of the lib. */ | ||
410 | int | ||
411 | _cdk_get_log_level (void) | ||
412 | { | ||
413 | return log_level; | ||
414 | } | ||
415 | |||
416 | |||
417 | void | ||
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 | |||
430 | void | ||
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. */ | ||
445 | char * | ||
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 | |||
454 | static void | ||
455 | handle_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 | |||
465 | static void | ||
466 | handle_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 | |||
476 | static void | ||
477 | handle_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 | |||
493 | static void | ||
494 | handle_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 | **/ | ||
521 | int | ||
522 | cdk_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 | **/ | ||
616 | cdk_error_t | ||
617 | cdk_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 | */ | ||
659 | cdk_error_t | ||
660 | cdk_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 | **/ | ||
687 | void | ||
688 | cdk_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 | **/ | ||
707 | cdk_keydb_hd_t | ||
708 | cdk_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 | **/ | ||
728 | void | ||
729 | cdk_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 | **/ | ||
747 | cdk_verify_result_t | ||
748 | cdk_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 | **/ | ||
760 | void | ||
761 | cdk_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 --*/ | ||
69 | const char * _cdk_armor_get_lineend (void); | ||
70 | |||
71 | /*-- main.c --*/ | ||
72 | int _cdk_get_log_level (void); | ||
73 | void _cdk_log_info (const char * fmt, ...); | ||
74 | void _cdk_log_debug (const char * fmt, ...); | ||
75 | char * _cdk_passphrase_get (cdk_ctx_t hd, const char *prompt); | ||
76 | |||
77 | /*-- misc.c --*/ | ||
78 | int _cdk_check_args( int overwrite, const char * in, const char * out ); | ||
79 | u32 _cdk_buftou32 (const byte * buf); | ||
80 | void _cdk_u32tobuf (u32 u, byte * buf); | ||
81 | const char *_cdk_memistr (const char * buf, size_t buflen, const char * sub); | ||
82 | cdk_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 --*/ | ||
90 | cdk_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); | ||
94 | cdk_error_t _cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx); | ||
95 | |||
96 | /*-- pubkey.c --*/ | ||
97 | u32 _cdk_pkt_get_keyid (cdk_packet_t pkt, u32 * keyid); | ||
98 | cdk_error_t _cdk_pkt_get_fingerprint (cdk_packet_t pkt, byte *fpr); | ||
99 | int _cdk_pk_algo_usage (int algo); | ||
100 | int _cdk_pk_test_algo (int algo, unsigned int usage); | ||
101 | int _cdk_sk_get_csum (cdk_pkt_seckey_t sk); | ||
102 | |||
103 | /*-- new-packet.c --*/ | ||
104 | byte * _cdk_subpkt_get_array (cdk_subpkt_t s, int count, size_t * r_nbytes); | ||
105 | cdk_error_t _cdk_subpkt_copy (cdk_subpkt_t * r_dst, cdk_subpkt_t src); | ||
106 | void _cdk_pkt_detach_free (cdk_packet_t pkt, int *r_pkttype, void **ctx); | ||
107 | |||
108 | /*-- sig-check.c --*/ | ||
109 | cdk_error_t _cdk_sig_check (cdk_pkt_pubkey_t pk, cdk_pkt_signature_t sig, | ||
110 | gcry_md_hd_t digest, int * r_expired); | ||
111 | cdk_error_t _cdk_hash_sig_data (cdk_pkt_signature_t sig, gcry_md_hd_t hd); | ||
112 | cdk_error_t _cdk_hash_userid (cdk_pkt_userid_t uid, int sig_version, gcry_md_hd_t md); | ||
113 | cdk_error_t _cdk_hash_pubkey (cdk_pkt_pubkey_t pk, gcry_md_hd_t md, | ||
114 | int use_fpr); | ||
115 | cdk_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 --*/ | ||
120 | void _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node); | ||
121 | void _cdk_kbnode_clone (cdk_kbnode_t node); | ||
122 | |||
123 | /*-- sesskey.c --*/ | ||
124 | cdk_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); | ||
128 | cdk_error_t _cdk_sk_unprotect_auto (cdk_ctx_t hd, cdk_pkt_seckey_t sk); | ||
129 | |||
130 | /*-- keydb.c --*/ | ||
131 | int _cdk_keydb_is_secret (cdk_keydb_hd_t db); | ||
132 | cdk_error_t _cdk_keydb_get_pk_byusage (cdk_keydb_hd_t hd, const char * name, | ||
133 | cdk_pkt_pubkey_t * ret_pk, int usage); | ||
134 | cdk_error_t _cdk_keydb_get_sk_byusage (cdk_keydb_hd_t hd, const char * name, | ||
135 | cdk_pkt_seckey_t * ret_sk, int usage); | ||
136 | cdk_error_t _cdk_keydb_check_userid (cdk_keydb_hd_t hd, u32 * keyid, | ||
137 | const char * id); | ||
138 | |||
139 | /*-- sign.c --*/ | ||
140 | int _cdk_sig_hash_for (cdk_pkt_pubkey_t pk); | ||
141 | void _cdk_trim_string (char * s, int canon); | ||
142 | cdk_error_t _cdk_sig_create (cdk_pkt_pubkey_t pk, cdk_pkt_signature_t sig); | ||
143 | cdk_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 --*/ | ||
147 | void _cdk_stream_set_compress_algo (cdk_stream_t s, int algo); | ||
148 | cdk_error_t _cdk_stream_open_mode (const char *file, const char *mode, | ||
149 | cdk_stream_t *ret_s); | ||
150 | void * _cdk_stream_get_opaque( cdk_stream_t s, int fid ); | ||
151 | const char * _cdk_stream_get_fname( cdk_stream_t s ); | ||
152 | FILE * _cdk_stream_get_fp( cdk_stream_t s ); | ||
153 | int _cdk_stream_gets( cdk_stream_t s, char * buf, size_t count ); | ||
154 | cdk_error_t _cdk_stream_append( const char * file, cdk_stream_t * ret_s ); | ||
155 | int _cdk_stream_get_errno( cdk_stream_t s ); | ||
156 | cdk_error_t _cdk_stream_set_blockmode( cdk_stream_t s, size_t nbytes ); | ||
157 | int _cdk_stream_get_blockmode( cdk_stream_t s ); | ||
158 | int _cdk_stream_puts( cdk_stream_t s, const char * buf ); | ||
159 | cdk_error_t _cdk_stream_fpopen (FILE * fp, unsigned write_mode, | ||
160 | cdk_stream_t *ret_out); | ||
161 | |||
162 | /*-- verify.c --*/ | ||
163 | void _cdk_result_verify_free (cdk_verify_result_t res); | ||
164 | cdk_verify_result_t _cdk_result_verify_new (void); | ||
165 | |||
166 | |||
167 | /*-- read-packet.c --*/ | ||
168 | size_t _cdk_pkt_read_len (FILE * inp, size_t *ret_partial); | ||
169 | |||
170 | /*-- write-packet.c --*/ | ||
171 | cdk_error_t _cdk_pkt_write_fp( FILE * out, cdk_packet_t pkt ); | ||
172 | |||
173 | /*-- seskey.c --*/ | ||
174 | cdk_error_t _cdk_s2k_copy (cdk_s2k_t *r_dst, cdk_s2k_t src); | ||
175 | |||
176 | cdk_error_t cdk_dek_encode_pkcs1 (cdk_dek_t dek, size_t nbits, | ||
177 | gcry_mpi_t *r_enc); | ||
178 | cdk_error_t cdk_dek_decode_pkcs1 (cdk_dek_t * ret_dek, gcry_mpi_t esk); | ||
179 | cdk_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 | |||
29 | u32 | ||
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 | |||
44 | void | ||
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 | |||
56 | static const char * | ||
57 | parse_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 | |||
74 | static const char * | ||
75 | parse_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 | **/ | ||
101 | const char * | ||
102 | cdk_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 | **/ | ||
136 | void | ||
137 | cdk_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 | **/ | ||
156 | cdk_strlist_t | ||
157 | cdk_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 | **/ | ||
182 | cdk_strlist_t | ||
183 | cdk_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 | |||
196 | const 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 | **/ | ||
227 | char * | ||
228 | cdk_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 | **/ | ||
267 | char * | ||
268 | cdk_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. */ | ||
467 | cdk_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. */ | ||
501 | void | ||
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 | |||
514 | int | ||
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 | |||
532 | FILE * | ||
533 | my_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 | ||
566 | FILE * | ||
567 | my_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. */ | ||
29 | void | ||
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 | **/ | ||
46 | cdk_error_t | ||
47 | cdk_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 | |||
61 | static void | ||
62 | free_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 | |||
71 | static void | ||
72 | free_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 | |||
85 | static void | ||
86 | free_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 | |||
96 | void | ||
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 | |||
110 | void | ||
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 | |||
136 | void | ||
137 | cdk_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 | |||
154 | void | ||
155 | cdk_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 | |||
174 | static void | ||
175 | free_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. */ | ||
191 | void | ||
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 | |||
221 | void | ||
222 | cdk_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 | **/ | ||
283 | void | ||
284 | cdk_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 | **/ | ||
300 | cdk_error_t | ||
301 | cdk_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 | |||
388 | cdk_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 | |||
413 | cdk_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 | |||
436 | cdk_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 | |||
462 | cdk_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 | |||
499 | cdk_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 | |||
519 | cdk_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 | |||
541 | cdk_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 | **/ | ||
571 | void | ||
572 | cdk_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 | **/ | ||
593 | cdk_subpkt_t | ||
594 | cdk_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 | **/ | ||
606 | size_t | ||
607 | cdk_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 | **/ | ||
631 | cdk_subpkt_t | ||
632 | cdk_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 | **/ | ||
654 | cdk_subpkt_t | ||
655 | cdk_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 | **/ | ||
677 | const byte * | ||
678 | cdk_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 | **/ | ||
696 | cdk_error_t | ||
697 | cdk_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 | |||
710 | byte * | ||
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 | |||
774 | cdk_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 | **/ | ||
811 | void | ||
812 | cdk_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. */ | ||
824 | const byte * | ||
825 | cdk_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 | **/ | ||
860 | cdk_subpkt_t | ||
861 | cdk_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 | ||
34 | extern "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. */ | ||
44 | struct cdk_ctx_s; | ||
45 | typedef struct cdk_ctx_s *cdk_ctx_t; | ||
46 | |||
47 | /* A generic context to store list of strings. */ | ||
48 | struct cdk_strlist_s; | ||
49 | typedef struct cdk_strlist_s *cdk_strlist_t; | ||
50 | |||
51 | /* Context used to list keys of a keyring. */ | ||
52 | struct cdk_listkey_s; | ||
53 | typedef struct cdk_listkey_s *cdk_listkey_t; | ||
54 | |||
55 | /* Opaque Data Encryption Key (DEK) context. */ | ||
56 | struct cdk_dek_s; | ||
57 | typedef struct cdk_dek_s *cdk_dek_t; | ||
58 | |||
59 | /* Opaque String to Key (S2K) handle. */ | ||
60 | struct cdk_s2k_s; | ||
61 | typedef struct cdk_s2k_s *cdk_s2k_t; | ||
62 | |||
63 | /* Abstract I/O object, a stream, which is used for most operations. */ | ||
64 | struct cdk_stream_s; | ||
65 | typedef struct cdk_stream_s *cdk_stream_t; | ||
66 | |||
67 | /* Opaque handle for the user ID preferences. */ | ||
68 | struct cdk_prefitem_s; | ||
69 | typedef struct cdk_prefitem_s *cdk_prefitem_t; | ||
70 | |||
71 | /* Node to store a single key node packet. */ | ||
72 | struct cdk_kbnode_s; | ||
73 | typedef struct cdk_kbnode_s *cdk_kbnode_t; | ||
74 | |||
75 | /* Key database handle. */ | ||
76 | struct cdk_keydb_hd_s; | ||
77 | typedef struct cdk_keydb_hd_s *cdk_keydb_hd_t; | ||
78 | |||
79 | /* Context to store a list of recipient keys. */ | ||
80 | struct cdk_keylist_s; | ||
81 | typedef struct cdk_keylist_s *cdk_keylist_t; | ||
82 | |||
83 | /* Context to encapsulate a single sub packet of a signature. */ | ||
84 | struct cdk_subpkt_s; | ||
85 | typedef struct cdk_subpkt_s *cdk_subpkt_t; | ||
86 | |||
87 | /* Context used to generate key pairs. */ | ||
88 | struct cdk_keygen_ctx_s; | ||
89 | typedef struct cdk_keygen_ctx_s *cdk_keygen_ctx_t; | ||
90 | |||
91 | /* Handle for a single designated revoker. */ | ||
92 | struct cdk_desig_revoker_s; | ||
93 | typedef struct cdk_desig_revoker_s *cdk_desig_revoker_t; | ||
94 | |||
95 | /* Alias for backward compatibility. */ | ||
96 | typedef gcry_mpi_t cdk_mpi_t; | ||
97 | |||
98 | |||
99 | /* All valid error constants. */ | ||
100 | typedef 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 | |||
133 | enum 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. */ | ||
149 | enum 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 */ | ||
158 | enum 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 */ | ||
167 | enum 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. */ | ||
177 | enum 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 */ | ||
190 | enum 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 */ | ||
204 | enum 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. */ | ||
212 | enum 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. */ | ||
221 | enum 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. */ | ||
248 | enum 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 | |||
256 | enum 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() */ | ||
274 | enum 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. */ | ||
286 | enum 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. */ | ||
294 | enum 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 */ | ||
304 | enum 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. */ | ||
320 | enum 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. */ | ||
337 | typedef 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. */ | ||
345 | typedef 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 */ | ||
352 | typedef 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 | |||
389 | struct 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 | }; | ||
416 | typedef struct cdk_pkt_signature_s *cdk_pkt_signature_t; | ||
417 | |||
418 | |||
419 | struct 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 | }; | ||
431 | typedef struct cdk_pkt_userid_s *cdk_pkt_userid_t; | ||
432 | |||
433 | |||
434 | struct 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 | }; | ||
452 | typedef struct cdk_pkt_pubkey_s *cdk_pkt_pubkey_t; | ||
453 | |||
454 | /* Alias to define a generic public key context. */ | ||
455 | typedef cdk_pkt_pubkey_t cdk_pubkey_t; | ||
456 | |||
457 | |||
458 | struct 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 | }; | ||
482 | typedef struct cdk_pkt_seckey_s *cdk_pkt_seckey_t; | ||
483 | |||
484 | /* Alias to define a generic secret key context. */ | ||
485 | typedef cdk_pkt_seckey_t cdk_seckey_t; | ||
486 | |||
487 | |||
488 | struct 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 | }; | ||
496 | typedef struct cdk_pkt_onepass_sig_s * cdk_pkt_onepass_sig_t; | ||
497 | |||
498 | |||
499 | struct 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 | }; | ||
506 | typedef struct cdk_pkt_pubkey_enc_s * cdk_pkt_pubkey_enc_t; | ||
507 | |||
508 | |||
509 | struct 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 | }; | ||
516 | typedef struct cdk_pkt_symkey_enc_s *cdk_pkt_symkey_enc_t; | ||
517 | |||
518 | |||
519 | struct cdk_pkt_encrypted_s { | ||
520 | unsigned int len; | ||
521 | int extralen; | ||
522 | unsigned char mdc_method; | ||
523 | cdk_stream_t buf; | ||
524 | }; | ||
525 | typedef struct cdk_pkt_encrypted_s *cdk_pkt_encrypted_t; | ||
526 | |||
527 | |||
528 | struct cdk_pkt_mdc_s { | ||
529 | unsigned char hash[20]; | ||
530 | }; | ||
531 | typedef struct cdk_pkt_mdc_s *cdk_pkt_mdc_t; | ||
532 | |||
533 | |||
534 | struct 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 | }; | ||
542 | typedef struct cdk_pkt_literal_s *cdk_pkt_literal_t; | ||
543 | |||
544 | |||
545 | struct cdk_pkt_compressed_s { | ||
546 | unsigned int len; | ||
547 | int algorithm; | ||
548 | cdk_stream_t buf; | ||
549 | }; | ||
550 | typedef struct cdk_pkt_compressed_s *cdk_pkt_compressed_t; | ||
551 | |||
552 | |||
553 | /* Structure which represents a single OpenPGP packet. */ | ||
554 | struct 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 | }; | ||
573 | typedef struct cdk_packet_s *cdk_packet_t; | ||
574 | |||
575 | /* memory routines */ | ||
576 | typedef void (*cdk_log_fnc_t) (void *, int, const char *, va_list); | ||
577 | |||
578 | /* Set the log level. */ | ||
579 | void cdk_set_log_level (int lvl); | ||
580 | |||
581 | /* Set a custom log handler which is used for logging. */ | ||
582 | void cdk_set_log_handler (cdk_log_fnc_t logfnc, void *opaque); | ||
583 | |||
584 | /* Return a human readable error description of the given error coe. */ | ||
585 | const 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. */ | ||
591 | void 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. */ | ||
598 | int cdk_malloc_hook_initialized (void); | ||
599 | |||
600 | /* Standard memory wrapper. */ | ||
601 | void *cdk_malloc (size_t size); | ||
602 | void *cdk_calloc (size_t n, size_t m); | ||
603 | void *cdk_realloc (void * ptr, size_t size); | ||
604 | void *cdk_salloc (size_t size, int clear); | ||
605 | char *cdk_strdup (const char * ptr); | ||
606 | void cdk_free (void * ptr); | ||
607 | |||
608 | /* Startup routines. */ | ||
609 | |||
610 | /* This function has to be called before any other | ||
611 | CDK function is executed. */ | ||
612 | void 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. */ | ||
616 | void cdk_lib_shutdown (void); | ||
617 | |||
618 | /* Session handle routines */ | ||
619 | cdk_error_t cdk_handle_new (cdk_ctx_t *r_ctx); | ||
620 | void 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. */ | ||
625 | void 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. */ | ||
630 | cdk_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. */ | ||
634 | cdk_keydb_hd_t cdk_handle_get_keydb (cdk_ctx_t hd, int type); | ||
635 | int cdk_handle_control (cdk_ctx_t hd, int action, int cmd, ...); | ||
636 | |||
637 | /* Set a passphrase callback for the given session handle. */ | ||
638 | void 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. */ | ||
672 | struct 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 | }; | ||
686 | typedef struct cdk_verify_result_s *cdk_verify_result_t; | ||
687 | |||
688 | /* Return the verify result. Do not free the data. */ | ||
689 | cdk_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. */ | ||
694 | cdk_error_t cdk_pkt_new (cdk_packet_t *r_pkt); | ||
695 | cdk_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. */ | ||
698 | void cdk_pkt_free (cdk_packet_t pkt); | ||
699 | |||
700 | /* Release the packet contents and the packet structure @PKT itself. */ | ||
701 | void cdk_pkt_release (cdk_packet_t pkt); | ||
702 | |||
703 | /* Read or write the given output from or to the stream. */ | ||
704 | cdk_error_t cdk_pkt_read (cdk_stream_t inp, cdk_packet_t pkt); | ||
705 | cdk_error_t cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt); | ||
706 | |||
707 | /* Sub packet routines */ | ||
708 | cdk_subpkt_t cdk_subpkt_new (size_t size); | ||
709 | void cdk_subpkt_free (cdk_subpkt_t ctx); | ||
710 | cdk_subpkt_t cdk_subpkt_find (cdk_subpkt_t ctx, size_t type); | ||
711 | cdk_subpkt_t cdk_subpkt_find_next (cdk_subpkt_t root, size_t type); | ||
712 | size_t cdk_subpkt_type_count (cdk_subpkt_t ctx, size_t type); | ||
713 | cdk_subpkt_t cdk_subpkt_find_nth (cdk_subpkt_t ctx, size_t type, size_t index); | ||
714 | cdk_error_t cdk_subpkt_add (cdk_subpkt_t root, cdk_subpkt_t node); | ||
715 | const unsigned char * cdk_subpkt_get_data (cdk_subpkt_t ctx, | ||
716 | size_t * r_type, size_t *r_nbytes); | ||
717 | void cdk_subpkt_init (cdk_subpkt_t node, size_t type, | ||
718 | const void *buf, size_t buflen); | ||
719 | |||
720 | /* Designated Revoker routines */ | ||
721 | const 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. */ | ||
733 | cdk_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. */ | ||
738 | cdk_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. */ | ||
743 | cdk_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. */ | ||
748 | cdk_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. */ | ||
757 | cdk_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. */ | ||
762 | cdk_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. */ | ||
768 | int cdk_pk_get_nbits (cdk_pubkey_t pk); | ||
769 | int cdk_pk_get_npkey (int algo); | ||
770 | int cdk_pk_get_nskey (int algo); | ||
771 | int cdk_pk_get_nsig (int algo); | ||
772 | int 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. */ | ||
778 | cdk_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. */ | ||
781 | cdk_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. */ | ||
787 | unsigned 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. */ | ||
792 | unsigned int cdk_pk_get_keyid (cdk_pubkey_t pk, unsigned int *keyid); | ||
793 | unsigned int cdk_sk_get_keyid (cdk_seckey_t sk, unsigned int *keyid); | ||
794 | unsigned int cdk_sig_get_keyid (cdk_pkt_signature_t sig, | ||
795 | unsigned int *keyid); | ||
796 | |||
797 | /* Key release functions. */ | ||
798 | void cdk_pk_release (cdk_pubkey_t pk); | ||
799 | void cdk_sk_release (cdk_seckey_t sk); | ||
800 | |||
801 | /* Secret key related functions. */ | ||
802 | cdk_error_t cdk_sk_unprotect (cdk_seckey_t sk, const char *pw); | ||
803 | cdk_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. */ | ||
806 | cdk_error_t cdk_pk_from_secret_key (cdk_seckey_t sk, | ||
807 | cdk_pubkey_t *ret_pk); | ||
808 | |||
809 | /* Sexp conversion of keys. */ | ||
810 | cdk_error_t cdk_pubkey_to_sexp (cdk_pubkey_t pk, | ||
811 | char **sexp, size_t *len); | ||
812 | cdk_error_t cdk_seckey_to_sexp (cdk_seckey_t sk, | ||
813 | char **sexp, size_t *len); | ||
814 | |||
815 | |||
816 | /* Data Encryption Key (DEK) routines */ | ||
817 | cdk_error_t cdk_dek_new (cdk_dek_t *r_dek); | ||
818 | void cdk_dek_free (cdk_dek_t dek); | ||
819 | |||
820 | /* Set the symmetric cipher algorithm which shall be used for this | ||
821 | DEK object. */ | ||
822 | cdk_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. */ | ||
825 | cdk_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. */ | ||
831 | cdk_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. */ | ||
835 | void 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.*/ | ||
838 | int 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. */ | ||
842 | cdk_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. */ | ||
847 | cdk_error_t cdk_s2k_new (cdk_s2k_t *ret_s2k, int mode, int digest_algo, | ||
848 | const unsigned char *salt); | ||
849 | void cdk_s2k_free (cdk_s2k_t s2k); | ||
850 | |||
851 | cdk_error_t cdk_file_armor (cdk_ctx_t hd, const char *file, | ||
852 | const char *output); | ||
853 | cdk_error_t cdk_file_dearmor (const char * file, const char *output); | ||
854 | int 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. */ | ||
859 | cdk_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. */ | ||
867 | struct 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 | }; | ||
875 | typedef struct cdk_stream_cbs_s *cdk_stream_cbs_t; | ||
876 | |||
877 | |||
878 | int cdk_stream_is_compressed (cdk_stream_t s); | ||
879 | |||
880 | /* Return a stream object which is associated to a socket. */ | ||
881 | cdk_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. */ | ||
885 | cdk_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. */ | ||
889 | cdk_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. */ | ||
893 | cdk_error_t cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa, | ||
894 | cdk_stream_t *ret_s); | ||
895 | cdk_error_t cdk_stream_create (const char * file, cdk_stream_t * ret_s); | ||
896 | cdk_error_t cdk_stream_tmp_new (cdk_stream_t *r_out); | ||
897 | cdk_error_t cdk_stream_tmp_from_mem (const void * buf, size_t buflen, | ||
898 | cdk_stream_t *r_out); | ||
899 | void cdk_stream_tmp_set_mode (cdk_stream_t s, int val); | ||
900 | cdk_error_t cdk_stream_flush (cdk_stream_t s); | ||
901 | cdk_error_t cdk_stream_enable_cache (cdk_stream_t s, int val); | ||
902 | cdk_error_t cdk_stream_filter_disable (cdk_stream_t s, int type); | ||
903 | cdk_error_t cdk_stream_close (cdk_stream_t s); | ||
904 | off_t cdk_stream_get_length (cdk_stream_t s); | ||
905 | int cdk_stream_read (cdk_stream_t s, void * buf, size_t count); | ||
906 | int cdk_stream_write (cdk_stream_t s, const void * buf, size_t count); | ||
907 | int cdk_stream_putc (cdk_stream_t s, int c); | ||
908 | int cdk_stream_getc (cdk_stream_t s); | ||
909 | int cdk_stream_eof (cdk_stream_t s); | ||
910 | off_t cdk_stream_tell (cdk_stream_t s); | ||
911 | cdk_error_t cdk_stream_seek (cdk_stream_t s, off_t offset); | ||
912 | cdk_error_t cdk_stream_set_armor_flag (cdk_stream_t s, int type); | ||
913 | |||
914 | /* Push the literal filter for the given stream. */ | ||
915 | cdk_error_t cdk_stream_set_literal_flag (cdk_stream_t s, | ||
916 | cdk_lit_format_t mode, | ||
917 | const char * fname); | ||
918 | |||
919 | cdk_error_t cdk_stream_set_cipher_flag (cdk_stream_t s, cdk_dek_t dek, | ||
920 | int use_mdc); | ||
921 | cdk_error_t cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level); | ||
922 | cdk_error_t cdk_stream_set_hash_flag (cdk_stream_t s, int algo); | ||
923 | cdk_error_t cdk_stream_set_text_flag (cdk_stream_t s, const char * lf); | ||
924 | cdk_error_t cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out); | ||
925 | cdk_error_t cdk_stream_mmap (cdk_stream_t s, unsigned char **ret_buf, | ||
926 | size_t *ret_buflen); | ||
927 | cdk_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. */ | ||
932 | int 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. */ | ||
937 | cdk_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. */ | ||
941 | cdk_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. */ | ||
945 | cdk_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. */ | ||
951 | cdk_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. */ | ||
955 | cdk_error_t cdk_keydb_check_sk (cdk_keydb_hd_t hd, unsigned int *keyid); | ||
956 | |||
957 | /* Prepare the key db search. */ | ||
958 | cdk_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(). */ | ||
962 | cdk_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. */ | ||
965 | void 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. */ | ||
969 | cdk_error_t cdk_keydb_get_bykeyid (cdk_keydb_hd_t hd, unsigned int *keyid, | ||
970 | cdk_kbnode_t *ret_pk); | ||
971 | cdk_error_t cdk_keydb_get_byfpr (cdk_keydb_hd_t hd, const unsigned char *fpr, | ||
972 | cdk_kbnode_t *ret_pk); | ||
973 | cdk_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. */ | ||
979 | cdk_error_t cdk_keydb_get_pk (cdk_keydb_hd_t khd, unsigned int * keyid, | ||
980 | cdk_pubkey_t *ret_pk); | ||
981 | cdk_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. */ | ||
986 | cdk_error_t cdk_keydb_get_keyblock (cdk_stream_t inp, cdk_kbnode_t * ret_key); | ||
987 | |||
988 | /* Rebuild the key db index if possible. */ | ||
989 | cdk_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. */ | ||
994 | cdk_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. */ | ||
998 | cdk_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. */ | ||
1005 | cdk_error_t cdk_listkey_start (cdk_listkey_t *r_ctx, cdk_keydb_hd_t db, | ||
1006 | const char *patt, cdk_strlist_t fpatt); | ||
1007 | void cdk_listkey_close (cdk_listkey_t ctx); | ||
1008 | |||
1009 | /* Return the next key which matches the pattern. */ | ||
1010 | cdk_error_t cdk_listkey_next (cdk_listkey_t ctx, cdk_kbnode_t *ret_key); | ||
1011 | |||
1012 | cdk_kbnode_t cdk_kbnode_new (cdk_packet_t pkt); | ||
1013 | cdk_error_t cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node, | ||
1014 | const unsigned char * buf, | ||
1015 | size_t buflen); | ||
1016 | cdk_error_t cdk_kbnode_write_to_mem (cdk_kbnode_t node, | ||
1017 | unsigned char * buf, size_t * r_nbytes); | ||
1018 | cdk_error_t cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node, | ||
1019 | unsigned char **r_buf, | ||
1020 | size_t *r_buflen); | ||
1021 | |||
1022 | void cdk_kbnode_release (cdk_kbnode_t node); | ||
1023 | cdk_kbnode_t cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * ctx, int all); | ||
1024 | cdk_packet_t cdk_kbnode_find_packet (cdk_kbnode_t node, int pkttype); | ||
1025 | cdk_packet_t cdk_kbnode_get_packet (cdk_kbnode_t node); | ||
1026 | cdk_kbnode_t cdk_kbnode_find (cdk_kbnode_t node, int pkttype); | ||
1027 | cdk_kbnode_t cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node, | ||
1028 | int pkttype); | ||
1029 | cdk_kbnode_t cdk_kbnode_find_next (cdk_kbnode_t node, int pkttype); | ||
1030 | cdk_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. */ | ||
1035 | cdk_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. */ | ||
1039 | cdk_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. */ | ||
1043 | int 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. */ | ||
1047 | int cdk_pklist_use_mdc (cdk_keylist_t pkl); | ||
1048 | cdk_error_t cdk_pklist_build (cdk_keylist_t *ret_pkl, cdk_keydb_hd_t hd, | ||
1049 | cdk_strlist_t remusr, int use); | ||
1050 | void 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. */ | ||
1054 | cdk_error_t cdk_pklist_encrypt (cdk_keylist_t pkl, cdk_dek_t dek, | ||
1055 | cdk_stream_t out); | ||
1056 | |||
1057 | /* Secret key lists */ | ||
1058 | cdk_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); | ||
1062 | void cdk_sklist_release (cdk_keylist_t skl); | ||
1063 | cdk_error_t cdk_sklist_write (cdk_keylist_t skl, cdk_stream_t outp, | ||
1064 | gcry_md_hd_t mdctx, | ||
1065 | int sigclass, int sigver); | ||
1066 | cdk_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. */ | ||
1072 | cdk_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. */ | ||
1076 | cdk_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. */ | ||
1080 | cdk_error_t cdk_file_encrypt (cdk_ctx_t hd, cdk_strlist_t remusr, | ||
1081 | const char *file, const char *output); | ||
1082 | cdk_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. */ | ||
1089 | cdk_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. */ | ||
1099 | cdk_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. */ | ||
1104 | cdk_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 | |||
1109 | cdk_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. */ | ||
1116 | cdk_error_t cdk_file_verify (cdk_ctx_t hd, const char *file, | ||
1117 | const char *data_file, const char *output); | ||
1118 | |||
1119 | int cdk_trustdb_get_validity (cdk_stream_t inp, cdk_pkt_userid_t id, | ||
1120 | int *r_val); | ||
1121 | int cdk_trustdb_get_ownertrust (cdk_stream_t inp, cdk_pubkey_t pk, | ||
1122 | int *r_val, int *r_flags); | ||
1123 | |||
1124 | void cdk_strlist_free (cdk_strlist_t sl); | ||
1125 | cdk_strlist_t cdk_strlist_add (cdk_strlist_t * list, const char * string); | ||
1126 | cdk_strlist_t cdk_strlist_next (cdk_strlist_t root, const char **r_str); | ||
1127 | const char * cdk_check_version (const char * req_version); | ||
1128 | /* UTF8 */ | ||
1129 | char* cdk_utf8_encode (const char * string); | ||
1130 | char* 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. */ | ||
1134 | cdk_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 | |||
1138 | cdk_error_t cdk_keygen_new (cdk_keygen_ctx_t * r_hd); | ||
1139 | void 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. */ | ||
1143 | cdk_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); | ||
1146 | cdk_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); | ||
1149 | int cdk_keygen_set_keyserver_flags (cdk_keygen_ctx_t hd, int no_modify, | ||
1150 | const char *pref_url); | ||
1151 | int 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> */ | ||
1157 | void cdk_keygen_set_name (cdk_keygen_ctx_t hd, const char * name); | ||
1158 | void cdk_keygen_set_passphrase (cdk_keygen_ctx_t hd, const char * pass); | ||
1159 | cdk_error_t cdk_keygen_start (cdk_keygen_ctx_t hd); | ||
1160 | cdk_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 | |||
19 | struct 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 --*/ | ||
28 | void _cdk_free_mpibuf (size_t n, gcry_mpi_t *array); | ||
29 | void _cdk_free_userid (cdk_pkt_userid_t uid); | ||
30 | void _cdk_free_signature( cdk_pkt_signature_t sig ); | ||
31 | cdk_prefitem_t _cdk_copy_prefs( const cdk_prefitem_t prefs ); | ||
32 | int _cdk_copy_userid( cdk_pkt_userid_t *dst, cdk_pkt_userid_t src ); | ||
33 | int _cdk_copy_pubkey( cdk_pkt_pubkey_t* dst, cdk_pkt_pubkey_t src ); | ||
34 | int _cdk_copy_seckey( cdk_pkt_seckey_t* dst, cdk_pkt_seckey_t src ); | ||
35 | int _cdk_copy_pk_to_sk( cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk ); | ||
36 | int _cdk_copy_signature( cdk_pkt_signature_t* dst, cdk_pkt_signature_t src ); | ||
37 | int _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. */ | ||
29 | static int | ||
30 | seckey_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. */ | ||
74 | static cdk_error_t | ||
75 | pubkey_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 | |||
113 | static cdk_error_t | ||
114 | enckey_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 | |||
127 | static cdk_error_t | ||
128 | digest_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 | |||
154 | static cdk_error_t | ||
155 | sexp_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 | |||
174 | static cdk_error_t | ||
175 | sexp_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 | |||
202 | static cdk_error_t | ||
203 | sig_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 | |||
235 | static cdk_error_t | ||
236 | sexp_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 | |||
254 | static cdk_error_t | ||
255 | pubenc_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 | |||
284 | static int | ||
285 | is_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 | **/ | ||
302 | cdk_error_t | ||
303 | cdk_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 | **/ | ||
342 | cdk_error_t | ||
343 | cdk_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 | **/ | ||
388 | cdk_error_t | ||
389 | cdk_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 | **/ | ||
452 | cdk_error_t | ||
453 | cdk_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 | |||
483 | leave: | ||
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 | **/ | ||
501 | int | ||
502 | cdk_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 | */ | ||
517 | int | ||
518 | cdk_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 | **/ | ||
537 | int | ||
538 | cdk_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 | **/ | ||
555 | int | ||
556 | cdk_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 | **/ | ||
572 | int | ||
573 | cdk_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 | |||
583 | int | ||
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 | |||
613 | static cdk_error_t | ||
614 | mpi_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 | **/ | ||
644 | cdk_error_t | ||
645 | cdk_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 | **/ | ||
669 | cdk_error_t | ||
670 | cdk_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 | |||
682 | static u16 | ||
683 | checksum_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 | **/ | ||
707 | cdk_error_t | ||
708 | cdk_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 | **/ | ||
836 | cdk_error_t | ||
837 | cdk_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 | |||
922 | leave: | ||
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 | **/ | ||
935 | cdk_error_t | ||
936 | cdk_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. */ | ||
945 | cdk_error_t | ||
946 | cdk_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 | |||
1002 | int | ||
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 | **/ | ||
1026 | cdk_error_t | ||
1027 | cdk_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 | **/ | ||
1065 | cdk_error_t | ||
1066 | cdk_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 | **/ | ||
1106 | u32 | ||
1107 | cdk_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 | **/ | ||
1138 | u32 | ||
1139 | cdk_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 | **/ | ||
1182 | u32 | ||
1183 | cdk_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 | **/ | ||
1205 | u32 | ||
1206 | cdk_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 */ | ||
1221 | u32 | ||
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. */ | ||
1255 | int | ||
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 | **/ | ||
1289 | cdk_error_t | ||
1290 | cdk_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 | **/ | ||
1341 | cdk_error_t | ||
1342 | cdk_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 | |||
33 | static int | ||
34 | stream_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. */ | ||
42 | static u32 | ||
43 | read_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. */ | ||
58 | static u16 | ||
59 | read_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 | |||
73 | static int | ||
74 | read_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 | |||
112 | static cdk_error_t | ||
113 | read_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. */ | ||
157 | size_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 | |||
190 | static cdk_error_t | ||
191 | read_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 | |||
219 | static cdk_error_t | ||
220 | read_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 | |||
288 | static cdk_error_t | ||
289 | read_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 | |||
324 | static cdk_error_t | ||
325 | read_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 | |||
344 | static cdk_error_t | ||
345 | read_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 | |||
369 | static cdk_error_t | ||
370 | read_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 | |||
416 | static cdk_error_t | ||
417 | read_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 | |||
425 | static cdk_error_t | ||
426 | read_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 | |||
525 | static cdk_error_t | ||
526 | read_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 | |||
539 | static cdk_error_t | ||
540 | read_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 | |||
608 | static cdk_error_t | ||
609 | read_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 | |||
633 | static cdk_error_t | ||
634 | read_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 | |||
691 | static cdk_error_t | ||
692 | read_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 | |||
715 | static cdk_error_t | ||
716 | parse_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 | |||
786 | static cdk_error_t | ||
787 | read_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 | |||
877 | static cdk_error_t | ||
878 | read_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. */ | ||
921 | static void | ||
922 | read_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. */ | ||
950 | static void | ||
951 | read_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. */ | ||
980 | static void | ||
981 | skip_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 | **/ | ||
1003 | cdk_error_t | ||
1004 | cdk_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 | */ | ||
35 | static cdk_error_t | ||
36 | do_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 | **/ | ||
98 | cdk_error_t | ||
99 | cdk_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 | **/ | ||
174 | cdk_error_t | ||
175 | cdk_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. */ | ||
242 | cdk_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]) */ | ||
293 | static char * | ||
294 | passphrase_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. */ | ||
320 | cdk_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 | **/ | ||
352 | cdk_error_t | ||
353 | cdk_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 | **/ | ||
393 | cdk_error_t | ||
394 | cdk_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 | **/ | ||
416 | cdk_error_t | ||
417 | cdk_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 | |||
431 | cdk_error_t | ||
432 | cdk_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 | **/ | ||
453 | cdk_error_t | ||
454 | cdk_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 | **/ | ||
503 | void | ||
504 | cdk_dek_set_mdc_flag (cdk_dek_t dek, int val) | ||
505 | { | ||
506 | if (dek) | ||
507 | dek->use_mdc = val; | ||
508 | } | ||
509 | |||
510 | |||
511 | int | ||
512 | cdk_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 | **/ | ||
526 | void | ||
527 | cdk_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. */ | ||
540 | static cdk_error_t | ||
541 | hash_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 | */ | ||
625 | cdk_error_t | ||
626 | cdk_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 | **/ | ||
663 | cdk_error_t | ||
664 | cdk_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 | **/ | ||
696 | void | ||
697 | cdk_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. */ | ||
704 | cdk_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. */ | ||
32 | static int | ||
33 | hash_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. */ | ||
62 | cdk_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. */ | ||
109 | cdk_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. */ | ||
140 | cdk_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. */ | ||
196 | static void | ||
197 | cache_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. */ | ||
216 | cdk_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. */ | ||
254 | cdk_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 | } | ||
342 | fail: | ||
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 | **/ | ||
358 | cdk_error_t | ||
359 | cdk_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 | **/ | ||
440 | cdk_error_t | ||
441 | cdk_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 | |||
38 | static int stream_flush (cdk_stream_t s); | ||
39 | static int stream_filter_write (cdk_stream_t s); | ||
40 | static int stream_cache_flush (cdk_stream_t s, FILE * fp); | ||
41 | |||
42 | /* Customized tmpfile() version from misc.c */ | ||
43 | FILE *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 | **/ | ||
59 | cdk_error_t | ||
60 | cdk_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. */ | ||
67 | cdk_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 | */ | ||
110 | cdk_error_t | ||
111 | cdk_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 | **/ | ||
145 | cdk_error_t | ||
146 | cdk_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 | **/ | ||
191 | cdk_error_t | ||
192 | cdk_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 | */ | ||
231 | cdk_error_t | ||
232 | cdk_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 | */ | ||
247 | cdk_error_t | ||
248 | cdk_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 | |||
271 | cdk_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 | |||
292 | cdk_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 | */ | ||
320 | int | ||
321 | cdk_stream_is_compressed (cdk_stream_t s) | ||
322 | { | ||
323 | if (!s) | ||
324 | return 0; | ||
325 | return s->flags.compressed; | ||
326 | } | ||
327 | |||
328 | void | ||
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 | |||
337 | cdk_error_t | ||
338 | cdk_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 | |||
373 | void | ||
374 | cdk_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 | **/ | ||
391 | cdk_error_t | ||
392 | cdk_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 | **/ | ||
462 | int | ||
463 | cdk_stream_eof (cdk_stream_t s) | ||
464 | { | ||
465 | return s ? s->flags.eof : -1; | ||
466 | } | ||
467 | |||
468 | |||
469 | const 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. */ | ||
482 | FILE * | ||
483 | _cdk_stream_get_fp (cdk_stream_t s) | ||
484 | { | ||
485 | return s ? s->fp : NULL; | ||
486 | } | ||
487 | |||
488 | |||
489 | int | ||
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 | **/ | ||
503 | off_t | ||
504 | cdk_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 | |||
533 | static struct stream_filter_s * | ||
534 | filter_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 | |||
549 | static struct stream_filter_s * | ||
550 | filter_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 | |||
566 | struct stream_filter_s * | ||
567 | filter_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 | |||
612 | static int | ||
613 | stream_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 | |||
623 | static filter_fnct_t | ||
624 | stream_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 | **/ | ||
650 | cdk_error_t | ||
651 | cdk_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. */ | ||
670 | static cdk_error_t | ||
671 | stream_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. */ | ||
691 | static cdk_error_t | ||
692 | stream_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. */ | ||
749 | static cdk_error_t | ||
750 | stream_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 | |||
815 | void * | ||
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 | **/ | ||
842 | int | ||
843 | cdk_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 | |||
893 | int | ||
894 | cdk_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 | **/ | ||
924 | int | ||
925 | cdk_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 | |||
980 | int | ||
981 | cdk_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 | |||
999 | off_t | ||
1000 | cdk_stream_tell (cdk_stream_t s) | ||
1001 | { | ||
1002 | return s ? ftell (s->fp) : (off_t) - 1; | ||
1003 | } | ||
1004 | |||
1005 | |||
1006 | cdk_error_t | ||
1007 | cdk_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 | |||
1034 | static cdk_error_t | ||
1035 | stream_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 | **/ | ||
1057 | cdk_error_t | ||
1058 | cdk_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 | **/ | ||
1084 | cdk_error_t | ||
1085 | cdk_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 | **/ | ||
1124 | cdk_error_t | ||
1125 | cdk_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 | **/ | ||
1159 | cdk_error_t | ||
1160 | cdk_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 | **/ | ||
1183 | cdk_error_t | ||
1184 | cdk_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 | **/ | ||
1207 | cdk_error_t | ||
1208 | cdk_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 | **/ | ||
1233 | cdk_error_t | ||
1234 | cdk_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 | |||
1252 | static int | ||
1253 | stream_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 | */ | ||
1281 | cdk_error_t | ||
1282 | cdk_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 | **/ | ||
1320 | cdk_error_t | ||
1321 | cdk_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 | |||
1355 | cdk_error_t | ||
1356 | cdk_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 | **/ | ||
1376 | int | ||
1377 | cdk_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. */ | ||
1398 | int | ||
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. */ | ||
1422 | int | ||
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. */ | ||
1430 | cdk_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. */ | ||
1442 | int | ||
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 | |||
22 | enum { | ||
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. */ | ||
33 | typedef int (*filter_fnct_t) (void * opaque, int ctl, FILE * in, FILE * out); | ||
34 | |||
35 | /* The stream filter context structure. */ | ||
36 | struct 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. */ | ||
61 | struct 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. */ | ||
31 | struct | ||
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 | |||
54 | static 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 | */ | ||
64 | cdk_error_t | ||
65 | cdk_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 | **/ | ||
84 | cdk_error_t | ||
85 | cdk_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 | |||
137 | void | ||
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 | |||
148 | cdk_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 | |||
160 | static cdk_error_t | ||
161 | file_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 | |||
300 | leave: | ||
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 | |||
27 | static int | ||
28 | stream_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 | |||
39 | static int | ||
40 | stream_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 | |||
54 | static int | ||
55 | stream_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 | |||
64 | static int | ||
65 | write_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 | |||
77 | static int | ||
78 | write_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 | |||
88 | static size_t | ||
89 | calc_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 | |||
100 | static int | ||
101 | write_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 | |||
119 | static cdk_error_t | ||
120 | write_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 | |||
136 | static cdk_error_t | ||
137 | pkt_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 | |||
169 | static cdk_error_t | ||
170 | write_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 | |||
185 | static cdk_error_t | ||
186 | write_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. */ | ||
223 | static cdk_error_t | ||
224 | pkt_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 | |||
237 | static int | ||
238 | pkt_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 | |||
246 | static cdk_error_t | ||
247 | write_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 | |||
265 | static int | ||
266 | write_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 | |||
289 | static cdk_error_t | ||
290 | write_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 | |||
333 | static int | ||
334 | write_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 | |||
369 | static cdk_error_t | ||
370 | write_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 | |||
390 | static size_t | ||
391 | calc_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 | |||
401 | static cdk_error_t | ||
402 | write_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 | |||
438 | static cdk_error_t | ||
439 | write_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 | |||
503 | static cdk_error_t | ||
504 | write_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 | |||
551 | static int | ||
552 | calc_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 | |||
576 | static cdk_error_t | ||
577 | write_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 | |||
690 | static cdk_error_t | ||
691 | write_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 | |||
709 | static cdk_error_t | ||
710 | write_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 | |||
758 | static cdk_error_t | ||
759 | write_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 | |||
791 | static cdk_error_t | ||
792 | write_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 | **/ | ||
835 | cdk_error_t | ||
836 | cdk_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 | |||
900 | cdk_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 | |||
935 | cdk_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 | } | ||