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
|
* Under Windows the default engines names are first searched in the
|
||||||
installation directory of the gpgme DLL.
|
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:
|
* Interface changes relative to the 1.4.2 release:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
gpgme_signers_count NEW.
|
gpgme_signers_count NEW.
|
||||||
|
gpgme_data_type_t NEW.
|
||||||
|
gpgme_data_identify NEW.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 1.4.2 (2013-05-28)
|
Noteworthy changes in version 1.4.2 (2013-05-28)
|
||||||
|
@ -1885,6 +1885,7 @@ be used to manipulate both.
|
|||||||
@menu
|
@menu
|
||||||
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
||||||
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
||||||
|
* Data Buffer Convenience:: Convenience fucntion for data buffers.
|
||||||
@end menu
|
@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}.
|
the data object with the handle @var{dh} to @var{enc}.
|
||||||
@end deftypefun
|
@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
|
||||||
@c Chapter Contexts
|
@c Chapter Contexts
|
||||||
|
@ -103,8 +103,9 @@ endif
|
|||||||
# unresolved symbols to the thread module.
|
# unresolved symbols to the thread module.
|
||||||
main_sources = \
|
main_sources = \
|
||||||
util.h conversion.c get-env.c context.h ops.h \
|
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.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 \
|
signers.c sig-notation.c \
|
||||||
wait.c wait-global.c wait-private.c wait-user.c wait.h \
|
wait.c wait-global.c wait-private.c wait-user.c wait.h \
|
||||||
op-support.c \
|
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_INCLUDE_CERTS,
|
||||||
STATUS_KEYLIST_MODE,
|
STATUS_KEYLIST_MODE,
|
||||||
STATUS_RECIPIENT,
|
STATUS_RECIPIENT,
|
||||||
STATUS_ENCRYPT_RESULT
|
STATUS_ENCRYPT_RESULT,
|
||||||
|
STATUS_IDENTIFY_RESULT
|
||||||
} status_t;
|
} status_t;
|
||||||
|
|
||||||
const char *status_string[] =
|
const char *status_string[] =
|
||||||
@ -1448,7 +1449,8 @@ const char *status_string[] =
|
|||||||
"INCLUDE_CERTS",
|
"INCLUDE_CERTS",
|
||||||
"KEYLIST_MODE",
|
"KEYLIST_MODE",
|
||||||
"RECIPIENT",
|
"RECIPIENT",
|
||||||
"ENCRYPT_RESULT"
|
"ENCRYPT_RESULT",
|
||||||
|
"IDENTIFY_RESULT"
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gpgme_tool
|
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
|
gpg_error_t
|
||||||
gt_passwd (gpgme_tool_t gt, char *fpr)
|
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_ENCRYPT 0x1
|
||||||
#define GT_RESULT_DECRYPT 0x2
|
#define GT_RESULT_DECRYPT 0x2
|
||||||
#define GT_RESULT_SIGN 0x4
|
#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
|
static gpg_error_t
|
||||||
cmd_passwd (assuan_context_t ctx, char *line)
|
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. */
|
/* Tell the assuan library about our commands. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
register_commands (assuan_context_t ctx)
|
register_commands (assuan_context_t ctx)
|
||||||
@ -3488,6 +3546,7 @@ register_commands (assuan_context_t ctx)
|
|||||||
{ "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
|
{ "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
|
||||||
{ "HASH_ALGO_NAME", cmd_hash_algo_name },
|
{ "HASH_ALGO_NAME", cmd_hash_algo_name },
|
||||||
{ "PASSWD", cmd_passwd, hlp_passwd },
|
{ "PASSWD", cmd_passwd, hlp_passwd },
|
||||||
|
{ "IDENTIFY", cmd_identify, hlp_identify },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
int idx;
|
int idx;
|
||||||
|
@ -211,5 +211,7 @@ EXPORTS
|
|||||||
|
|
||||||
gpgme_signers_count @160
|
gpgme_signers_count @160
|
||||||
|
|
||||||
|
gpgme_data_identify @161
|
||||||
|
|
||||||
; END
|
; END
|
||||||
|
|
||||||
|
@ -210,6 +210,22 @@ typedef enum
|
|||||||
}
|
}
|
||||||
gpgme_data_encoding_t;
|
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. */
|
/* Public key algorithms from libgcrypt. */
|
||||||
typedef enum
|
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,
|
gpgme_error_t gpgme_data_set_file_name (gpgme_data_t dh,
|
||||||
const char *file_name);
|
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
|
/* Create a new data buffer which retrieves the data from the callback
|
||||||
function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
|
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_set_file_name;
|
||||||
gpgme_data_get_file_name;
|
gpgme_data_get_file_name;
|
||||||
|
gpgme_data_identify;
|
||||||
|
|
||||||
gpgme_sig_notation_clear;
|
gpgme_sig_notation_clear;
|
||||||
gpgme_sig_notation_add;
|
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