Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F20065030
conversion.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
14 KB
Subscribers
None
conversion.c
View Options
/* conversion.c - String conversion helper functions.
* Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <https://gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#if HAVE_CONFIG_H
#include
<config.h>
#endif
#include
<stdlib.h>
#include
<string.h>
#ifdef HAVE_SYS_TYPES_H
/* Solaris 8 needs sys/types.h before time.h. */
# include <sys/types.h>
#endif
#include
<time.h>
#include
<errno.h>
#include
<stdarg.h>
#include
"gpgme.h"
#include
"util.h"
#include
"debug.h"
#define atoi_1(p) (*(p) - '0' )
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
void
_gpgme_wipememory
(
void
*
ptr
,
size_t
len
)
{
/* Prevent compiler from optimizing away the call to memset by accessing
* memset through volatile pointer. */
static
void
*
(
*
volatile
memset_ptr
)(
void
*
,
int
,
size_t
)
=
(
void
*
)
memset
;
memset_ptr
(
ptr
,
0
,
len
);
}
static
char
*
do_strconcat
(
const
char
*
s1
,
va_list
arg_ptr
)
{
const
char
*
argv
[
16
];
size_t
argc
;
size_t
needed
;
char
*
buffer
,
*
p
;
argc
=
0
;
argv
[
argc
++
]
=
s1
;
needed
=
strlen
(
s1
);
while
(((
argv
[
argc
]
=
va_arg
(
arg_ptr
,
const
char
*
))))
{
needed
+=
strlen
(
argv
[
argc
]);
if
(
argc
>=
DIM
(
argv
)
-1
)
{
gpg_err_set_errno
(
EINVAL
);
return
NULL
;
}
argc
++
;
}
needed
++
;
buffer
=
malloc
(
needed
);
if
(
buffer
)
{
for
(
p
=
buffer
,
argc
=
0
;
argv
[
argc
];
argc
++
)
p
=
stpcpy
(
p
,
argv
[
argc
]);
}
return
buffer
;
}
/* Concatenate the string S1 with all the following strings up to a
* NULL. Returns a malloced buffer with the new string or NULL on a
malloc error or if too many arguments are given. */
char
*
_gpgme_strconcat
(
const
char
*
s1
,
...)
{
va_list
arg_ptr
;
char
*
result
;
if
(
!
s1
)
result
=
strdup
(
""
);
else
{
va_start
(
arg_ptr
,
s1
);
result
=
do_strconcat
(
s1
,
arg_ptr
);
va_end
(
arg_ptr
);
}
return
result
;
}
/* Convert two hexadecimal digits from STR to the value they
represent. Returns -1 if one of the characters is not a
hexadecimal digit. */
int
_gpgme_hextobyte
(
const
char
*
str
)
{
int
val
=
0
;
int
i
;
#define NROFHEXDIGITS 2
for
(
i
=
0
;
i
<
NROFHEXDIGITS
;
i
++
)
{
if
(
*
str
>=
'0'
&&
*
str
<=
'9'
)
val
+=
*
str
-
'0'
;
else
if
(
*
str
>=
'A'
&&
*
str
<=
'F'
)
val
+=
10
+
*
str
-
'A'
;
else
if
(
*
str
>=
'a'
&&
*
str
<=
'f'
)
val
+=
10
+
*
str
-
'a'
;
else
return
-1
;
if
(
i
<
NROFHEXDIGITS
-
1
)
val
*=
16
;
str
++
;
}
return
val
;
}
/* Decode the C formatted string SRC and store the result in the
buffer *DESTP which is LEN bytes long. If LEN is zero, then a
large enough buffer is allocated with malloc and *DESTP is set to
the result. Currently, LEN is only used to specify if allocation
is desired or not, the caller is expected to make sure that *DESTP
is large enough if LEN is not zero. */
gpgme_error_t
_gpgme_decode_c_string
(
const
char
*
src
,
char
**
destp
,
size_t
len
)
{
char
*
dest
;
/* Set up the destination buffer. */
if
(
len
)
{
if
(
len
<
strlen
(
src
)
+
1
)
return
gpg_error
(
GPG_ERR_INTERNAL
);
dest
=
*
destp
;
}
else
{
/* The converted string will never be larger than the original
string. */
dest
=
malloc
(
strlen
(
src
)
+
1
);
if
(
!
dest
)
return
gpg_error_from_syserror
();
*
destp
=
dest
;
}
/* Convert the string. */
while
(
*
src
)
{
if
(
*
src
!=
'\\'
)
{
*
(
dest
++
)
=
*
(
src
++
);
continue
;
}
switch
(
src
[
1
])
{
#define DECODE_ONE(match,result) \
case match: \
src += 2; \
*(dest++) = result; \
break;
DECODE_ONE
(
'\''
,
'\''
);
DECODE_ONE
(
'\"'
,
'\"'
);
DECODE_ONE
(
'\?'
,
'\?'
);
DECODE_ONE
(
'\\'
,
'\\'
);
DECODE_ONE
(
'a'
,
'\a'
);
DECODE_ONE
(
'b'
,
'\b'
);
DECODE_ONE
(
'f'
,
'\f'
);
DECODE_ONE
(
'n'
,
'\n'
);
DECODE_ONE
(
'r'
,
'\r'
);
DECODE_ONE
(
't'
,
'\t'
);
DECODE_ONE
(
'v'
,
'\v'
);
case
'x'
:
{
int
val
=
_gpgme_hextobyte
(
&
src
[
2
]);
if
(
val
==
-1
)
{
/* Should not happen. */
*
(
dest
++
)
=
*
(
src
++
);
*
(
dest
++
)
=
*
(
src
++
);
if
(
*
src
)
*
(
dest
++
)
=
*
(
src
++
);
if
(
*
src
)
*
(
dest
++
)
=
*
(
src
++
);
}
else
{
if
(
!
val
)
{
/* A binary zero is not representable in a C
string. */
*
(
dest
++
)
=
'\\'
;
*
(
dest
++
)
=
'0'
;
}
else
*
((
unsigned
char
*
)
dest
++
)
=
val
;
src
+=
4
;
}
}
break
;
default
:
{
/* Should not happen. */
*
(
dest
++
)
=
*
(
src
++
);
*
(
dest
++
)
=
*
(
src
++
);
}
}
}
*
(
dest
++
)
=
0
;
return
0
;
}
/* Decode the percent escaped string SRC and store the result in the
buffer *DESTP which is LEN bytes long. If LEN is zero, then a
large enough buffer is allocated with malloc and *DESTP is set to
the result. Currently, LEN is only used to specify if allocation
is desired or not, the caller is expected to make sure that *DESTP
is large enough if LEN is not zero. If BINARY is 1, then '\0'
characters are allowed in the output. */
gpgme_error_t
_gpgme_decode_percent_string
(
const
char
*
src
,
char
**
destp
,
size_t
len
,
int
binary
)
{
char
*
dest
;
/* Set up the destination buffer. */
if
(
len
)
{
if
(
len
<
strlen
(
src
)
+
1
)
return
gpg_error
(
GPG_ERR_INTERNAL
);
dest
=
*
destp
;
}
else
{
/* The converted string will never be larger than the original
string. */
dest
=
malloc
(
strlen
(
src
)
+
1
);
if
(
!
dest
)
return
gpg_error_from_syserror
();
*
destp
=
dest
;
}
/* Convert the string. */
while
(
*
src
)
{
if
(
*
src
!=
'%'
)
{
*
(
dest
++
)
=
*
(
src
++
);
continue
;
}
else
{
int
val
=
_gpgme_hextobyte
(
&
src
[
1
]);
if
(
val
==
-1
)
{
/* Should not happen. */
*
(
dest
++
)
=
*
(
src
++
);
if
(
*
src
)
*
(
dest
++
)
=
*
(
src
++
);
if
(
*
src
)
*
(
dest
++
)
=
*
(
src
++
);
}
else
{
if
(
!
val
&&
!
binary
)
{
/* A binary zero is not representable in a C
string. */
*
(
dest
++
)
=
'\\'
;
*
(
dest
++
)
=
'0'
;
}
else
*
((
unsigned
char
*
)
dest
++
)
=
val
;
src
+=
3
;
}
}
}
*
(
dest
++
)
=
0
;
return
0
;
}
/* Encode the string SRC with percent escaping and store the result in
the buffer *DESTP which is LEN bytes long. If LEN is zero, then a
large enough buffer is allocated with malloc and *DESTP is set to
the result. Currently, LEN is only used to specify if allocation
is desired or not, the caller is expected to make sure that *DESTP
is large enough if LEN is not zero. If BINARY is 1, then '\0'
characters are allowed in the output. */
gpgme_error_t
_gpgme_encode_percent_string
(
const
char
*
src
,
char
**
destp
,
size_t
len
)
{
size_t
destlen
;
char
*
dest
;
const
char
*
str
;
destlen
=
0
;
str
=
src
;
/* We percent-escape the + character because the user might need a
"percent plus" escaped string (special gpg format). But we
percent-escape the space character, which works with and without
the special plus format. */
while
(
*
str
)
{
if
(
*
str
==
'+'
||
*
str
==
'\"'
||
*
str
==
'%'
||
*
(
const
unsigned
char
*
)
str
<=
0x20
)
destlen
+=
3
;
else
destlen
++
;
str
++
;
}
/* Terminating nul byte. */
destlen
++
;
/* Set up the destination buffer. */
if
(
len
)
{
if
(
len
<
destlen
)
return
gpg_error
(
GPG_ERR_INTERNAL
);
dest
=
*
destp
;
}
else
{
/* The converted string will never be larger than the original
string. */
dest
=
malloc
(
destlen
);
if
(
!
dest
)
return
gpg_error_from_syserror
();
*
destp
=
dest
;
}
/* Convert the string. */
while
(
*
src
)
{
if
(
*
src
==
'+'
||
*
src
==
'\"'
||
*
src
==
'%'
||
*
(
const
unsigned
char
*
)
src
<=
0x20
)
{
snprintf
(
dest
,
4
,
"%%%02X"
,
*
(
unsigned
char
*
)
src
);
dest
+=
3
;
}
else
*
(
dest
++
)
=
*
src
;
src
++
;
}
*
(
dest
++
)
=
0
;
return
0
;
}
/* Split a string into space delimited fields and remove leading and
* trailing spaces from each field. A pointer to each field is
* stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function
* modifies STRING. The number of parsed fields is returned.
*/
int
_gpgme_split_fields
(
char
*
string
,
char
**
array
,
int
arraysize
)
{
int
n
=
0
;
char
*
p
,
*
pend
;
for
(
p
=
string
;
*
p
==
' '
;
p
++
)
;
do
{
if
(
n
==
arraysize
)
break
;
array
[
n
++
]
=
p
;
pend
=
strchr
(
p
,
' '
);
if
(
!
pend
)
break
;
*
pend
++
=
0
;
for
(
p
=
pend
;
*
p
==
' '
;
p
++
)
;
}
while
(
*
p
);
return
n
;
}
/* Convert the field STRING into an unsigned long value. Check for
* trailing garbage. */
gpgme_error_t
_gpgme_strtoul_field
(
const
char
*
string
,
unsigned
long
*
result
)
{
char
*
endp
;
gpg_err_set_errno
(
0
);
*
result
=
strtoul
(
string
,
&
endp
,
0
);
if
(
errno
)
return
gpg_error_from_syserror
();
if
(
endp
==
string
||
*
endp
)
return
gpg_error
(
GPG_ERR_INV_VALUE
);
return
0
;
}
/* Convert STRING into an offset value. Note that this functions only
* allows for a base-10 length. This function is similar to atoi()
* and thus there is no error checking. */
uint64_t
_gpgme_string_to_off
(
const
char
*
string
)
{
uint64_t
value
=
0
;
while
(
*
string
==
' '
||
*
string
==
'\t'
)
string
++
;
for
(;
*
string
>=
'0'
&&
*
string
<=
'9'
;
string
++
)
{
value
*=
10
;
value
+=
atoi_1
(
string
);
}
return
value
;
}
#ifdef HAVE_W32_SYSTEM
static
time_t
_gpgme_timegm
(
struct
tm
*
tm
)
{
/* This one is thread safe. */
SYSTEMTIME
st
;
FILETIME
ft
;
unsigned
long
long
cnsecs
;
st
.
wYear
=
tm
->
tm_year
+
1900
;
st
.
wMonth
=
tm
->
tm_mon
+
1
;
st
.
wDay
=
tm
->
tm_mday
;
st
.
wHour
=
tm
->
tm_hour
;
st
.
wMinute
=
tm
->
tm_min
;
st
.
wSecond
=
tm
->
tm_sec
;
st
.
wMilliseconds
=
0
;
/* Not available. */
st
.
wDayOfWeek
=
0
;
/* Ignored. */
/* System time is UTC thus the conversion is pretty easy. */
if
(
!
SystemTimeToFileTime
(
&
st
,
&
ft
))
{
gpg_err_set_errno
(
EINVAL
);
return
(
time_t
)(
-1
);
}
cnsecs
=
(((
unsigned
long
long
)
ft
.
dwHighDateTime
<<
32
)
|
ft
.
dwLowDateTime
);
cnsecs
-=
116444736000000000ULL
;
/* The filetime epoch is 1601-01-01. */
return
(
time_t
)(
cnsecs
/
10000000ULL
);
}
#endif
/* Parse the string TIMESTAMP into a time_t. The string may either be
seconds since Epoch or in the ISO 8601 format like
"20390815T143012". Returns 0 for an empty string or seconds since
Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
point to the next non-parsed character in TIMESTRING. */
time_t
_gpgme_parse_timestamp
(
const
char
*
timestamp
,
char
**
endp
)
{
/* Need to skip leading spaces, because that is what strtoul does
but not our ISO 8601 checking code. */
while
(
*
timestamp
&&
*
timestamp
==
' '
)
timestamp
++
;
if
(
!*
timestamp
)
return
0
;
if
(
strlen
(
timestamp
)
>=
15
&&
timestamp
[
8
]
==
'T'
)
{
struct
tm
buf
;
int
year
;
year
=
atoi_4
(
timestamp
);
if
(
year
<
1900
)
return
(
time_t
)(
-1
);
if
(
endp
)
*
endp
=
(
char
*
)(
timestamp
+
15
);
/* Fixme: We would better use a configure test to see whether
mktime can handle dates beyond 2038. */
if
(
sizeof
(
time_t
)
<=
4
&&
year
>=
2038
)
return
(
time_t
)
2145914603
;
/* 2037-12-31 23:23:23 */
memset
(
&
buf
,
0
,
sizeof
buf
);
buf
.
tm_year
=
year
-
1900
;
buf
.
tm_mon
=
atoi_2
(
timestamp
+
4
)
-
1
;
buf
.
tm_mday
=
atoi_2
(
timestamp
+
6
);
buf
.
tm_hour
=
atoi_2
(
timestamp
+
9
);
buf
.
tm_min
=
atoi_2
(
timestamp
+
11
);
buf
.
tm_sec
=
atoi_2
(
timestamp
+
13
);
#ifdef HAVE_W32_SYSTEM
return
_gpgme_timegm
(
&
buf
);
#else
#ifdef HAVE_TIMEGM
return
timegm
(
&
buf
);
#else
{
time_t
tim
;
putenv
(
"TZ=UTC"
);
tim
=
mktime
(
&
buf
);
#ifdef __GNUC__
#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
#endif
return
tim
;
}
#endif
/* !HAVE_TIMEGM */
#endif
/* !HAVE_W32_SYSTEM */
}
else
return
(
time_t
)
strtoul
(
timestamp
,
endp
,
10
);
}
/* This function is similar to _gpgme_parse_timestamp but returns an
* unsigned long and 0 on error. */
unsigned
long
_gpgme_parse_timestamp_ul
(
const
char
*
timestamp
)
{
time_t
tim
;
char
*
tail
;
if
(
!*
timestamp
)
return
0
;
/* Shortcut empty strings. */
tim
=
_gpgme_parse_timestamp
(
timestamp
,
&
tail
);
if
(
tim
==
-1
||
timestamp
==
tail
||
(
*
tail
&&
*
tail
!=
' '
))
tim
=
0
;
/* No time given or invalid engine. */
return
(
unsigned
long
)
tim
;
}
/* The GPG backend uses OpenPGP algorithm numbers which we need to map
to our algorithm numbers. This function MUST not change ERRNO. */
int
_gpgme_map_pk_algo
(
int
algo
,
gpgme_protocol_t
protocol
)
{
if
(
protocol
==
GPGME_PROTOCOL_OPENPGP
)
{
switch
(
algo
)
{
case
1
:
case
2
:
case
3
:
case
16
:
case
17
:
break
;
case
18
:
algo
=
GPGME_PK_ECDH
;
break
;
case
19
:
algo
=
GPGME_PK_ECDSA
;
break
;
case
20
:
break
;
case
22
:
algo
=
GPGME_PK_EDDSA
;
break
;
default
:
algo
=
0
;
break
;
/* Unknown. */
}
}
return
algo
;
}
/* Return a string with a cipher algorithm. */
const
char
*
_gpgme_cipher_algo_name
(
int
algo
,
gpgme_protocol_t
protocol
)
{
if
(
protocol
==
GPGME_PROTOCOL_OPENPGP
)
{
/* The algo is given according to OpenPGP specs. */
switch
(
algo
)
{
case
1
:
return
"IDEA"
;
case
2
:
return
"3DES"
;
case
3
:
return
"CAST5"
;
case
4
:
return
"BLOWFISH"
;
case
7
:
return
"AES"
;
case
8
:
return
"AES192"
;
case
9
:
return
"AES256"
;
case
10
:
return
"TWOFISH"
;
case
11
:
return
"CAMELLIA128"
;
case
12
:
return
"CAMELLIA192"
;
case
13
:
return
"CAMELLIA256"
;
}
}
return
"Unknown"
;
}
/* Return a string with the cipher mode. */
const
char
*
_gpgme_cipher_mode_name
(
int
algo
,
gpgme_protocol_t
protocol
)
{
if
(
protocol
==
GPGME_PROTOCOL_OPENPGP
)
{
/* The algo is given according to OpenPGP specs. */
switch
(
algo
)
{
case
0
:
return
"CFB"
;
case
1
:
return
"EAX"
;
case
2
:
return
"OCB"
;
}
}
return
"Unknown"
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Feb 23, 7:57 PM (1 h, 23 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
98/70/ebcb3e35ccee94c6758ceb089bd6
Attached To
rM GPGME
Event Timeline
Log In to Comment