Add function gpgme_data_identify.
* src/gpgme.h.in (gpgme_data_type_t): New. (gpgme_data_identify): New prototype. * src/data-identify.c: New. * src/parsetlv.c, src/parsetlv.h: New. Take from gpa. * src/libgpgme.vers, src/gpgme.def: Add gpgme_data_identify. * src/gpgme-tool.c (status): Add STATUS_IDENTIFY_RESULT. (gt_identify): New. (cmd_identify): New. (hlp_passwd): Move close to cmd_passwd. -- It is often useful to have a way to identify the data which needs processing. This is such a common task that it makes sense to implement this in gpgme to avoid diverging implementations.
This commit is contained in:
parent
a4c80126ae
commit
8579091c4f
4
NEWS
4
NEWS
@ -7,9 +7,13 @@ Noteworthy changes in version 1.4.3 (unreleased)
|
||||
* Under Windows the default engines names are first searched in the
|
||||
installation directory of the gpgme DLL.
|
||||
|
||||
* New function gpgme_data_identify to detect the type of a message.
|
||||
|
||||
* Interface changes relative to the 1.4.2 release:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
gpgme_signers_count NEW.
|
||||
gpgme_data_type_t NEW.
|
||||
gpgme_data_identify NEW.
|
||||
|
||||
|
||||
Noteworthy changes in version 1.4.2 (2013-05-28)
|
||||
|
@ -1885,6 +1885,7 @@ be used to manipulate both.
|
||||
@menu
|
||||
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
||||
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
||||
* Data Buffer Convenience:: Convenience fucntion for data buffers.
|
||||
@end menu
|
||||
|
||||
|
||||
@ -2047,6 +2048,56 @@ The function @code{gpgme_data_set_encoding} changes the encoding of
|
||||
the data object with the handle @var{dh} to @var{enc}.
|
||||
@end deftypefun
|
||||
|
||||
@node Data Buffer Convenience
|
||||
@subsection Data Buffer Convenience Functions
|
||||
@cindex data buffer, convenience
|
||||
@cindex type of data
|
||||
@cindex identify
|
||||
|
||||
@deftp {Data type} {enum gpgme_data_type_t}
|
||||
@tindex gpgme_data_type_t
|
||||
The @code{gpgme_data_type_t} type is used to return the detected type
|
||||
of the content of a data buffer.
|
||||
@end deftp
|
||||
|
||||
@table @code
|
||||
@item GPGME_DATA_TYPE_INVALID
|
||||
This is returned by @code{gpgme_data_identify} if it was not possible
|
||||
to identify the data. Reasons for this might be a non-seekable stream
|
||||
or a memory problem. The value is 0.
|
||||
@item GPGME_DATA_TYPE_UNKNOWN
|
||||
The type of the data is not known.
|
||||
@item GPGME_DATA_TYPE_PGP_SIGNED
|
||||
The data is an OpenPGP signed message. This may be a binary
|
||||
signature, a detached one or a cleartext signature.
|
||||
@item GPGME_DATA_TYPE_PGP_OTHER
|
||||
This is a generic OpenPGP message. In most cases this will be
|
||||
encrypted data.
|
||||
@item GPGME_DATA_TYPE_PGP_KEY
|
||||
This is an OpenPGP key (private or public).
|
||||
@item GPGME_DATA_TYPE_CMS_SIGNED
|
||||
This is a CMS signed message.
|
||||
@item GPGME_DATA_TYPE_CMS_ENCRYPTED
|
||||
This is a CMS encrypted (enveloped data) message.
|
||||
@item GPGME_DATA_TYPE_CMS_OTHER
|
||||
This is used for other CMS message types.
|
||||
@item GPGME_DATA_TYPE_X509_CERT
|
||||
The data is a X.509 certificate
|
||||
@item GPGME_DATA_TYPE_PKCS12
|
||||
The data is a PKCS#12 message. This is commonly used to exchange
|
||||
private keys for X.509.
|
||||
@end table
|
||||
|
||||
@deftypefun gpgme_data_type_t gpgme_data_identify (@w{gpgme_data_t @var{dh}})
|
||||
The function @code{gpgme_data_identify} returns the type of the data
|
||||
with the handle @var{dh}. If it is not possible to perform the
|
||||
identification, the function returns zero
|
||||
(@code{GPGME_DATA_TYPE_INVALID}). Note that depending on how the data
|
||||
object has been created the identification may not be possible or the
|
||||
data object may change its internal state (file pointer moved). For
|
||||
file or memory based data object, the state should not change.
|
||||
@end deftypefun
|
||||
|
||||
|
||||
@c
|
||||
@c Chapter Contexts
|
||||
|
@ -103,8 +103,9 @@ endif
|
||||
# unresolved symbols to the thread module.
|
||||
main_sources = \
|
||||
util.h conversion.c get-env.c context.h ops.h \
|
||||
parsetlv.c parsetlv.h \
|
||||
data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \
|
||||
data-compat.c \
|
||||
data-compat.c data-identify.c \
|
||||
signers.c sig-notation.c \
|
||||
wait.c wait-global.c wait-private.c wait-user.c wait.h \
|
||||
op-support.c \
|
||||
|
247
src/data-identify.c
Normal file
247
src/data-identify.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* data-identify.c - Try to identify the data
|
||||
Copyright (C) 2013 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gpgme.h"
|
||||
#include "data.h"
|
||||
#include "util.h"
|
||||
#include "parsetlv.h"
|
||||
|
||||
/* The size of the sample data we take for detection. */
|
||||
#define SAMPLE_SIZE 2048
|
||||
|
||||
|
||||
|
||||
/* Note that DATA may be binary but a final nul is required so that
|
||||
string operations will find a terminator.
|
||||
|
||||
Returns: GPGME_DATA_TYPE_xxxx */
|
||||
static gpgme_data_type_t
|
||||
basic_detection (const char *data, size_t datalen)
|
||||
{
|
||||
tlvinfo_t ti;
|
||||
const char *s;
|
||||
size_t n;
|
||||
int maybe_p12 = 0;
|
||||
|
||||
if (datalen < 24) /* Object is probably too short for detection. */
|
||||
return GPGME_DATA_TYPE_UNKNOWN;
|
||||
|
||||
/* This is a common example of a CMS object - it is obvious that we
|
||||
only need to read a few bytes to get to the OID:
|
||||
30 82 0B 59 06 09 2A 86 48 86 F7 0D 01 07 02 A0 82 0B 4A 30 82 0B 46 02
|
||||
----------- ++++++++++++++++++++++++++++++++
|
||||
SEQUENCE OID (signedData)
|
||||
(2 byte len)
|
||||
|
||||
A PKCS#12 message is:
|
||||
|
||||
30 82 08 59 02 01 03 30 82 08 1F 06 09 2A 86 48 86 F7 0D 01 07 01 A0 82
|
||||
----------- ++++++++ ----------- ++++++++++++++++++++++++++++++++
|
||||
SEQUENCE INTEGER SEQUENCE OID (data)
|
||||
|
||||
A X.509 certificate is:
|
||||
|
||||
30 82 05 B8 30 82 04 A0 A0 03 02 01 02 02 07 15 46 A0 BF 30 07 39 30 0D
|
||||
----------- +++++++++++ ----- ++++++++ --------------------------
|
||||
SEQUENCE SEQUENCE [0] INTEGER INTEGER SEQU
|
||||
(tbs) (version) (s/n) (Algo)
|
||||
|
||||
Thus we need to read at least 22 bytes, we add 2 bytes to cope with
|
||||
length headers stored with 4 bytes.
|
||||
*/
|
||||
|
||||
|
||||
s = data;
|
||||
n = datalen;
|
||||
|
||||
if (parse_tlv (&s, &n, &ti))
|
||||
goto try_pgp; /* Not properly BER encoded. */
|
||||
if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
|
||||
&& ti.is_cons))
|
||||
goto try_pgp; /* A CMS object always starts with a sequence. */
|
||||
|
||||
if (parse_tlv (&s, &n, &ti))
|
||||
goto try_pgp; /* Not properly BER encoded. */
|
||||
if (ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
|
||||
&& ti.is_cons && n >= ti.length)
|
||||
{
|
||||
if (parse_tlv (&s, &n, &ti))
|
||||
goto try_pgp;
|
||||
if (!(ti.cls == ASN1_CLASS_CONTEXT && ti.tag == 0
|
||||
&& ti.is_cons && ti.length == 3 && n >= ti.length))
|
||||
goto try_pgp;
|
||||
|
||||
if (parse_tlv (&s, &n, &ti))
|
||||
goto try_pgp;
|
||||
if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_INTEGER
|
||||
&& !ti.is_cons && ti.length == 1 && n && (*s == 1 || *s == 2)))
|
||||
goto try_pgp;
|
||||
s++;
|
||||
n--;
|
||||
if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_INTEGER
|
||||
&& !ti.is_cons))
|
||||
goto try_pgp;
|
||||
/* Because the now following S/N may be larger than the sample
|
||||
data we have, we stop parsing here and don't check for the
|
||||
algorithm ID. */
|
||||
return GPGME_DATA_TYPE_X509_CERT;
|
||||
}
|
||||
if (ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_INTEGER
|
||||
&& !ti.is_cons && ti.length == 1 && n && *s == 3)
|
||||
{
|
||||
maybe_p12 = 1;
|
||||
s++;
|
||||
n--;
|
||||
if (parse_tlv (&s, &n, &ti))
|
||||
goto try_pgp;
|
||||
if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
|
||||
&& ti.is_cons))
|
||||
goto try_pgp;
|
||||
if (parse_tlv (&s, &n, &ti))
|
||||
goto try_pgp;
|
||||
}
|
||||
if (ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
|
||||
&& !ti.is_cons && ti.length && n >= ti.length)
|
||||
{
|
||||
if (ti.length == 9)
|
||||
{
|
||||
if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x01", 9))
|
||||
{
|
||||
/* Data. */
|
||||
return (maybe_p12 ? GPGME_DATA_TYPE_PKCS12
|
||||
/* */ : GPGME_DATA_TYPE_CMS_OTHER);
|
||||
}
|
||||
if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", 9))
|
||||
{
|
||||
/* Signed Data. */
|
||||
return (maybe_p12 ? GPGME_DATA_TYPE_PKCS12
|
||||
/* */ : GPGME_DATA_TYPE_CMS_SIGNED);
|
||||
}
|
||||
if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x03", 9))
|
||||
return GPGME_DATA_TYPE_CMS_ENCRYPTED; /* Enveloped Data. */
|
||||
if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x05", 9))
|
||||
return GPGME_DATA_TYPE_CMS_OTHER; /* Digested Data. */
|
||||
if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x06", 9))
|
||||
return GPGME_DATA_TYPE_CMS_OTHER; /* Encrypted Data. */
|
||||
}
|
||||
else if (ti.length == 11)
|
||||
{
|
||||
if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x01\x02", 11))
|
||||
return GPGME_DATA_TYPE_CMS_OTHER; /* Auth Data. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try_pgp:
|
||||
/* Check whether this might be a non-armored PGP message. We need
|
||||
to do this before checking for armor lines, so that we don't get
|
||||
fooled by armored messages inside a signed binary PGP message. */
|
||||
if ((data[0] & 0x80))
|
||||
{
|
||||
/* That might be a binary PGP message. At least it is not plain
|
||||
ASCII. Of course this might be certain lead-in text of
|
||||
armored CMS messages. However, I am not sure whether this is
|
||||
at all defined and in any case it is uncommon. Thus we don't
|
||||
do any further plausibility checks but stupidly assume no CMS
|
||||
armored data will follow. */
|
||||
return GPGME_DATA_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Now check whether there are armor lines. */
|
||||
for (s = data; s && *s; s = (*s=='\n')?(s+1):((s=strchr (s,'\n'))?(s+1):s))
|
||||
{
|
||||
if (!strncmp (s, "-----BEGIN ", 11))
|
||||
{
|
||||
if (!strncmp (s+11, "SIGNED ", 7))
|
||||
return GPGME_DATA_TYPE_CMS_SIGNED;
|
||||
if (!strncmp (s+11, "ENCRYPTED ", 10))
|
||||
return GPGME_DATA_TYPE_CMS_ENCRYPTED;
|
||||
if (!strncmp (s+11, "PGP ", 4))
|
||||
{
|
||||
if (!strncmp (s+15, "SIGNATURE", 9))
|
||||
return GPGME_DATA_TYPE_PGP_SIGNED;
|
||||
if (!strncmp (s+15, "SIGNED MESSAGE", 14))
|
||||
return GPGME_DATA_TYPE_PGP_SIGNED;
|
||||
if (!strncmp (s+15, "PUBLIC KEY BLOCK", 16))
|
||||
return GPGME_DATA_TYPE_PGP_KEY;
|
||||
if (!strncmp (s+15, "PRIVATE KEY BLOCK", 17))
|
||||
return GPGME_DATA_TYPE_PGP_KEY;
|
||||
if (!strncmp (s+15, "SECRET KEY BLOCK", 16))
|
||||
return GPGME_DATA_TYPE_PGP_KEY;
|
||||
if (!strncmp (s+15, "ARMORED FILE", 12))
|
||||
return GPGME_DATA_TYPE_UNKNOWN;
|
||||
return GPGME_DATA_TYPE_PGP_OTHER; /* PGP MESSAGE */
|
||||
}
|
||||
if (!strncmp (s+11, "CERTIFICATE", 11))
|
||||
return GPGME_DATA_TYPE_X509_CERT;
|
||||
if (!strncmp (s+11, "PKCS12", 6))
|
||||
return GPGME_DATA_TYPE_PKCS12;
|
||||
return GPGME_DATA_TYPE_CMS_OTHER; /* Not PGP, thus we assume CMS. */
|
||||
}
|
||||
}
|
||||
|
||||
return GPGME_DATA_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* Try to detect the type of the data. Note that this function works
|
||||
only on seekable data objects. The function tries to reset the
|
||||
file pointer but there is no guarantee that it will work.
|
||||
|
||||
FIXME: We may want to add internal buffering so that this function
|
||||
can be implemented for allmost all kind of data objects.
|
||||
*/
|
||||
gpgme_data_type_t
|
||||
gpgme_data_identify (gpgme_data_t dh, int reserved)
|
||||
{
|
||||
gpgme_data_type_t result;
|
||||
char *sample;
|
||||
int n;
|
||||
gpgme_off_t off;
|
||||
|
||||
/* Check whether we can seek the data object. */
|
||||
off = gpgme_data_seek (dh, 0, SEEK_CUR);
|
||||
if (off == (gpgme_off_t)(-1))
|
||||
return GPGME_DATA_TYPE_INVALID;
|
||||
|
||||
/* Allocate a buffer and read the data. */
|
||||
sample = malloc (SAMPLE_SIZE);
|
||||
if (!sample)
|
||||
return GPGME_DATA_TYPE_INVALID; /* Ooops. */
|
||||
n = gpgme_data_read (dh, sample, SAMPLE_SIZE - 1);
|
||||
if (n < 0)
|
||||
{
|
||||
free (sample);
|
||||
return GPGME_DATA_TYPE_INVALID; /* Ooops. */
|
||||
}
|
||||
sample[n] = 0; /* (Required for our string functions.) */
|
||||
|
||||
result = basic_detection (sample, n);
|
||||
free (sample);
|
||||
gpgme_data_seek (dh, off, SEEK_SET);
|
||||
|
||||
return result;
|
||||
}
|
@ -1435,7 +1435,8 @@ typedef enum status
|
||||
STATUS_INCLUDE_CERTS,
|
||||
STATUS_KEYLIST_MODE,
|
||||
STATUS_RECIPIENT,
|
||||
STATUS_ENCRYPT_RESULT
|
||||
STATUS_ENCRYPT_RESULT,
|
||||
STATUS_IDENTIFY_RESULT
|
||||
} status_t;
|
||||
|
||||
const char *status_string[] =
|
||||
@ -1448,7 +1449,8 @@ const char *status_string[] =
|
||||
"INCLUDE_CERTS",
|
||||
"KEYLIST_MODE",
|
||||
"RECIPIENT",
|
||||
"ENCRYPT_RESULT"
|
||||
"ENCRYPT_RESULT",
|
||||
"IDENTIFY_RESULT"
|
||||
};
|
||||
|
||||
struct gpgme_tool
|
||||
@ -2065,11 +2067,6 @@ gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_passwd[] =
|
||||
"PASSWD <user-id>\n"
|
||||
"\n"
|
||||
"Ask the backend to change the passphrase for the key\n"
|
||||
"specified by USER-ID.";
|
||||
gpg_error_t
|
||||
gt_passwd (gpgme_tool_t gt, char *fpr)
|
||||
{
|
||||
@ -2086,6 +2083,29 @@ gt_passwd (gpgme_tool_t gt, char *fpr)
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
gt_identify (gpgme_tool_t gt, gpgme_data_t data)
|
||||
{
|
||||
const char *s = "?";
|
||||
|
||||
switch (gpgme_data_identify (data, 0))
|
||||
{
|
||||
case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
|
||||
case GPGME_DATA_TYPE_UNKNOWN : s = "unknown"; break;
|
||||
case GPGME_DATA_TYPE_PGP_SIGNED : s = "PGP-signed"; break;
|
||||
case GPGME_DATA_TYPE_PGP_OTHER : s = "PGP"; break;
|
||||
case GPGME_DATA_TYPE_PGP_KEY : s = "PGP-key"; break;
|
||||
case GPGME_DATA_TYPE_CMS_SIGNED : s = "CMS-signed"; break;
|
||||
case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
|
||||
case GPGME_DATA_TYPE_CMS_OTHER : s = "CMS"; break;
|
||||
case GPGME_DATA_TYPE_X509_CERT : s = "X.509"; break;
|
||||
case GPGME_DATA_TYPE_PKCS12 : s = "PKCS12"; break;
|
||||
}
|
||||
gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define GT_RESULT_ENCRYPT 0x1
|
||||
#define GT_RESULT_DECRYPT 0x2
|
||||
#define GT_RESULT_SIGN 0x4
|
||||
@ -3374,6 +3394,11 @@ cmd_vfs_create (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_passwd[] =
|
||||
"PASSWD <user-id>\n"
|
||||
"\n"
|
||||
"Ask the backend to change the passphrase for the key\n"
|
||||
"specified by USER-ID.";
|
||||
static gpg_error_t
|
||||
cmd_passwd (assuan_context_t ctx, char *line)
|
||||
{
|
||||
@ -3430,6 +3455,39 @@ cmd_hash_algo_name (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_identify[] =
|
||||
"IDENTIY\n"
|
||||
"\n"
|
||||
"Identify the type of data set with the INPUT command.";
|
||||
static gpg_error_t
|
||||
cmd_identify (assuan_context_t ctx, char *line)
|
||||
{
|
||||
struct server *server = assuan_get_pointer (ctx);
|
||||
gpg_error_t err;
|
||||
assuan_fd_t inp_fd;
|
||||
char *inp_fn;
|
||||
gpgme_data_t inp_data;
|
||||
|
||||
inp_fd = server->input_fd;
|
||||
inp_fn = server->input_filename;
|
||||
if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
|
||||
return GPG_ERR_ASS_NO_INPUT;
|
||||
|
||||
err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
|
||||
&server->input_stream);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = gt_identify (server->gt, inp_data);
|
||||
|
||||
gpgme_data_release (inp_data);
|
||||
server_reset_fds (server);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the assuan library about our commands. */
|
||||
static gpg_error_t
|
||||
register_commands (assuan_context_t ctx)
|
||||
@ -3488,6 +3546,7 @@ register_commands (assuan_context_t ctx)
|
||||
{ "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
|
||||
{ "HASH_ALGO_NAME", cmd_hash_algo_name },
|
||||
{ "PASSWD", cmd_passwd, hlp_passwd },
|
||||
{ "IDENTIFY", cmd_identify, hlp_identify },
|
||||
{ NULL }
|
||||
};
|
||||
int idx;
|
||||
|
@ -211,5 +211,7 @@ EXPORTS
|
||||
|
||||
gpgme_signers_count @160
|
||||
|
||||
gpgme_data_identify @161
|
||||
|
||||
; END
|
||||
|
||||
|
@ -210,6 +210,22 @@ typedef enum
|
||||
}
|
||||
gpgme_data_encoding_t;
|
||||
|
||||
/* Known data types. */
|
||||
typedef enum
|
||||
{
|
||||
GPGME_DATA_TYPE_INVALID = 0, /* Not detected. */
|
||||
GPGME_DATA_TYPE_UNKNOWN = 1,
|
||||
GPGME_DATA_TYPE_PGP_SIGNED = 0x10,
|
||||
GPGME_DATA_TYPE_PGP_OTHER = 0x12,
|
||||
GPGME_DATA_TYPE_PGP_KEY = 0x13,
|
||||
GPGME_DATA_TYPE_CMS_SIGNED = 0x20,
|
||||
GPGME_DATA_TYPE_CMS_ENCRYPTED= 0x21,
|
||||
GPGME_DATA_TYPE_CMS_OTHER = 0x22,
|
||||
GPGME_DATA_TYPE_X509_CERT = 0x23,
|
||||
GPGME_DATA_TYPE_PKCS12 = 0x24,
|
||||
}
|
||||
gpgme_data_type_t;
|
||||
|
||||
|
||||
/* Public key algorithms from libgcrypt. */
|
||||
typedef enum
|
||||
@ -1149,6 +1165,9 @@ char *gpgme_data_get_file_name (gpgme_data_t dh);
|
||||
gpgme_error_t gpgme_data_set_file_name (gpgme_data_t dh,
|
||||
const char *file_name);
|
||||
|
||||
/* Try to identify the type of the data in DH. */
|
||||
gpgme_data_type_t gpgme_data_identify (gpgme_data_t dh, int reserved);
|
||||
|
||||
|
||||
/* Create a new data buffer which retrieves the data from the callback
|
||||
function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
|
||||
|
@ -29,6 +29,7 @@ GPGME_1.1 {
|
||||
|
||||
gpgme_data_set_file_name;
|
||||
gpgme_data_get_file_name;
|
||||
gpgme_data_identify;
|
||||
|
||||
gpgme_sig_notation_clear;
|
||||
gpgme_sig_notation_add;
|
||||
|
103
src/parsetlv.c
Normal file
103
src/parsetlv.c
Normal file
@ -0,0 +1,103 @@
|
||||
/* parsetlv.c - ASN.1 TLV functions
|
||||
* Copyright (C) 2005, 2007, 2008, 2012 g10 Code GmbH
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* This file 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "parsetlv.h"
|
||||
|
||||
|
||||
/* Simple but pretty complete ASN.1 BER parser. Parse the data at the
|
||||
address of BUFFER with a length given at the address of SIZE. On
|
||||
success return 0 and update BUFFER and SIZE to point to the value.
|
||||
Do not update them on error. The information about the object are
|
||||
stored in the caller allocated TI structure. */
|
||||
int
|
||||
_gpgme_parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti)
|
||||
{
|
||||
int c;
|
||||
unsigned long tag;
|
||||
const unsigned char *buf = (const unsigned char *)(*buffer);
|
||||
size_t length = *size;
|
||||
|
||||
ti->cls = 0;
|
||||
ti->tag = 0;
|
||||
ti->is_cons = 0;
|
||||
ti->is_ndef = 0;
|
||||
ti->length = 0;
|
||||
ti->nhdr = 0;
|
||||
|
||||
if (!length)
|
||||
return -1;
|
||||
c = *buf++; length--; ++ti->nhdr;
|
||||
|
||||
ti->cls = (c & 0xc0) >> 6;
|
||||
ti->is_cons = !!(c & 0x20);
|
||||
tag = c & 0x1f;
|
||||
|
||||
if (tag == 0x1f)
|
||||
{
|
||||
tag = 0;
|
||||
do
|
||||
{
|
||||
tag <<= 7;
|
||||
if (!length)
|
||||
return -1;
|
||||
c = *buf++; length--; ++ti->nhdr;
|
||||
tag |= c & 0x7f;
|
||||
}
|
||||
while (c & 0x80);
|
||||
}
|
||||
ti->tag = tag;
|
||||
|
||||
if (!length)
|
||||
return -1;
|
||||
c = *buf++; length--; ++ti->nhdr;
|
||||
|
||||
if ( !(c & 0x80) )
|
||||
ti->length = c;
|
||||
else if (c == 0x80)
|
||||
ti->is_ndef = 1;
|
||||
else if (c == 0xff)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
unsigned long len = 0;
|
||||
int count = (c & 0x7f);
|
||||
|
||||
if (count > sizeof (len) || count > sizeof (size_t))
|
||||
return -1;
|
||||
|
||||
for (; count; count--)
|
||||
{
|
||||
len <<= 8;
|
||||
if (!length)
|
||||
return -1;
|
||||
c = *buf++; length--; ++ti->nhdr;
|
||||
len |= c & 0xff;
|
||||
}
|
||||
ti->length = len;
|
||||
}
|
||||
|
||||
*buffer = (void*)buf;
|
||||
*size = length;
|
||||
return 0;
|
||||
}
|
48
src/parsetlv.h
Normal file
48
src/parsetlv.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* parsetlv.h - TLV functions defintions
|
||||
* Copyright (C) 2012 g10 Code GmbH
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* This file 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PARSETLV_H
|
||||
#define PARSETLV_H
|
||||
|
||||
/* ASN.1 constants. */
|
||||
#define ASN1_CLASS_UNIVERSAL 0
|
||||
#define ASN1_CLASS_APPLICATION 1
|
||||
#define ASN1_CLASS_CONTEXT 2
|
||||
#define ASN1_CLASS_PRIVATE 3
|
||||
#define ASN1_TAG_INTEGER 2
|
||||
#define ASN1_TAG_OBJECT_ID 6
|
||||
#define ASN1_TAG_SEQUENCE 16
|
||||
|
||||
|
||||
/* Object used with parse_tlv. */
|
||||
struct tlvinfo_s
|
||||
{
|
||||
int cls; /* The class of the tag. */
|
||||
int tag; /* The tag. */
|
||||
int is_cons; /* True if it is a constructed object. */
|
||||
int is_ndef; /* True if the object has an indefinite length. */
|
||||
size_t length; /* The length of the value. */
|
||||
size_t nhdr; /* The number of octets in the header (tag,length). */
|
||||
};
|
||||
typedef struct tlvinfo_s tlvinfo_t;
|
||||
|
||||
/*-- parsetlv.c --*/
|
||||
int _gpgme_parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti);
|
||||
#define parse_tlv(a,b,c) _gpgme_parse_tlv ((a), (b), (c))
|
||||
|
||||
|
||||
#endif /*PARSETLV_H*/
|
Loading…
Reference in New Issue
Block a user