File: | lib/opencdk/armor.c |
Location: | line 278, column 15 |
Description: | Although the value stored to 'nread' is used in the enclosing expression, the value is never actually read from 'nread' |
1 | /* armor.c - Armor filters |
2 | * Copyright (C) 1998-2003, 2007-2008, 2010, 2012 Free Software |
3 | * Foundation, Inc. |
4 | * |
5 | * Author: Timo Schulz |
6 | * |
7 | * This file is part of OpenCDK. |
8 | * |
9 | * The OpenCDK library is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Lesser General Public License |
11 | * as published by the Free Software Foundation; either version 3 of |
12 | * the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Lesser General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public License |
20 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
21 | * |
22 | * ChangeLog for basic BASE64 code (base64_encode, base64_decode): |
23 | * Original author: Eric S. Raymond (Fetchmail) |
24 | * Heavily modified by Brendan Cully <brendan@kublai.com> (Mutt) |
25 | * Modify the code for generic use by Timo Schulz <twoaday@freakmail.de> |
26 | */ |
27 | |
28 | #ifdef HAVE_CONFIG_H1 |
29 | #include <config.h> |
30 | #endif |
31 | #include <stdio.h> |
32 | #include <string.h> |
33 | #include <sys/stat.h> |
34 | |
35 | #include "opencdk.h" |
36 | #include "main.h" |
37 | #include "filters.h" |
38 | |
39 | #ifdef __MINGW32__ |
40 | #define LF"\n" "\r\n" |
41 | #define ALTLF"\r\n" "\n" |
42 | #else |
43 | #define LF"\n" "\n" |
44 | #define ALTLF"\r\n" "\r\n" |
45 | #endif |
46 | |
47 | #define CRCINIT0xB704CE 0xB704CE |
48 | |
49 | #define BAD-1 -1 |
50 | #define b64val(c)index64[(unsigned int)(c)] index64[(unsigned int)(c)] |
51 | |
52 | static u32 crc_table[] = { |
53 | 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC, |
54 | 0x9F7F17, |
55 | 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5, |
56 | 0x3EFE2E, |
57 | 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65, |
58 | 0x5A319E, |
59 | 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C, |
60 | 0xFBB0A7, |
61 | 0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205, |
62 | 0x93AEFE, |
63 | 0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C, |
64 | 0x322FC7, |
65 | 0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C, |
66 | 0x56E077, |
67 | 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5, |
68 | 0xF7614E, |
69 | 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E, |
70 | 0x86DCC5, |
71 | 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107, |
72 | 0x275DFC, |
73 | 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7, |
74 | 0x43924C, |
75 | 0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E, |
76 | 0xE21375, |
77 | 0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7, |
78 | 0x8A0D2C, |
79 | 0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE, |
80 | 0x2B8C15, |
81 | 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E, |
82 | 0x4F43A5, |
83 | 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67, |
84 | 0xEEC29C, |
85 | 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448, |
86 | 0xAC38B3, |
87 | 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571, |
88 | 0x0DB98A, |
89 | 0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1, |
90 | 0x69763A, |
91 | 0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8, |
92 | 0xC8F703, |
93 | 0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1, |
94 | 0xA0E95A, |
95 | 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498, |
96 | 0x016863, |
97 | 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28, |
98 | 0x65A7D3, |
99 | 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11, |
100 | 0xC426EA, |
101 | 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A, |
102 | 0xB59B61, |
103 | 0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3, |
104 | 0x141A58, |
105 | 0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913, |
106 | 0x70D5E8, |
107 | 0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A, |
108 | 0xD154D1, |
109 | 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673, |
110 | 0xB94A88, |
111 | 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A, |
112 | 0x18CBB1, |
113 | 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA, |
114 | 0x7C0401, |
115 | 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3, |
116 | 0xDD8538 |
117 | }; |
118 | |
119 | static const char *armor_begin[] = { |
120 | "BEGIN PGP MESSAGE", |
121 | "BEGIN PGP PUBLIC KEY BLOCK", |
122 | "BEGIN PGP PRIVATE KEY BLOCK", |
123 | "BEGIN PGP SIGNATURE", |
124 | NULL((void*)0) |
125 | }; |
126 | |
127 | static const char *armor_end[] = { |
128 | "END PGP MESSAGE", |
129 | "END PGP PUBLIC KEY BLOCK", |
130 | "END PGP PRIVATE KEY BLOCK", |
131 | "END PGP SIGNATURE", |
132 | NULL((void*)0) |
133 | }; |
134 | |
135 | static const char *valid_headers[] = { |
136 | "Comment", |
137 | "Version", |
138 | "MessageID", |
139 | "Hash", |
140 | "Charset", |
141 | NULL((void*)0) |
142 | }; |
143 | |
144 | static char b64chars[] = |
145 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
146 | |
147 | static int index64[128] = { |
148 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
149 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
150 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, |
151 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, |
152 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
153 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, |
154 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
155 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 |
156 | }; |
157 | |
158 | |
159 | /* encode a raw binary buffer to a null-terminated base64 strings */ |
160 | static int |
161 | base64_encode (char *out, const byte * in, size_t len, size_t olen) |
162 | { |
163 | if (!out || !in) |
164 | { |
165 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",165); } while(0);; |
166 | return CDK_Inv_Value; |
167 | } |
168 | |
169 | while (len >= 3 && olen > 10) |
170 | { |
171 | *out++ = b64chars[in[0] >> 2]; |
172 | *out++ = b64chars[((in[0] << 4) & 0x30) | (in[1] >> 4)]; |
173 | *out++ = b64chars[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; |
174 | *out++ = b64chars[in[2] & 0x3f]; |
175 | olen -= 4; |
176 | len -= 3; |
177 | in += 3; |
178 | } |
179 | |
180 | /* clean up remainder */ |
181 | if (len > 0 && olen > 4) |
182 | { |
183 | byte fragment = 0; |
184 | *out++ = b64chars[in[0] >> 2]; |
185 | fragment = (in[0] << 4) & 0x30; |
186 | if (len > 1) |
187 | fragment |= in[1] >> 4; |
188 | *out++ = b64chars[fragment]; |
189 | *out++ = (len < 2) ? '=' : b64chars[(in[1] << 2) & 0x3c]; |
190 | *out++ = '='; |
191 | } |
192 | *out = '\0'; |
193 | return 0; |
194 | } |
195 | |
196 | |
197 | /* Convert '\0'-terminated base64 string to raw byte buffer. |
198 | Returns length of returned buffer, or -1 on error. */ |
199 | static int |
200 | base64_decode (byte * out, const char *in) |
201 | { |
202 | size_t len; |
203 | byte digit1, digit2, digit3, digit4; |
204 | |
205 | if (!out || !in) |
206 | { |
207 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",207); } while(0);; |
208 | return -1; |
209 | } |
210 | |
211 | len = 0; |
212 | do |
213 | { |
214 | digit1 = in[0]; |
215 | if (digit1 > 127 || b64val (digit1)index64[(unsigned int)(digit1)] == BAD-1) |
216 | { |
217 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",217); } while(0);; |
218 | return -1; |
219 | } |
220 | digit2 = in[1]; |
221 | if (digit2 > 127 || b64val (digit2)index64[(unsigned int)(digit2)] == BAD-1) |
222 | { |
223 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",223); } while(0);; |
224 | return -1; |
225 | } |
226 | digit3 = in[2]; |
227 | if (digit3 > 127 || ((digit3 != '=') && (b64val (digit3)index64[(unsigned int)(digit3)] == BAD-1))) |
228 | { |
229 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",229); } while(0);; |
230 | return -1; |
231 | } |
232 | digit4 = in[3]; |
233 | if (digit4 > 127 || ((digit4 != '=') && (b64val (digit4)index64[(unsigned int)(digit4)] == BAD-1))) |
234 | { |
235 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",235); } while(0);; |
236 | return -1; |
237 | } |
238 | in += 4; |
239 | |
240 | /* digits are already sanity-checked */ |
241 | *out++ = (b64val (digit1)index64[(unsigned int)(digit1)] << 2) | (b64val (digit2)index64[(unsigned int)(digit2)] >> 4); |
242 | len++; |
243 | if (digit3 != '=') |
244 | { |
245 | *out++ = ((b64val (digit2)index64[(unsigned int)(digit2)] << 4) & 0xf0) | (b64val (digit3)index64[(unsigned int)(digit3)] >> 2); |
246 | len++; |
247 | if (digit4 != '=') |
248 | { |
249 | *out++ = ((b64val (digit3)index64[(unsigned int)(digit3)] << 6) & 0xc0) | b64val (digit4)index64[(unsigned int)(digit4)]; |
250 | len++; |
251 | } |
252 | } |
253 | } |
254 | while (*in && digit4 != '='); |
255 | |
256 | return len; |
257 | } |
258 | |
259 | |
260 | /* Return the compression algorithm in @r_zipalgo. |
261 | If the parameter is not set after execution, |
262 | the stream is not compressed. */ |
263 | static int |
264 | compress_get_algo (cdk_stream_t inp, int *r_zipalgo) |
265 | { |
266 | byte plain[512]; |
267 | char buf[128]; |
268 | int nread, pkttype; |
269 | |
270 | *r_zipalgo = 0; |
271 | cdk_stream_seek (inp, 0); |
272 | while (!cdk_stream_eof (inp)) |
273 | { |
274 | nread = _cdk_stream_gets (inp, buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1); |
275 | if (!nread || nread == -1) |
276 | break; |
277 | if (nread == 1 && !cdk_stream_eof (inp) |
278 | && (nread = _cdk_stream_gets (inp, buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1)) > 0) |
Although the value stored to 'nread' is used in the enclosing expression, the value is never actually read from 'nread' | |
279 | { |
280 | base64_decode (plain, buf); |
281 | if (!(*plain & 0x80)) |
282 | break; |
283 | pkttype = *plain & 0x40 ? (*plain & 0x3f) : ((*plain >> 2) & 0xf); |
284 | if (pkttype == CDK_PKT_COMPRESSED && r_zipalgo) |
285 | { |
286 | _gnutls_buffers_log ("armor compressed (algo=%d)\n",do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "armor compressed (algo=%d)\n", *(plain + 1)); } while(0) |
287 | *(plain + 1))do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "armor compressed (algo=%d)\n", *(plain + 1)); } while(0); |
288 | *r_zipalgo = *(plain + 1); |
289 | } |
290 | break; |
291 | } |
292 | } |
293 | return 0; |
294 | } |
295 | |
296 | |
297 | static int |
298 | check_armor (cdk_stream_t inp, int *r_zipalgo) |
299 | { |
300 | char buf[4096]; |
301 | size_t nread; |
302 | int check; |
303 | |
304 | check = 0; |
305 | nread = cdk_stream_read (inp, buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1); |
306 | if (nread > 0) |
307 | { |
308 | buf[nread] = '\0'; |
309 | if (strstr (buf, "-----BEGIN PGP")) |
310 | { |
311 | compress_get_algo (inp, r_zipalgo); |
312 | check = 1; |
313 | } |
314 | cdk_stream_seek (inp, 0); |
315 | } |
316 | return check; |
317 | } |
318 | |
319 | |
320 | static int |
321 | is_armored (int ctb) |
322 | { |
323 | int pkttype = 0; |
324 | |
325 | if (!(ctb & 0x80)) |
326 | { |
327 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",327); } while(0);; |
328 | return 1; /* invalid packet: assume it is armored */ |
329 | } |
330 | pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb >> 2) & 0xf); |
331 | switch (pkttype) |
332 | { |
333 | case CDK_PKT_MARKER: |
334 | case CDK_PKT_ONEPASS_SIG: |
335 | case CDK_PKT_PUBLIC_KEY: |
336 | case CDK_PKT_SECRET_KEY: |
337 | case CDK_PKT_PUBKEY_ENC: |
338 | case CDK_PKT_SIGNATURE: |
339 | case CDK_PKT_LITERAL: |
340 | case CDK_PKT_COMPRESSED: |
341 | return 0; /* seems to be a regular packet: not armored */ |
342 | } |
343 | return 1; |
344 | } |
345 | |
346 | |
347 | static u32 |
348 | update_crc (u32 crc, const byte * buf, size_t buflen) |
349 | { |
350 | unsigned int j; |
351 | |
352 | if (!crc) |
353 | crc = CRCINIT0xB704CE; |
354 | |
355 | for (j = 0; j < buflen; j++) |
356 | crc = (crc << 8) ^ crc_table[0xff & ((crc >> 16) ^ buf[j])]; |
357 | crc &= 0xffffff; |
358 | return crc; |
359 | } |
360 | |
361 | |
362 | static cdk_error_t |
363 | armor_encode (void *data, FILE * in, FILE * out) |
364 | { |
365 | armor_filter_t *afx = data; |
366 | struct stat statbuf; |
367 | char crcbuf[5], buf[128], raw[49]; |
368 | byte crcbuf2[3]; |
369 | size_t nread = 0; |
370 | const char *lf; |
371 | |
372 | if (!afx) |
373 | { |
374 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",374); } while(0);; |
375 | return CDK_Inv_Value; |
376 | } |
377 | if (afx->idx < 0 || afx->idx > (int) DIM (armor_begin)(sizeof (armor_begin)/sizeof ((armor_begin)[0])) || |
378 | afx->idx2 < 0 || afx->idx2 > (int) DIM (armor_end)(sizeof (armor_end)/sizeof ((armor_end)[0]))) |
379 | { |
380 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",380); } while(0);; |
381 | return CDK_Inv_Value; |
382 | } |
383 | |
384 | _gnutls_buffers_log ("armor filter: encode\n")do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "armor filter: encode\n"); } while (0); |
385 | |
386 | memset (crcbuf, 0, sizeof (crcbuf)); |
387 | |
388 | lf = afx->le ? afx->le : LF"\n"; |
389 | fprintf (out, "-----%s-----%s", armor_begin[afx->idx], lf); |
390 | fprintf (out, "Version: OpenPrivacy " PACKAGE_VERSION"3.0.12" "%s", lf); |
391 | if (afx->hdrlines) |
392 | fwrite (afx->hdrlines, 1, strlen (afx->hdrlines), out); |
393 | fprintf (out, "%s", lf); |
394 | |
395 | if (fstat (fileno (in), &statbuf)) |
396 | { |
397 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",397); } while(0);; |
398 | return CDK_General_Error; |
399 | } |
400 | |
401 | while (!feof (in)) |
402 | { |
403 | nread = fread (raw, 1, DIM (raw)(sizeof (raw)/sizeof ((raw)[0])) - 1, in); |
404 | if (!nread) |
405 | break; |
406 | if (ferror (in)) |
407 | { |
408 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",408); } while(0);; |
409 | return CDK_File_Error; |
410 | } |
411 | afx->crc = update_crc (afx->crc, (byte *) raw, nread); |
412 | base64_encode (buf, (byte *) raw, nread, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1); |
413 | fprintf (out, "%s%s", buf, lf); |
414 | } |
415 | |
416 | crcbuf2[0] = afx->crc >> 16; |
417 | crcbuf2[1] = afx->crc >> 8; |
418 | crcbuf2[2] = afx->crc; |
419 | crcbuf[0] = b64chars[crcbuf2[0] >> 2]; |
420 | crcbuf[1] = b64chars[((crcbuf2[0] << 4) & 0x30) | (crcbuf2[1] >> 4)]; |
421 | crcbuf[2] = b64chars[((crcbuf2[1] << 2) & 0x3c) | (crcbuf2[2] >> 6)]; |
422 | crcbuf[3] = b64chars[crcbuf2[2] & 0x3f]; |
423 | fprintf (out, "=%s%s", crcbuf, lf); |
424 | fprintf (out, "-----%s-----%s", armor_end[afx->idx2], lf); |
425 | |
426 | return 0; |
427 | } |
428 | |
429 | static int |
430 | search_header (const char *buf, const char **array) |
431 | { |
432 | const char *s; |
433 | int i; |
434 | |
435 | if (strlen (buf) < 5 || strncmp (buf, "-----", 5)) |
436 | { |
437 | return -1; |
438 | } |
439 | for (i = 0; (s = array[i]); i++) |
440 | { |
441 | if (!strncmp (s, buf + 5, strlen (s))) |
442 | return i; |
443 | } |
444 | return -1; |
445 | } |
446 | |
447 | |
448 | const char * |
449 | _cdk_armor_get_lineend (void) |
450 | { |
451 | return LF"\n"; |
452 | } |
453 | |
454 | |
455 | static cdk_error_t |
456 | armor_decode (void *data, FILE * in, FILE * out) |
457 | { |
458 | armor_filter_t *afx = data; |
459 | const char *s; |
460 | char buf[127]; |
461 | byte raw[128], crcbuf[4]; |
462 | u32 crc2 = 0; |
463 | ssize_t nread = 0; |
464 | int i, pgp_data = 0; |
465 | cdk_error_t rc = 0; |
466 | int len; |
467 | |
468 | if (!afx) |
469 | { |
470 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",470); } while(0);; |
471 | return CDK_Inv_Value; |
472 | } |
473 | |
474 | _gnutls_buffers_log ("armor filter: decode\n")do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "armor filter: decode\n"); } while (0); |
475 | |
476 | fseek (in, 0, SEEK_SET0); |
477 | /* Search the begin of the message */ |
478 | while (!feof (in) && !pgp_data) |
479 | { |
480 | s = fgets (buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1, in); |
481 | if (!s) |
482 | break; |
483 | afx->idx = search_header (buf, armor_begin); |
484 | if (afx->idx >= 0) |
485 | pgp_data = 1; |
486 | } |
487 | |
488 | if (feof (in) || !pgp_data) |
489 | { |
490 | return CDK_Armor_Error; /* no data found */ |
491 | } |
492 | |
493 | /* Parse header until the empty line is reached */ |
494 | while (!feof (in)) |
495 | { |
496 | s = fgets (buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1, in); |
497 | if (!s) |
498 | return CDK_EOF; |
499 | if (strcmp (s, LF"\n") == 0 || strcmp (s, ALTLF"\r\n") == 0) |
500 | { |
501 | rc = 0; |
502 | break; /* empty line */ |
503 | } |
504 | /* From RFC2440: OpenPGP should consider improperly formatted Armor |
505 | Headers to be corruption of the ASCII Armor. A colon and a single |
506 | space separate the key and value. */ |
507 | if (!strstr (buf, ": ")) |
508 | { |
509 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",509); } while(0);; |
510 | return CDK_Armor_Error; |
511 | } |
512 | rc = CDK_General_Error; |
513 | for (i = 0; (s = valid_headers[i]); i++) |
514 | { |
515 | if (!strncmp (s, buf, strlen (s))) |
516 | rc = 0; |
517 | } |
518 | if (rc) |
519 | { |
520 | /* From RFC2440: Unknown keys should be reported to the user, |
521 | but OpenPGP should continue to process the message. */ |
522 | _cdk_log_info ("unknown header: `%s'\n", buf)do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "unknown header: `%s'\n", buf); } while(0); |
523 | rc = 0; |
524 | } |
525 | } |
526 | |
527 | /* Read the data body */ |
528 | while (!feof (in)) |
529 | { |
530 | s = fgets (buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1, in); |
531 | if (!s) |
532 | break; |
533 | |
534 | len = strlen(buf); |
535 | |
536 | if (buf[len - 1] == '\n') |
537 | buf[len - 1] = '\0'; |
538 | if (buf[len - 1] == '\r') |
539 | buf[len - 1] = '\0'; |
540 | if (buf[0] == '=' && strlen (s) == 5) |
541 | { /* CRC */ |
542 | memset (crcbuf, 0, sizeof (crcbuf)); |
543 | base64_decode (crcbuf, buf + 1); |
544 | crc2 = (crcbuf[0] << 16) | (crcbuf[1] << 8) | crcbuf[2]; |
545 | break; /* stop here */ |
546 | } |
547 | else |
548 | { |
549 | nread = base64_decode (raw, buf); |
550 | if (nread == -1 || nread == 0) |
551 | break; |
552 | afx->crc = update_crc (afx->crc, raw, nread); |
553 | fwrite (raw, 1, nread, out); |
554 | } |
555 | } |
556 | |
557 | /* Search the tail of the message */ |
558 | s = fgets (buf, DIM (buf)(sizeof (buf)/sizeof ((buf)[0])) - 1, in); |
559 | if (s) |
560 | { |
561 | int len = strlen(buf); |
562 | if (buf[len - 1] == '\n') |
563 | buf[len - 1] = '\0'; |
564 | if (buf[len - 1] == '\r') |
565 | buf[len - 1] = '\0'; |
566 | rc = CDK_General_Error; |
567 | afx->idx2 = search_header (buf, armor_end); |
568 | if (afx->idx2 >= 0) |
569 | rc = 0; |
570 | } |
571 | |
572 | /* This catches error when no tail was found or the header is |
573 | different then the tail line. */ |
574 | if (rc || afx->idx != afx->idx2) |
575 | rc = CDK_Armor_Error; |
576 | |
577 | afx->crc_okay = (afx->crc == crc2) ? 1 : 0; |
578 | if (!afx->crc_okay && !rc) |
579 | { |
580 | _gnutls_buffers_log ("file crc=%08X afx_crc=%08X\n",do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "file crc=%08X afx_crc=%08X\n", (unsigned int) crc2, (unsigned int) afx->crc); } while(0) |
581 | (unsigned int) crc2, (unsigned int) afx->crc)do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "file crc=%08X afx_crc=%08X\n", (unsigned int) crc2, (unsigned int) afx->crc); } while(0); |
582 | rc = CDK_Armor_CRC_Error; |
583 | } |
584 | |
585 | return rc; |
586 | } |
587 | |
588 | int |
589 | _cdk_filter_armor (void *data, int ctl, FILE * in, FILE * out) |
590 | { |
591 | if (ctl == STREAMCTL_READ) |
592 | return armor_decode (data, in, out); |
593 | else if (ctl == STREAMCTL_WRITE) |
594 | return armor_encode (data, in, out); |
595 | else if (ctl == STREAMCTL_FREE) |
596 | { |
597 | armor_filter_t *afx = data; |
598 | if (afx) |
599 | { |
600 | _gnutls_buffers_log ("free armor filter\n")do { if (__builtin_expect((_gnutls_log_level == 6 || _gnutls_log_level > 9), 0)) _gnutls_log( 6, "free armor filter\n"); } while (0); |
601 | afx->idx = afx->idx2 = 0; |
602 | afx->crc = afx->crc_okay = 0; |
603 | return 0; |
604 | } |
605 | } |
606 | |
607 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",607); } while(0);; |
608 | return CDK_Inv_Mode; |
609 | } |
610 | |
611 | |
612 | /** |
613 | * cdk_armor_encode_buffer: |
614 | * @inbuf: the raw input buffer |
615 | * @inlen: raw buffer len |
616 | * @outbuf: the destination buffer for the base64 output |
617 | * @outlen: destination buffer len |
618 | * @nwritten: actual length of the base64 data |
619 | * @type: the base64 file type. |
620 | * |
621 | * Encode the given buffer into base64 format. The base64 |
622 | * string will be null terminated but the null will |
623 | * not be contained in the size. |
624 | **/ |
625 | cdk_error_t |
626 | cdk_armor_encode_buffer (const byte * inbuf, size_t inlen, |
627 | char *outbuf, size_t outlen, |
628 | size_t * nwritten, int type) |
629 | { |
630 | const char *head, *tail, *le; |
631 | byte tempbuf[48]; |
632 | char tempout[128]; |
633 | size_t pos, off, len, rest; |
634 | |
635 | if (!inbuf || !nwritten) |
636 | { |
637 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",637); } while(0);; |
638 | return CDK_Inv_Value; |
639 | } |
640 | if (type > CDK_ARMOR_SIGNATURE) |
641 | { |
642 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",642); } while(0);; |
643 | return CDK_Inv_Mode; |
644 | } |
645 | |
646 | head = armor_begin[type]; |
647 | tail = armor_end[type]; |
648 | le = _cdk_armor_get_lineend (); |
649 | pos = strlen (head) + 10 + 2 + 2 + strlen (tail) + 10 + 2 + 5 + 2 + 1; |
650 | /* The output data is 4/3 times larger, plus a line end for each line. */ |
651 | pos += (4 * inlen / 3) + 2 * (4 * inlen / 3 / 64) + 1; |
652 | |
653 | if (outbuf && outlen < pos) |
654 | { |
655 | gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log ( 2, "ASSERT: %s:%d\n", "armor.c",655); } while(0);; |
656 | *nwritten = pos; |
657 | return CDK_Too_Short; |
658 | } |
659 | |
660 | /* Only return the size of the output. */ |
661 | if (!outbuf) |
662 | { |
663 | *nwritten = pos; |
664 | return 0; |
665 | } |
666 | |
667 | pos = 0; |
668 | memset (outbuf, 0, outlen); |
669 | memcpy (outbuf + pos, "-----", 5); |
670 | pos += 5; |
671 | memcpy (outbuf + pos, head, strlen (head)); |
672 | pos += strlen (head); |
673 | memcpy (outbuf + pos, "-----", 5); |
674 | pos += 5; |
675 | memcpy (outbuf + pos, le, strlen (le)); |
676 | pos += strlen (le); |
677 | memcpy (outbuf + pos, le, strlen (le)); |
678 | pos += strlen (le); |
679 | rest = inlen; |
680 | for (off = 0; off < inlen;) |
681 | { |
682 | if (rest > 48) |
683 | { |
684 | memcpy (tempbuf, inbuf + off, 48); |
685 | off += 48; |
686 | len = 48; |
687 | } |
688 | else |
689 | { |
690 | memcpy (tempbuf, inbuf + off, rest); |
691 | off += rest; |
692 | len = rest; |
693 | } |
694 | rest -= len; |
695 | base64_encode (tempout, tempbuf, len, DIM (tempout)(sizeof (tempout)/sizeof ((tempout)[0])) - 1); |
696 | memcpy (outbuf + pos, tempout, strlen (tempout)); |
697 | pos += strlen (tempout); |
698 | memcpy (outbuf + pos, le, strlen (le)); |
699 | pos += strlen (le); |
700 | } |
701 | |
702 | memcpy (outbuf + pos, "-----", 5); |
703 | pos += 5; |
704 | memcpy (outbuf + pos, tail, strlen (tail)); |
705 | pos += strlen (tail); |
706 | memcpy (outbuf + pos, "-----", 5); |
707 | pos += 5; |
708 | memcpy (outbuf + pos, le, strlen (le)); |
709 | pos += strlen (le); |
710 | outbuf[pos] = 0; |
711 | *nwritten = pos - 1; |
712 | return 0; |
713 | } |