Line data Source code
1 : /* conversion.c - String conversion helper functions.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : 02111-1307, USA. */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #ifdef HAVE_SYS_TYPES_H
29 : /* Solaris 8 needs sys/types.h before time.h. */
30 : # include <sys/types.h>
31 : #endif
32 : #include <time.h>
33 : #include <errno.h>
34 :
35 : #include "gpgme.h"
36 : #include "util.h"
37 : #include "debug.h"
38 :
39 : #define atoi_1(p) (*(p) - '0' )
40 : #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
41 : #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
42 :
43 :
44 :
45 : /* Convert two hexadecimal digits from STR to the value they
46 : represent. Returns -1 if one of the characters is not a
47 : hexadecimal digit. */
48 : int
49 44 : _gpgme_hextobyte (const char *str)
50 : {
51 44 : int val = 0;
52 : int i;
53 :
54 : #define NROFHEXDIGITS 2
55 132 : for (i = 0; i < NROFHEXDIGITS; i++)
56 : {
57 88 : if (*str >= '0' && *str <= '9')
58 65 : val += *str - '0';
59 23 : else if (*str >= 'A' && *str <= 'F')
60 21 : val += 10 + *str - 'A';
61 2 : else if (*str >= 'a' && *str <= 'f')
62 2 : val += 10 + *str - 'a';
63 : else
64 0 : return -1;
65 88 : if (i < NROFHEXDIGITS - 1)
66 44 : val *= 16;
67 88 : str++;
68 : }
69 44 : return val;
70 : }
71 :
72 :
73 : /* Decode the C formatted string SRC and store the result in the
74 : buffer *DESTP which is LEN bytes long. If LEN is zero, then a
75 : large enough buffer is allocated with malloc and *DESTP is set to
76 : the result. Currently, LEN is only used to specify if allocation
77 : is desired or not, the caller is expected to make sure that *DESTP
78 : is large enough if LEN is not zero. */
79 : gpgme_error_t
80 190 : _gpgme_decode_c_string (const char *src, char **destp, size_t len)
81 : {
82 : char *dest;
83 :
84 : /* Set up the destination buffer. */
85 190 : if (len)
86 : {
87 184 : if (len < strlen (src) + 1)
88 0 : return gpg_error (GPG_ERR_INTERNAL);
89 :
90 184 : dest = *destp;
91 : }
92 : else
93 : {
94 : /* The converted string will never be larger than the original
95 : string. */
96 6 : dest = malloc (strlen (src) + 1);
97 6 : if (!dest)
98 0 : return gpg_error_from_syserror ();
99 :
100 6 : *destp = dest;
101 : }
102 :
103 : /* Convert the string. */
104 7218 : while (*src)
105 : {
106 6838 : if (*src != '\\')
107 : {
108 6836 : *(dest++) = *(src++);
109 6836 : continue;
110 : }
111 :
112 2 : switch (src[1])
113 : {
114 : #define DECODE_ONE(match,result) \
115 : case match: \
116 : src += 2; \
117 : *(dest++) = result; \
118 : break;
119 :
120 0 : DECODE_ONE ('\'', '\'');
121 0 : DECODE_ONE ('\"', '\"');
122 0 : DECODE_ONE ('\?', '\?');
123 0 : DECODE_ONE ('\\', '\\');
124 0 : DECODE_ONE ('a', '\a');
125 0 : DECODE_ONE ('b', '\b');
126 0 : DECODE_ONE ('f', '\f');
127 0 : DECODE_ONE ('n', '\n');
128 0 : DECODE_ONE ('r', '\r');
129 0 : DECODE_ONE ('t', '\t');
130 0 : DECODE_ONE ('v', '\v');
131 :
132 : case 'x':
133 : {
134 2 : int val = _gpgme_hextobyte (&src[2]);
135 :
136 2 : if (val == -1)
137 : {
138 : /* Should not happen. */
139 0 : *(dest++) = *(src++);
140 0 : *(dest++) = *(src++);
141 0 : if (*src)
142 0 : *(dest++) = *(src++);
143 0 : if (*src)
144 0 : *(dest++) = *(src++);
145 : }
146 : else
147 : {
148 2 : if (!val)
149 : {
150 : /* A binary zero is not representable in a C
151 : string. */
152 0 : *(dest++) = '\\';
153 0 : *(dest++) = '0';
154 : }
155 : else
156 2 : *((unsigned char *) dest++) = val;
157 2 : src += 4;
158 : }
159 : }
160 2 : break;
161 :
162 : default:
163 : {
164 : /* Should not happen. */
165 0 : *(dest++) = *(src++);
166 0 : *(dest++) = *(src++);
167 : }
168 : }
169 : }
170 190 : *(dest++) = 0;
171 :
172 190 : return 0;
173 : }
174 :
175 :
176 : /* Decode the percent escaped string SRC and store the result in the
177 : buffer *DESTP which is LEN bytes long. If LEN is zero, then a
178 : large enough buffer is allocated with malloc and *DESTP is set to
179 : the result. Currently, LEN is only used to specify if allocation
180 : is desired or not, the caller is expected to make sure that *DESTP
181 : is large enough if LEN is not zero. If BINARY is 1, then '\0'
182 : characters are allowed in the output. */
183 : gpgme_error_t
184 459 : _gpgme_decode_percent_string (const char *src, char **destp, size_t len,
185 : int binary)
186 : {
187 : char *dest;
188 :
189 : /* Set up the destination buffer. */
190 459 : if (len)
191 : {
192 453 : if (len < strlen (src) + 1)
193 0 : return gpg_error (GPG_ERR_INTERNAL);
194 :
195 453 : dest = *destp;
196 : }
197 : else
198 : {
199 : /* The converted string will never be larger than the original
200 : string. */
201 6 : dest = malloc (strlen (src) + 1);
202 6 : if (!dest)
203 0 : return gpg_error_from_syserror ();
204 :
205 6 : *destp = dest;
206 : }
207 :
208 : /* Convert the string. */
209 12956 : while (*src)
210 : {
211 12038 : if (*src != '%')
212 : {
213 12021 : *(dest++) = *(src++);
214 12021 : continue;
215 : }
216 : else
217 : {
218 17 : int val = _gpgme_hextobyte (&src[1]);
219 :
220 17 : if (val == -1)
221 : {
222 : /* Should not happen. */
223 0 : *(dest++) = *(src++);
224 0 : if (*src)
225 0 : *(dest++) = *(src++);
226 0 : if (*src)
227 0 : *(dest++) = *(src++);
228 : }
229 : else
230 : {
231 17 : if (!val && !binary)
232 : {
233 : /* A binary zero is not representable in a C
234 : string. */
235 0 : *(dest++) = '\\';
236 0 : *(dest++) = '0';
237 : }
238 : else
239 17 : *((unsigned char *) dest++) = val;
240 17 : src += 3;
241 : }
242 : }
243 : }
244 459 : *(dest++) = 0;
245 :
246 459 : return 0;
247 : }
248 :
249 :
250 : /* Encode the string SRC with percent escaping and store the result in
251 : the buffer *DESTP which is LEN bytes long. If LEN is zero, then a
252 : large enough buffer is allocated with malloc and *DESTP is set to
253 : the result. Currently, LEN is only used to specify if allocation
254 : is desired or not, the caller is expected to make sure that *DESTP
255 : is large enough if LEN is not zero. If BINARY is 1, then '\0'
256 : characters are allowed in the output. */
257 : gpgme_error_t
258 0 : _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
259 : {
260 : size_t destlen;
261 : char *dest;
262 : const char *str;
263 :
264 0 : destlen = 0;
265 0 : str = src;
266 : /* We percent-escape the + character because the user might need a
267 : "percent plus" escaped string (special gpg format). But we
268 : percent-escape the space character, which works with and without
269 : the special plus format. */
270 0 : while (*str)
271 : {
272 0 : if (*str == '+' || *str == '\"' || *str == '%'
273 0 : || *(const unsigned char *)str <= 0x20)
274 0 : destlen += 3;
275 : else
276 0 : destlen++;
277 0 : str++;
278 : }
279 : /* Terminating nul byte. */
280 0 : destlen++;
281 :
282 : /* Set up the destination buffer. */
283 0 : if (len)
284 : {
285 0 : if (len < destlen)
286 0 : return gpg_error (GPG_ERR_INTERNAL);
287 :
288 0 : dest = *destp;
289 : }
290 : else
291 : {
292 : /* The converted string will never be larger than the original
293 : string. */
294 0 : dest = malloc (destlen);
295 0 : if (!dest)
296 0 : return gpg_error_from_syserror ();
297 :
298 0 : *destp = dest;
299 : }
300 :
301 : /* Convert the string. */
302 0 : while (*src)
303 : {
304 0 : if (*src == '+' || *src == '\"' || *src == '%'
305 0 : || *(const unsigned char *)src <= 0x20)
306 : {
307 0 : snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
308 0 : dest += 3;
309 : }
310 : else
311 0 : *(dest++) = *src;
312 0 : src++;
313 : }
314 0 : *(dest++) = 0;
315 :
316 0 : return 0;
317 : }
318 :
319 :
320 : #ifdef HAVE_W32_SYSTEM
321 : static time_t
322 : _gpgme_timegm (struct tm *tm)
323 : {
324 : /* This one is thread safe. */
325 : SYSTEMTIME st;
326 : FILETIME ft;
327 : unsigned long long cnsecs;
328 :
329 : st.wYear = tm->tm_year + 1900;
330 : st.wMonth = tm->tm_mon + 1;
331 : st.wDay = tm->tm_mday;
332 : st.wHour = tm->tm_hour;
333 : st.wMinute = tm->tm_min;
334 : st.wSecond = tm->tm_sec;
335 : st.wMilliseconds = 0; /* Not available. */
336 : st.wDayOfWeek = 0; /* Ignored. */
337 :
338 : /* System time is UTC thus the conversion is pretty easy. */
339 : if (!SystemTimeToFileTime (&st, &ft))
340 : {
341 : gpg_err_set_errno (EINVAL);
342 : return (time_t)(-1);
343 : }
344 :
345 : cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
346 : | ft.dwLowDateTime);
347 : cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
348 : return (time_t)(cnsecs / 10000000ULL);
349 : }
350 : #endif
351 :
352 :
353 : /* Parse the string TIMESTAMP into a time_t. The string may either be
354 : seconds since Epoch or in the ISO 8601 format like
355 : "20390815T143012". Returns 0 for an empty string or seconds since
356 : Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
357 : point to the next non-parsed character in TIMESTRING. */
358 : time_t
359 376 : _gpgme_parse_timestamp (const char *timestamp, char **endp)
360 : {
361 : /* Need to skip leading spaces, because that is what strtoul does
362 : but not our ISO 8601 checking code. */
363 776 : while (*timestamp && *timestamp== ' ')
364 24 : timestamp++;
365 376 : if (!*timestamp)
366 168 : return 0;
367 :
368 208 : if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
369 : {
370 : struct tm buf;
371 : int year;
372 :
373 15 : year = atoi_4 (timestamp);
374 15 : if (year < 1900)
375 0 : return (time_t)(-1);
376 :
377 15 : if (endp)
378 3 : *endp = (char*)(timestamp + 15);
379 :
380 : /* Fixme: We would better use a configure test to see whether
381 : mktime can handle dates beyond 2038. */
382 : if (sizeof (time_t) <= 4 && year >= 2038)
383 : return (time_t)2145914603; /* 2037-12-31 23:23:23 */
384 :
385 15 : memset (&buf, 0, sizeof buf);
386 15 : buf.tm_year = year - 1900;
387 15 : buf.tm_mon = atoi_2 (timestamp+4) - 1;
388 15 : buf.tm_mday = atoi_2 (timestamp+6);
389 15 : buf.tm_hour = atoi_2 (timestamp+9);
390 15 : buf.tm_min = atoi_2 (timestamp+11);
391 15 : buf.tm_sec = atoi_2 (timestamp+13);
392 :
393 : #ifdef HAVE_W32_SYSTEM
394 : return _gpgme_timegm (&buf);
395 : #else
396 : #ifdef HAVE_TIMEGM
397 15 : return timegm (&buf);
398 : #else
399 : {
400 : time_t tim;
401 :
402 : putenv ("TZ=UTC");
403 : tim = mktime (&buf);
404 : #ifdef __GNUC__
405 : #warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
406 : #endif
407 : return tim;
408 : }
409 : #endif /* !HAVE_TIMEGM */
410 : #endif /* !HAVE_W32_SYSTEM */
411 : }
412 : else
413 193 : return (time_t)strtoul (timestamp, endp, 10);
414 : }
415 :
416 :
417 : /* The GPG backend uses OpenPGP algorithm numbers which we need to map
418 : to our algorithm numbers. This function MUST not change ERRNO. */
419 : int
420 219 : _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
421 : {
422 219 : if (protocol == GPGME_PROTOCOL_OPENPGP)
423 : {
424 209 : switch (algo)
425 : {
426 209 : case 1: case 2: case 3: case 16: case 17: break;
427 0 : case 18: algo = GPGME_PK_ECDH; break;
428 0 : case 19: algo = GPGME_PK_ECDSA; break;
429 0 : case 20: break;
430 0 : case 22: algo = GPGME_PK_EDDSA; break;
431 0 : default: algo = 0; break; /* Unknown. */
432 : }
433 : }
434 :
435 219 : return algo;
436 : }
|