removing dead stuff

This commit is contained in:
Christian Grothoff
2008-08-24 15:17:11 +00:00
parent 45c6900e36
commit 2bdfce2c5a
43 changed files with 3 additions and 18967 deletions
-19
View File
@@ -218,24 +218,6 @@ AC_ARG_ENABLE([x509],
AC_MSG_RESULT($enable_x509)
# optional: OpenPGP support
AC_MSG_CHECKING(--enable-OpenPGP argument)
AC_ARG_ENABLE([OpenPGP],
[AS_HELP_STRING([--enable-OpenPGP],
[enable OpenPGP support (default is no)])],
[enable_openpgp=$enableval],
[enable_openpgp="no"])
AC_MSG_RESULT($enable_openpgp)
# currently we ignore this option.
if test "$enable_openpgp" = "yes"
then
AC_DEFINE([ENABLE_OPENPGP],[0],[Include OpenGPG support])
else
AC_DEFINE([ENABLE_OPENPGP],[0],[Include OpenGPG support])
fi
AM_CONDITIONAL(ENABLE_OPENPGP, test "$enable_openpgp" = "yes")
# Libgcrypt linkage : required for HTTPS support
AC_CHECK_HEADERS(gcrypt.h,gcrypt=true,gcrypt=false)
AC_ARG_WITH(libgcrypt,
@@ -342,7 +324,6 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
HTTPS support: ${enable_HTTPS}
TLS support: ${enable_TLS}
SSLv3 support: ${enable_SSL}
OpenGPG support: ${enable_openpgp}
x509 support: ${enable_x509}
libgcrypt: ${MSG_GCRYPT}
+1 -3
View File
@@ -42,9 +42,7 @@ libmicrohttpd_la_LIBADD = \
https/lgl/liblgl.la \
https/x509/libx509.la \
https/tls/libtls.la \
https/minitasn1/libasn1.la \
https/opencdk/libopencdk.la \
https/openpgp/libopenpgp.la
https/minitasn1/libasn1.la
endif
+1 -1
View File
@@ -24,7 +24,7 @@
* @author Christian Grothoff
*/
#include "config.h"
#include "platform.h"
#include "platform.h"
#include "microhttpd.h"
#include <stdlib.h>
+1 -6
View File
@@ -1,6 +1 @@
# placing '.' at the end of SUBDIRS having OPENPGP enabled mixes up build order !
SUBDIRS = minitasn1 lgl x509 tls
if ENABLE_OPENPGP
# SUBDIRS += opencdk openpgp
endif
SUBDIRS = minitasn1 lgl x509 tls .
-186
View File
@@ -1,186 +0,0 @@
/*
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* GNUTLS-EXTRA 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNUTLS-EXTRA; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Note the libgnutls-extra is not a standalone library. It requires
* to link also against libgnutls.
*/
#ifndef GNUTLS_EXTRA_H
#define GNUTLS_EXTRA_H
#include "gnutls.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define LIBGNUTLS_EXTRA_VERSION LIBGNUTLS_VERSION
/* Openpgp certificate stuff
*/
typedef enum gnutls_openpgp_crt_fmt
{ GNUTLS_OPENPGP_FMT_RAW,
GNUTLS_OPENPGP_FMT_BASE64
} gnutls_openpgp_crt_fmt_t;
/**
* mhd_gtls_openpgp_recv_key_func - Callback prototype to get OpenPGP keys
* @session: a TLS session
* @keyfpr: key fingerprint
* @keyfpr_length: length of key fingerprint
* @key: output key.
*
* A callback of this type is used to retrieve OpenPGP keys. Only
* useful on the server, and will only be used if the peer send a key
* fingerprint instead of a full key. See also
* gnutls_openpgp_set_recv_key_function().
*
*/
typedef int (*mhd_gtls_openpgp_recv_key_func) (mhd_gtls_session_t session,
const unsigned char *keyfpr,
unsigned int keyfpr_length,
gnutls_datum_t * key);
void gnutls_openpgp_set_recv_key_function (mhd_gtls_session_t session,
mhd_gtls_openpgp_recv_key_func
func);
int
gnutls_certificate_set_openpgp_key_file (mhd_gtls_cert_credentials_t
res, const char *CERTFILE,
const char *KEYFILE,
gnutls_openpgp_crt_fmt_t);
int gnutls_certificate_set_openpgp_key_mem (mhd_gtls_cert_credentials_t res,
const gnutls_datum_t * CERT,
const gnutls_datum_t * KEY,
gnutls_openpgp_crt_fmt_t);
int
gnutls_certificate_set_openpgp_keyring_mem
(mhd_gtls_cert_credentials_t c, const unsigned char *data,
size_t dlen, gnutls_openpgp_crt_fmt_t);
int
gnutls_certificate_set_openpgp_keyring_file
(mhd_gtls_cert_credentials_t c, const char *file,
gnutls_openpgp_crt_fmt_t);
/*
* TLS/IA stuff
*/
typedef enum
{
GNUTLS_IA_APPLICATION_PAYLOAD = 0,
GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED = 1,
GNUTLS_IA_FINAL_PHASE_FINISHED = 2
} gnutls_ia_apptype_t;
/*
* TLS/IA credential
*/
typedef int (*gnutls_ia_avp_func) (mhd_gtls_session_t session, void *ptr,
const char *last, size_t lastlen,
char **next, size_t * nextlen);
typedef struct gnutls_ia_server_credentials_st
*gnutls_ia_server_credentials_t;
typedef struct gnutls_ia_client_credentials_st
*gnutls_ia_client_credentials_t;
/* Allocate and free TLS/IA credentials. */
extern void
gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc);
extern int
gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t *
sc);
extern void
gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc);
extern int
gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t *
sc);
/* Client TLS/IA credential functions. */
extern void
gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
gnutls_ia_avp_func avp_func);
extern void
gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred,
void *ptr);
extern void *gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t
cred);
/* Server TLS/IA credential functions. */
extern void
gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
gnutls_ia_avp_func avp_func);
extern void
gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred,
void *ptr);
extern void *gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t
cred);
/* TLS/IA handshake. */
extern int gnutls_ia_handshake_p (mhd_gtls_session_t session);
extern int gnutls_ia_handshake (mhd_gtls_session_t session);
/* TLS/IA low level interface. */
extern int
gnutls_ia_permute_inner_secret (mhd_gtls_session_t session,
size_t session_keys_size,
const char *session_keys);
extern int gnutls_ia_endphase_send (mhd_gtls_session_t session,
int final_p);
extern int gnutls_ia_verify_endphase (mhd_gtls_session_t session,
const char *checksum);
extern ssize_t gnutls_ia_send (mhd_gtls_session_t session,
const char *data, size_t sizeofdata);
extern ssize_t gnutls_ia_recv (mhd_gtls_session_t session,
char *data, size_t sizeofdata);
/* Utility stuff. */
extern int gnutls_ia_generate_challenge (mhd_gtls_session_t session,
size_t buffer_size, char *buffer);
extern void gnutls_ia_extract_inner_secret (mhd_gtls_session_t session,
char *buffer);
/* Define whether inner phases are wanted. */
extern void gnutls_ia_enable (mhd_gtls_session_t session,
int allow_skip_on_resume);
int gnutls_global_init_extra (void);
/* returns libgnutls-extra version (call it with a NULL argument)
*/
const char *gnutls_extra_check_version (const char *req_version);
#ifdef __cplusplus
}
#endif
#endif
-14
View File
@@ -1,14 +0,0 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/include \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/lgl \
-I$(GCRYPT_CPPFLAGS)
noinst_LTLIBRARIES = libopencdk.la
libopencdk_la_LDFLAGS = -lgcrypt
libopencdk_la_SOURCES = armor.c filters.h main.c seskey.c types.h \
cipher.c kbnode.c main.h packet.h dummy.c sig-check.c verify.c \
compress.c keydb.c misc.c pubkey.c stream.c write-packet.c \
context.h literal.c new-packet.c read-packet.c stream.h opencdk.h
-5
View File
@@ -1,5 +0,0 @@
This is a stripped down mirror of the files in OpenCDK
src/. To avoid to link proc-packets.c, dummy.c is included.
In Makefile.am libminiopencdk_la_SOURCES contains the list
of all needed files.
-763
View File
@@ -1,763 +0,0 @@
/* armor.c - Armor filters
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*
* ChangeLog for basic BASE64 code (base64_encode, base64_decode):
* Original author: Eric S. Raymond (Fetchmail)
* Heavily modified by Brendan Cully <brendan@kublai.com> (Mutt)
* Modify the code for generic use by Timo Schulz <twoaday@freakmail.de>
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
#include "opencdk.h"
#include "main.h"
#include "filters.h"
#ifdef __MINGW32__
# define LF "\r\n"
#else
# define LF "\n"
#endif
#define CRCINIT 0xB704CE
#define BAD -1
#define b64val(c) index64[(unsigned int)(c)]
static u32 crc_table[] = {
0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC,
0x9F7F17,
0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5,
0x3EFE2E,
0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65,
0x5A319E,
0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C,
0xFBB0A7,
0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205,
0x93AEFE,
0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C,
0x322FC7,
0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C,
0x56E077,
0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5,
0xF7614E,
0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E,
0x86DCC5,
0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107,
0x275DFC,
0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7,
0x43924C,
0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E,
0xE21375,
0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7,
0x8A0D2C,
0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE,
0x2B8C15,
0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E,
0x4F43A5,
0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67,
0xEEC29C,
0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448,
0xAC38B3,
0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571,
0x0DB98A,
0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1,
0x69763A,
0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8,
0xC8F703,
0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1,
0xA0E95A,
0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498,
0x016863,
0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28,
0x65A7D3,
0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11,
0xC426EA,
0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A,
0xB59B61,
0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3,
0x141A58,
0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913,
0x70D5E8,
0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A,
0xD154D1,
0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673,
0xB94A88,
0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A,
0x18CBB1,
0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA,
0x7C0401,
0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3,
0xDD8538
};
static const char *armor_begin[] = {
"BEGIN PGP MESSAGE",
"BEGIN PGP PUBLIC KEY BLOCK",
"BEGIN PGP PRIVATE KEY BLOCK",
"BEGIN PGP SIGNATURE",
NULL
};
static const char *armor_end[] = {
"END PGP MESSAGE",
"END PGP PUBLIC KEY BLOCK",
"END PGP PRIVATE KEY BLOCK",
"END PGP SIGNATURE",
NULL
};
static const char *valid_headers[] = {
"Comment",
"Version",
"MessageID",
"Hash",
"Charset",
NULL
};
static char b64chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static int index64[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
};
/* encode a raw binary buffer to a null-terminated base64 strings */
static int
base64_encode (char *out, const byte * in, size_t len, size_t olen)
{
if (!out || !in)
return CDK_Inv_Value;
while (len >= 3 && olen > 10)
{
*out++ = b64chars[in[0] >> 2];
*out++ = b64chars[((in[0] << 4) & 0x30) | (in[1] >> 4)];
*out++ = b64chars[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
*out++ = b64chars[in[2] & 0x3f];
olen -= 4;
len -= 3;
in += 3;
}
/* clean up remainder */
if (len > 0 && olen > 4)
{
byte fragment = 0;
*out++ = b64chars[in[0] >> 2];
fragment = (in[0] << 4) & 0x30;
if (len > 1)
fragment |= in[1] >> 4;
*out++ = b64chars[fragment];
*out++ = (len < 2) ? '=' : b64chars[(in[1] << 2) & 0x3c];
*out++ = '=';
}
*out = '\0';
return 0;
}
/* Convert '\0'-terminated base64 string to raw byte buffer.
Returns length of returned buffer, or -1 on error. */
static int
base64_decode (byte * out, const char *in)
{
size_t len;
byte digit1, digit2, digit3, digit4;
if (!out || !in)
return -1;
len = 0;
do
{
digit1 = in[0];
if (digit1 > 127 || b64val (digit1) == BAD)
return -1;
digit2 = in[1];
if (digit2 > 127 || b64val (digit2) == BAD)
return -1;
digit3 = in[2];
if (digit3 > 127 || ((digit3 != '=') && (b64val (digit3) == BAD)))
return -1;
digit4 = in[3];
if (digit4 > 127 || ((digit4 != '=') && (b64val (digit4) == BAD)))
return -1;
in += 4;
/* digits are already sanity-checked */
*out++ = (b64val (digit1) << 2) | (b64val (digit2) >> 4);
len++;
if (digit3 != '=')
{
*out++ = ((b64val (digit2) << 4) & 0xf0) | (b64val (digit3) >> 2);
len++;
if (digit4 != '=')
{
*out++ = ((b64val (digit3) << 6) & 0xc0) | b64val (digit4);
len++;
}
}
}
while (*in && digit4 != '=');
return len;
}
/* Return the compression algorithm in @r_zipalgo.
If the parameter is not set after execution,
the stream is not compressed. */
static int
compress_get_algo (cdk_stream_t inp, int *r_zipalgo)
{
byte plain[512];
char buf[128];
int nread, pkttype;
*r_zipalgo = 0;
cdk_stream_seek (inp, 0);
while (!cdk_stream_eof (inp))
{
nread = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
if (!nread || nread == -1)
break;
if (nread == 1 && !cdk_stream_eof (inp)
&& (nread = _cdk_stream_gets (inp, buf, DIM (buf) - 1)) > 0)
{
base64_decode (plain, buf);
if (!(*plain & 0x80))
break;
pkttype = *plain & 0x40 ? (*plain & 0x3f) : ((*plain >> 2) & 0xf);
if (pkttype == CDK_PKT_COMPRESSED && r_zipalgo)
{
_cdk_log_debug ("armor compressed (algo=%d)\n", *(plain + 1));
*r_zipalgo = *(plain + 1);
}
break;
}
}
return 0;
}
static int
check_armor (cdk_stream_t inp, int *r_zipalgo)
{
char buf[4096];
size_t nread;
int check;
check = 0;
nread = cdk_stream_read (inp, buf, DIM (buf) - 1);
if (nread > 0)
{
buf[nread] = '\0';
if (strstr (buf, "-----BEGIN PGP"))
{
compress_get_algo (inp, r_zipalgo);
check = 1;
}
cdk_stream_seek (inp, 0);
}
return check;
}
static int
is_armored (int ctb)
{
int pkttype = 0;
if (!(ctb & 0x80))
return 1; /* invalid packet: assume it is armored */
pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb >> 2) & 0xf);
switch (pkttype)
{
case CDK_PKT_MARKER:
case CDK_PKT_SYMKEY_ENC:
case CDK_PKT_ONEPASS_SIG:
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_SECRET_KEY:
case CDK_PKT_PUBKEY_ENC:
case CDK_PKT_SIGNATURE:
case CDK_PKT_LITERAL:
case CDK_PKT_COMPRESSED:
case CDK_PKT_ENCRYPTED:
return 0; /* seems to be a regular packet: not armored */
}
return 1;
}
static u32
update_crc (u32 crc, const byte * buf, size_t buflen)
{
int j;
if (!crc)
crc = CRCINIT;
for (j = 0; j < buflen; j++)
crc = (crc << 8) ^ crc_table[0xff & ((crc >> 16) ^ buf[j])];
crc &= 0xffffff;
return crc;
}
static cdk_error_t
armor_encode (void *opaque, FILE * in, FILE * out)
{
armor_filter_t *afx = opaque;
struct stat statbuf;
char crcbuf[5], buf[128], raw[49];
byte crcbuf2[3];
size_t nread = 0;
const char *lf;
if (!afx)
return CDK_Inv_Value;
if (afx->idx < 0 || afx->idx > DIM (armor_begin) ||
afx->idx2 < 0 || afx->idx2 > DIM (armor_end))
return CDK_Inv_Value;
_cdk_log_debug ("armor filter: encode\n");
memset (crcbuf, 0, sizeof (crcbuf));
lf = afx->le ? afx->le : LF;
fprintf (out, "-----%s-----%s", armor_begin[afx->idx], lf);
fprintf (out, "Version: OpenPrivacy " PACKAGE_VERSION "%s", lf);
if (afx->hdrlines)
fwrite (afx->hdrlines, 1, strlen (afx->hdrlines), out);
fprintf (out, "%s", lf);
if (fstat (fileno (in), &statbuf))
return CDK_General_Error;
while (!feof (in))
{
nread = fread (raw, 1, DIM (raw) - 1, in);
if (!nread)
break;
if (ferror (in))
return CDK_File_Error;
afx->crc = update_crc (afx->crc, (byte *) raw, nread);
base64_encode (buf, (byte *) raw, nread, DIM (buf) - 1);
fprintf (out, "%s%s", buf, lf);
}
crcbuf2[0] = afx->crc >> 16;
crcbuf2[1] = afx->crc >> 8;
crcbuf2[2] = afx->crc;
crcbuf[0] = b64chars[crcbuf2[0] >> 2];
crcbuf[1] = b64chars[((crcbuf2[0] << 4) & 0x30) | (crcbuf2[1] >> 4)];
crcbuf[2] = b64chars[((crcbuf2[1] << 2) & 0x3c) | (crcbuf2[2] >> 6)];
crcbuf[3] = b64chars[crcbuf2[2] & 0x3f];
fprintf (out, "=%s%s", crcbuf, lf);
fprintf (out, "-----%s-----%s", armor_end[afx->idx2], lf);
return 0;
}
/**
* cdk_armor_filter_use:
* @inp: the stream to check
*
* Check if the stream contains armored data.
**/
int
cdk_armor_filter_use (cdk_stream_t inp)
{
int c, check;
int zipalgo;
zipalgo = 0;
c = cdk_stream_getc (inp);
if (c == EOF)
return 0; /* EOF, doesn't matter whether armored or not */
cdk_stream_seek (inp, 0);
check = is_armored (c);
if (check)
{
check = check_armor (inp, &zipalgo);
if (zipalgo)
_cdk_stream_set_compress_algo (inp, zipalgo);
}
return check;
}
static int
search_header (const char *buf, const char **array)
{
const char *s;
int i;
if (strlen (buf) < 5 || strncmp (buf, "-----", 5))
return -1;
for (i = 0; (s = array[i]); i++)
{
if (!strncmp (s, buf + 5, strlen (s)))
return i;
}
return -1;
}
const char *
_cdk_armor_get_lineend (void)
{
return LF;
}
static cdk_error_t
armor_decode (void *opaque, FILE * in, FILE * out)
{
armor_filter_t *afx = opaque;
const char *s;
char buf[127];
byte raw[128], crcbuf[4];
u32 crc2 = 0;
size_t nread = 0;
int i, pgp_data = 0;
cdk_error_t rc = 0;
if (!afx)
return CDK_Inv_Value;
_cdk_log_debug ("armor filter: decode\n");
fseek (in, 0, SEEK_SET);
/* Search the begin of the message */
while (!feof (in) && !pgp_data)
{
s = fgets (buf, DIM (buf) - 1, in);
if (!s)
break;
afx->idx = search_header (buf, armor_begin);
if (afx->idx >= 0)
pgp_data = 1;
}
if (feof (in) || !pgp_data)
return CDK_Armor_Error; /* no data found */
/* Parse header until the empty line is reached */
while (!feof (in))
{
s = fgets (buf, DIM (buf) - 1, in);
if (!s)
return CDK_EOF;
if (strlen (s) == strlen (LF))
{
rc = 0;
break; /* empty line */
}
/* From RFC2440: OpenPGP should consider improperly formatted Armor
Headers to be corruption of the ASCII Armor. A colon and a single
space separate the key and value. */
if (!strstr (buf, ": "))
return CDK_Armor_Error;
rc = CDK_General_Error;
for (i = 0; (s = valid_headers[i]); i++)
{
if (!strncmp (s, buf, strlen (s)))
rc = 0;
}
if (rc)
{
/* From RFC2440: Unknown keys should be reported to the user,
but OpenPGP should continue to process the message. */
_cdk_log_info ("unknown header: `%s'\n", buf);
rc = 0;
}
}
/* Read the data body */
while (!feof (in))
{
s = fgets (buf, DIM (buf) - 1, in);
if (!s)
break;
buf[strlen (buf) - strlen (LF)] = '\0';
if (buf[0] == '=' && strlen (s) == 5)
{ /* CRC */
memset (crcbuf, 0, sizeof (crcbuf));
base64_decode (crcbuf, buf + 1);
crc2 = (crcbuf[0] << 16) | (crcbuf[1] << 8) | crcbuf[2];
break; /* stop here */
}
else
{
nread = base64_decode (raw, buf);
if (nread == -1 || nread == 0)
break;
afx->crc = update_crc (afx->crc, raw, nread);
fwrite (raw, 1, nread, out);
}
}
/* Search the tail of the message */
s = fgets (buf, DIM (buf) - 1, in);
if (s)
{
buf[strlen (buf) - strlen (LF)] = '\0';
rc = CDK_General_Error;
afx->idx2 = search_header (buf, armor_end);
if (afx->idx2 >= 0)
rc = 0;
}
/* This catches error when no tail was found or the header is
different then the tail line. */
if (rc || afx->idx != afx->idx2)
rc = CDK_Armor_Error;
afx->crc_okay = (afx->crc == crc2) ? 1 : 0;
if (!afx->crc_okay && !rc)
{
_cdk_log_debug ("file crc=%08lX afx_crc=%08lX\n", crc2, afx->crc);
rc = CDK_Armor_CRC_Error;
}
return rc;
}
/**
* cdk_file_armor:
* @hd: Handle
* @file: Name of the file to protect.
* @output: Output filename.
*
* Protect a file with ASCII armor.
**/
cdk_error_t
cdk_file_armor (cdk_ctx_t hd, const char *file, const char *output)
{
cdk_stream_t inp, out;
cdk_error_t rc;
rc = _cdk_check_args (hd->opt.overwrite, file, output);
if (rc)
return rc;
rc = cdk_stream_open (file, &inp);
if (rc)
return rc;
rc = cdk_stream_new (output, &out);
if (rc)
{
cdk_stream_close (inp);
return rc;
}
cdk_stream_set_armor_flag (out, CDK_ARMOR_MESSAGE);
if (hd->opt.compress)
rc = cdk_stream_set_compress_flag (out, hd->compress.algo,
hd->compress.level);
if (!rc)
rc = cdk_stream_set_literal_flag (out, 0, file);
if (!rc)
rc = cdk_stream_kick_off (inp, out);
if (!rc)
rc = _cdk_stream_get_errno (out);
cdk_stream_close (out);
cdk_stream_close (inp);
return rc;
}
/**
* cdk_file_dearmor:
* @file: Name of the file to unprotect.
* @output: Output filename.
*
* Remove ASCII armor from a file.
**/
cdk_error_t
cdk_file_dearmor (const char *file, const char *output)
{
cdk_stream_t inp, out;
cdk_error_t rc;
int zipalgo;
rc = _cdk_check_args (1, file, output);
if (rc)
return rc;
rc = cdk_stream_open (file, &inp);
if (rc)
return rc;
rc = cdk_stream_create (output, &out);
if (rc)
{
cdk_stream_close (inp);
return rc;
}
if (cdk_armor_filter_use (inp))
{
rc = cdk_stream_set_literal_flag (inp, 0, NULL);
zipalgo = cdk_stream_is_compressed (inp);
if (zipalgo)
rc = cdk_stream_set_compress_flag (inp, zipalgo, 0);
if (!rc)
rc = cdk_stream_set_armor_flag (inp, 0);
if (!rc)
rc = cdk_stream_kick_off (inp, out);
if (!rc)
rc = _cdk_stream_get_errno (inp);
}
cdk_stream_close (inp);
cdk_stream_close (out);
return rc;
}
int
_cdk_filter_armor (void *opaque, int ctl, FILE * in, FILE * out)
{
if (ctl == STREAMCTL_READ)
return armor_decode (opaque, in, out);
else if (ctl == STREAMCTL_WRITE)
return armor_encode (opaque, in, out);
else if (ctl == STREAMCTL_FREE)
{
armor_filter_t *afx = opaque;
if (afx)
{
_cdk_log_debug ("free armor filter\n");
afx->idx = afx->idx2 = 0;
afx->crc = afx->crc_okay = 0;
return 0;
}
}
return CDK_Inv_Mode;
}
/**
* cdk_armor_encode_buffer:
* @inbuf: the raw input buffer
* @inlen: raw buffer len
* @outbuf: the destination buffer for the base64 output
* @outlen: destination buffer len
* @nwritten: actual length of the base64 data
* @type: the base64 file type.
*
* Encode the given buffer into base64 format.
**/
cdk_error_t
cdk_armor_encode_buffer (const byte * inbuf, size_t inlen,
char *outbuf, size_t outlen,
size_t * nwritten, int type)
{
const char *head, *tail, *le;
byte tempbuf[48];
char tempout[128];
size_t pos, off, len, rest;
if (!inbuf || !nwritten)
return CDK_Inv_Value;
if (type > CDK_ARMOR_SIGNATURE)
return CDK_Inv_Mode;
head = armor_begin[type];
tail = armor_end[type];
le = _cdk_armor_get_lineend ();
pos = strlen (head) + 10 + 2 + 2 + strlen (tail) + 10 + 2 + 5 + 2;
/* The output data is 4/3 times larger, plus a line end for each line. */
pos += (4 * inlen / 3) + 2 * (4 * inlen / 3 / 64);
if (outbuf && outlen < pos)
return CDK_Too_Short;
/* Only return the size of the output. */
if (!outbuf)
{
*nwritten = pos;
return 0;
}
pos = 0;
memset (outbuf, 0, outlen);
memcpy (outbuf + pos, "-----", 5);
pos += 5;
memcpy (outbuf + pos, head, strlen (head));
pos += strlen (head);
memcpy (outbuf + pos, "-----", 5);
pos += 5;
memcpy (outbuf + pos, le, strlen (le));
pos += strlen (le);
memcpy (outbuf + pos, le, strlen (le));
pos += strlen (le);
rest = inlen;
for (off = 0; off < inlen;)
{
if (rest > 48)
{
memcpy (tempbuf, inbuf + off, 48);
off += 48;
len = 48;
}
else
{
memcpy (tempbuf, inbuf + off, rest);
off += rest;
len = rest;
}
rest -= len;
base64_encode (tempout, tempbuf, len, DIM (tempout) - 1);
memcpy (outbuf + pos, tempout, strlen (tempout));
pos += strlen (tempout);
memcpy (outbuf + pos, le, strlen (le));
pos += strlen (le);
}
memcpy (outbuf + pos, "-----", 5);
pos += 5;
memcpy (outbuf + pos, tail, strlen (tail));
pos += strlen (tail);
memcpy (outbuf + pos, "-----", 5);
pos += 5;
memcpy (outbuf + pos, le, strlen (le));
pos += strlen (le);
*nwritten = pos;
return 0;
}
-528
View File
@@ -1,528 +0,0 @@
/* cipher.c - Cipher filters
* Copyright (C) 2002, 2003, 2007 Timo Schulz
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <assert.h>
#include <sys/stat.h>
#include "opencdk.h"
#include "main.h"
#include "filters.h"
/* The maximal cipher block size in octets. */
#define MAX_CIPHER_BLKSIZE 16
static off_t
fp_get_length (FILE * fp)
{
struct stat statbuf;
if (fstat (fileno (fp), &statbuf))
return (off_t) - 1;
return statbuf.st_size;
}
static cdk_error_t
hash_encode (void *opaque, FILE * in, FILE * out)
{
md_filter_t *mfx = opaque;
byte buf[BUFSIZE];
gcry_error_t err;
int nread;
if (!mfx)
return CDK_Inv_Value;
_cdk_log_debug ("hash filter: encode algo=%d\n", mfx->digest_algo);
if (!mfx->md)
{
err = gcry_md_open (&mfx->md, mfx->digest_algo, 0);
if (err)
return map_gcry_error (err);
}
while (!feof (in))
{
nread = fread (buf, 1, BUFSIZE, in);
if (!nread)
break;
gcry_md_write (mfx->md, buf, nread);
}
wipemem (buf, sizeof (buf));
return 0;
}
cdk_error_t
_cdk_filter_hash (void *opaque, int ctl, FILE * in, FILE * out)
{
if (ctl == STREAMCTL_READ)
return hash_encode (opaque, in, out);
else if (ctl == STREAMCTL_FREE)
{
md_filter_t *mfx = opaque;
if (mfx)
{
_cdk_log_debug ("free hash filter\n");
gcry_md_close (mfx->md);
mfx->md = NULL;
return 0;
}
}
return CDK_Inv_Mode;
}
static cdk_error_t
write_header (cipher_filter_t * cfx, FILE * out)
{
cdk_pkt_encrypted_t ed;
cdk_packet_t pkt;
cdk_error_t rc;
cdk_dek_t dek = cfx->dek;
byte temp[MAX_CIPHER_BLKSIZE + 2];
size_t blocksize;
int use_mdc, nprefix;
gcry_error_t err;
blocksize = gcry_cipher_get_algo_blklen (dek->algo);
if (blocksize < 8 || blocksize > 16)
return CDK_Inv_Algo;
/* It might be possible the receiver does not understand the MDC
output and thus we offer to supress the MDC packet. */
use_mdc = dek->use_mdc;
if (blocksize == 8)
use_mdc = 0;
/* We need to increase the data length because the MDC packet will
be also included. It has a fixed length of 22 octets. */
if (use_mdc && cfx->datalen)
cfx->datalen += 22;
cdk_pkt_alloc (&pkt, CDK_PKT_ENCRYPTED_MDC);
ed = pkt->pkt.encrypted;
if (!cfx->blkmode.on)
{
ed->len = cfx->datalen;
ed->extralen = blocksize + 2;
}
else
cfx->blkmode.nleft = DEF_BLOCKSIZE;
if (use_mdc)
{
ed->mdc_method = GCRY_MD_SHA1;
err = gcry_md_open (&cfx->mdc, GCRY_MD_SHA1, 0);
if (err)
return map_gcry_error (err);
}
/* When we use partial bodies, the MDC feature or a blocksize
larger than 8, we force the use of the new packet format. */
if (cfx->blkmode.on || use_mdc || blocksize != 8)
pkt->old_ctb = 0;
else
pkt->old_ctb = 1;
pkt->pkttype = use_mdc ? CDK_PKT_ENCRYPTED_MDC : CDK_PKT_ENCRYPTED;
rc = _cdk_pkt_write_fp (out, pkt);
cdk_pkt_release (pkt);
if (rc)
return rc;
nprefix = blocksize;
gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM);
temp[nprefix] = temp[nprefix - 2];
temp[nprefix + 1] = temp[nprefix - 1];
err = gcry_cipher_open (&cfx->hd, dek->algo, GCRY_CIPHER_MODE_CFB,
use_mdc ? 0 : GCRY_CIPHER_ENABLE_SYNC);
if (err)
return map_gcry_error (err);
err = gcry_cipher_setiv (cfx->hd, NULL, 0);
if (err)
return map_gcry_error (err);
err = gcry_cipher_setkey (cfx->hd, dek->key, dek->keylen);
if (err)
return map_gcry_error (err);
if (cfx->mdc)
gcry_md_write (cfx->mdc, temp, nprefix + 2);
gcry_cipher_encrypt (cfx->hd, temp, nprefix + 2, NULL, 0);
gcry_cipher_sync (cfx->hd);
fwrite (temp, 1, nprefix + 2, out);
if (cfx->blkmode.on)
{
cfx->blkmode.nleft -= (nprefix + 2);
if (use_mdc)
cfx->blkmode.nleft--; /* 1 byte version */
}
return rc;
}
static cdk_error_t
write_mdc_packet (FILE * out, cipher_filter_t * cfx)
{
byte pktdata[22];
int dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
if (!out || !cfx)
return CDK_Inv_Value;
if (dlen != 20)
return CDK_Inv_Algo;
/* We must hash the prefix of the MDC packet here */
pktdata[0] = 0xD3;
pktdata[1] = 0x14;
gcry_md_write (cfx->mdc, pktdata, 2);
gcry_md_final (cfx->mdc);
memcpy (pktdata + 2, gcry_md_read (cfx->mdc, GCRY_MD_SHA1), dlen);
gcry_cipher_encrypt (cfx->hd, pktdata, dlen + 2, NULL, 0);
fwrite (pktdata, 1, dlen + 2, out);
wipemem (pktdata, sizeof (pktdata));
return 0;
}
static inline int
num2bits (size_t n)
{
size_t i;
for (i = 0; n > 1; i++)
n >>= 1;
return i;
}
static cdk_error_t
write_partial_block (FILE * in, FILE * out, off_t * r_len,
cipher_filter_t * cfx)
{
gcry_error_t err;
byte buf[DEF_BLOCKSIZE];
size_t n;
int nread;
if (!out || !cfx)
return CDK_Inv_Value;
if (!cfx->blkmode.nleft && *r_len > 0)
{
if (*r_len > DEF_BLOCKSIZE)
{
/*_cdk_log_debug ("write_partial_block: size %lu block %d\n",
*r_len, DEF_BLOCKSIZE);*/
fputc ((0xE0 | DEF_BLOCKBITS), out);
cfx->blkmode.nleft = DEF_BLOCKSIZE;
(*r_len) -= DEF_BLOCKSIZE;
}
else if (*r_len > 512)
{
n = num2bits (*r_len);
cfx->blkmode.nleft = (1 << n);
/*_cdk_log_debug ("write_partial_block: size %lu bits %d block %d\n",
*r_len, n, (1<<n));*/
fputc ((0xE0 | n), out);
(*r_len) -= cfx->blkmode.nleft;
}
else
{
size_t pktlen = *r_len;
/* If we use the MDC mode, we need to increase the final
partial body length to hold the mdc packet itself. */
if (cfx->mdc)
pktlen += 22;
if (pktlen < 192)
fputc (pktlen, out);
else if (pktlen < 8384)
{
pktlen -= 192;
fputc ((pktlen / 256) + 192, out);
fputc ((pktlen % 256), out);
}
cfx->blkmode.nleft = pktlen;
/*_cdk_log_debug ("write_partial_block: end %d block\n", pktlen);*/
(*r_len) -= pktlen;
}
}
else
(*r_len) -= cfx->blkmode.nleft;
n = cfx->blkmode.nleft < DIM (buf) ? cfx->blkmode.nleft : DIM (buf);
nread = fread (buf, 1, n, in);
if (!nread)
return CDK_EOF;
if (cfx->mdc)
gcry_md_write (cfx->mdc, buf, nread);
err = gcry_cipher_encrypt (cfx->hd, buf, nread, NULL, 0);
if (err)
return map_gcry_error (err);
fwrite (buf, 1, nread, out);
cfx->blkmode.nleft -= nread;
return 0;
}
static cdk_error_t
cipher_encode_file (void *opaque, FILE * in, FILE * out)
{
cipher_filter_t *cfx = opaque;
byte buf[BUFSIZE];
off_t len, len2;
int nread;
cdk_error_t rc;
if (!cfx || !in || !out)
return CDK_Inv_Value;
len = len2 = fp_get_length (in);
if (len == (off_t) - 1)
return CDK_File_Error;
while (!feof (in))
{
if (cfx->blkmode.on)
{
rc = write_partial_block (in, out, &len2, cfx);
if (rc == CDK_EOF)
break;
if (rc)
{
wipemem (buf, sizeof (buf));
return rc;
}
continue;
}
nread = fread (buf, 1, DIM (buf), in);
if (!nread)
break;
if (cfx->mdc)
gcry_md_write (cfx->mdc, buf, nread);
gcry_cipher_encrypt (cfx->hd, buf, nread, NULL, 0);
fwrite (buf, 1, nread, out);
}
if (cfx->mdc)
rc = write_mdc_packet (out, cfx);
else
rc = 0;
wipemem (buf, sizeof (buf));
return rc;
}
static cdk_error_t
read_header (cipher_filter_t * cfx, FILE * in)
{
cdk_dek_t dek;
byte temp[32];
int blocksize, nprefix;
int i, c;
gcry_error_t err;
if (!cfx || !in)
return CDK_Inv_Value;
dek = cfx->dek;
blocksize = gcry_cipher_get_algo_blklen (dek->algo);
if (blocksize < 8 || blocksize > 16)
return CDK_Inv_Algo;
nprefix = blocksize;
if (cfx->datalen > 0 && cfx->datalen < (nprefix + 2))
return CDK_Inv_Value;
if (cfx->mdc_method)
{
err = gcry_md_open (&cfx->mdc, cfx->mdc_method, 0);
if (err)
return map_gcry_error (err);
}
err = gcry_cipher_open (&cfx->hd, dek->algo, GCRY_CIPHER_MODE_CFB,
cfx->mdc_method ? 0 : GCRY_CIPHER_ENABLE_SYNC);
if (err)
return map_gcry_error (err);
err = gcry_cipher_setiv (cfx->hd, NULL, 0);
if (err)
return map_gcry_error (err);
err = gcry_cipher_setkey (cfx->hd, dek->key, dek->keylen);
if (err)
return map_gcry_error (err);
for (i = 0; i < (nprefix + 2); i++)
{
c = fgetc (in);
if (c == EOF)
return CDK_File_Error;
temp[i] = c;
}
gcry_cipher_decrypt (cfx->hd, temp, nprefix + 2, NULL, 0);
gcry_cipher_sync (cfx->hd);
i = nprefix;
if (temp[i - 2] != temp[i] || temp[i - 1] != temp[i + 1])
return CDK_Chksum_Error;
if (cfx->mdc)
gcry_md_write (cfx->mdc, temp, nprefix + 2);
if (cfx->blkmode.on)
cfx->blkmode.size -= (nprefix + 2);
return 0;
}
static cdk_error_t
finalize_mdc (gcry_md_hd_t md, const byte * buf, size_t nread)
{
byte mdcbuf[20];
int dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
cdk_error_t rc;
if (dlen != 20)
return CDK_Inv_Algo;
if (buf[nread - dlen - 2] == 0xD3 && buf[nread - dlen - 1] == 0x14)
{
gcry_md_write (md, buf, nread - dlen);
gcry_md_final (md);
memcpy (mdcbuf, gcry_md_read (md, GCRY_MD_SHA1), dlen);
if (memcmp (mdcbuf, buf + nread - dlen, dlen))
rc = CDK_Bad_MDC;
else
rc = CDK_Success;
wipemem (mdcbuf, sizeof (mdcbuf));
return rc;
}
return CDK_Inv_Packet;
}
static cdk_error_t
cipher_decode_file (void *opaque, FILE * in, FILE * out)
{
cipher_filter_t *cfx = opaque;
cdk_error_t rc;
byte buf[BUFSIZE];
int nread, nreq;
if (!cfx || !in || !out)
return CDK_Inv_Value;
while (!feof (in))
{
/*_cdk_log_debug ("partial on=%d size=%lu\n",
cfx->blkmode.on, cfx->blkmode.size);*/
nreq = cfx->blkmode.on ? cfx->blkmode.size : DIM (buf);
nread = fread (buf, 1, nreq, in);
if (!nread)
break;
gcry_cipher_decrypt (cfx->hd, buf, nread, NULL, 0);
if (feof (in) && cfx->mdc)
{
rc = finalize_mdc (cfx->mdc, buf, nread);
if (rc)
{
wipemem (buf, sizeof (buf));
return rc;
}
/* We need to correct the size here to avoid the MDC
packet will be written to the output. */
nread -= 22;
}
else if (cfx->mdc)
gcry_md_write (cfx->mdc, buf, nread);
fwrite (buf, 1, nread, out);
if (cfx->blkmode.on)
{
cfx->blkmode.size = _cdk_pkt_read_len (in, &cfx->blkmode.on);
if (cfx->blkmode.size == (size_t) EOF)
return CDK_Inv_Packet;
}
}
wipemem (buf, sizeof (buf));
return 0;
}
static cdk_error_t
cipher_decode (void *opaque, FILE * in, FILE * out)
{
cipher_filter_t *cfx = opaque;
cdk_error_t rc;
_cdk_log_debug ("cipher filter: decode\n");
if (!cfx || !in || !out)
return CDK_Inv_Value;
rc = read_header (cfx, in);
if (!rc)
rc = cipher_decode_file (cfx, in, out);
return rc;
}
static cdk_error_t
cipher_encode (void *opaque, FILE * in, FILE * out)
{
cipher_filter_t *cfx = opaque;
cdk_error_t rc;
_cdk_log_debug ("cipher filter: encode\n");
if (!cfx || !in || !out)
return CDK_Inv_Value;
cfx->datalen = fp_get_length (in);
if (cfx->datalen < BUFSIZE && cfx->blkmode.on)
cfx->blkmode.on = 0;
rc = write_header (cfx, out);
if (!rc)
rc = cipher_encode_file (cfx, in, out);
return rc;
}
cdk_error_t
_cdk_filter_cipher (void *opaque, int ctl, FILE * in, FILE * out)
{
if (ctl == STREAMCTL_READ)
return cipher_decode (opaque, in, out);
else if (ctl == STREAMCTL_WRITE)
return cipher_encode (opaque, in, out);
else if (ctl == STREAMCTL_FREE)
{
cipher_filter_t *cfx = opaque;
if (cfx)
{
_cdk_log_debug ("free cipher filter\n");
gcry_md_close (cfx->mdc);
cfx->mdc = NULL;
gcry_cipher_close (cfx->hd);
cfx->hd = NULL;
return 0;
}
}
return CDK_Inv_Mode;
}
-238
View File
@@ -1,238 +0,0 @@
/* compress.c - Compression filters
* Copyright (C) 2002, 2003 Timo Schulz
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <time.h>
#ifdef HAVE_LIBZ
# include <zlib.h>
#endif
#include "opencdk.h"
#include "main.h"
#include "filters.h"
#ifdef HAVE_LIBZ
static int
compress_data (z_stream * zs, int flush, byte * inbuf, size_t insize,
FILE * out)
{
int nbytes, zrc;
byte buf[4096];
zs->next_in = inbuf;
zs->avail_in = insize;
do
{
zs->next_out = buf;
zs->avail_out = DIM (buf);
zrc = deflate (zs, flush);
if (zrc == Z_STREAM_END && flush == Z_FINISH)
;
else if (zrc != Z_OK)
break;
nbytes = DIM (buf) - zs->avail_out;
fwrite (buf, 1, nbytes, out);
}
while (zs->avail_out == 0 || (flush == Z_FINISH && zrc != Z_STREAM_END));
return zrc;
}
static int
decompress_data (compress_filter_t * zfx, z_stream * zs,
FILE * in, size_t * ret_len)
{
int nread, nold;
int rc, zrc;
rc = 0;
nread = 0;
while (zs->avail_out != 0)
{
if (!zs->avail_in)
{
nread = fread (zfx->inbuf, 1, zfx->inbufsize, in);
zs->next_in = zfx->inbuf;
zs->avail_in = nread;
}
nold = zs->avail_out;
zrc = inflate (zs, Z_SYNC_FLUSH);
if (zrc != Z_OK && zrc != Z_STREAM_END)
{
rc = CDK_Zlib_Error;
break;
}
*ret_len = zfx->outbufsize - zs->avail_out;
if (nold == zs->avail_out)
break;
if (zrc == Z_STREAM_END)
{
rc = EOF; /* eof */
break;
}
}
if (!nread && feof (in))
rc = -1;
return rc;
}
static cdk_error_t
compress_decode (void *opaque, FILE * in, FILE * out)
{
compress_filter_t *zfx = opaque;
z_stream *zs;
size_t nbytes;
int zrc;
cdk_error_t rc = 0;
_cdk_log_debug ("compress filter: decode (algo=%d)\n", zfx->algo);
if (!zfx || !in || !out)
return CDK_Inv_Value;
zs = cdk_calloc (1, sizeof *zs);
if (!zs)
return CDK_Out_Of_Core;
if (zfx->algo == CDK_COMPRESS_ZIP)
zrc = inflateInit2 (zs, -13);
else
zrc = inflateInit (zs);
if (zrc != Z_OK)
return CDK_Zlib_Error;
zfx->outbufsize = 8192;
zfx->inbufsize = 2048;
memset (zfx->inbuf, 0, sizeof zfx->inbuf);
zs->avail_in = 0;
nbytes = 0;
while (rc != -1)
{
zs->next_out = zfx->outbuf;
zs->avail_out = 8192;
rc = decompress_data (zfx, zs, in, &nbytes);
fwrite (zfx->outbuf, 1, nbytes, out);
}
inflateEnd (zs);
cdk_free (zs);
if (rc == CDK_EOF)
rc = 0;
return rc;
}
static cdk_error_t
compress_encode (void *opaque, FILE * in, FILE * out)
{
compress_filter_t *zfx = opaque;
z_stream *zs;
struct cdk_pkt_compressed_s cd;
struct cdk_packet_s pkt;
int zrc, nread;
cdk_error_t rc;
_cdk_log_debug ("compress filter: encode\n");
if (!zfx || !in || !out)
return CDK_Inv_Value;
if (!zfx->algo)
zfx->algo = CDK_COMPRESS_ZIP;
memset (&cd, 0, sizeof (cd));
cd.len = 0;
cd.algorithm = zfx->algo;
pkt.pkttype = CDK_PKT_COMPRESSED;
pkt.pkt.compressed = &cd;
rc = _cdk_pkt_write_fp (out, &pkt);
if (rc)
return rc;
zs = cdk_calloc (1, sizeof *zs);
if (!zs)
return CDK_Out_Of_Core;
if (zfx->algo == CDK_COMPRESS_ZIP)
rc = deflateInit2 (zs, zfx->level, Z_DEFLATED, -13, 8,
Z_DEFAULT_STRATEGY);
else
rc = deflateInit (zs, zfx->level);
if (rc != Z_OK)
{
cdk_free (zs);
return CDK_Zlib_Error;
}
zfx->outbufsize = 8192;
memset (zfx->outbuf, 0, sizeof zfx->outbuf);
while (!feof (in))
{
nread = fread (zfx->outbuf, 1, zfx->outbufsize, in);
if (!nread)
break;
zrc = compress_data (zs, Z_NO_FLUSH, zfx->outbuf, nread, out);
if (zrc)
{
rc = CDK_Zlib_Error;
break;
}
}
if (!rc)
{
nread = 0;
zrc = compress_data (zs, Z_FINISH, zfx->outbuf, nread, out);
if (zrc != Z_STREAM_END)
rc = CDK_Zlib_Error;
}
deflateEnd (zs);
cdk_free (zs);
return rc;
}
cdk_error_t
_cdk_filter_compress (void *opaque, int ctl, FILE * in, FILE * out)
{
if (ctl == STREAMCTL_READ)
return compress_decode (opaque, in, out);
else if (ctl == STREAMCTL_WRITE)
return compress_encode (opaque, in, out);
else if (ctl == STREAMCTL_FREE)
{
compress_filter_t *zfx = opaque;
if (zfx)
{
_cdk_log_debug ("free compress filter\n");
zfx->level = 0;
zfx->algo = 0;
return 0;
}
}
return CDK_Inv_Mode;
}
#else
cdk_error_t
_cdk_filter_compress (void *opaque, int ctl, FILE * in, FILE * out)
{
return CDK_Not_Implemented;
}
#endif /* HAVE_LIBZ */
-120
View File
@@ -1,120 +0,0 @@
/* context.h
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef CDK_CONTEXT_H
#define CDK_CONTEXT_H
#include "types.h"
struct cdk_listkey_s {
unsigned init:1;
cdk_stream_t inp;
cdk_keydb_hd_t db;
int type;
union {
char *patt;
cdk_strlist_t fpatt;
} u;
cdk_strlist_t t;
};
struct cdk_s2k_s {
int mode;
byte hash_algo;
byte salt[8];
u32 count;
};
struct cdk_ctx_s {
int cipher_algo;
int digest_algo;
struct {
int algo;
int level;
} compress;
struct {
int mode;
int digest_algo;
} _s2k;
struct {
unsigned blockmode:1;
unsigned armor:1;
unsigned textmode:1;
unsigned compress:1;
unsigned mdc:1;
unsigned overwrite;
unsigned force_digest:1;
} opt;
struct {
cdk_verify_result_t verify;
} result;
struct {
cdk_pkt_seckey_t sk;
unsigned on:1;
} cache;
cdk_dek_t dek;
struct {
cdk_keydb_hd_t sec;
cdk_keydb_hd_t pub;
unsigned int close_db:1;
} db;
char *(*passphrase_cb) (void *opaque, const char *prompt);
void * passphrase_cb_value;
};
struct cdk_prefitem_s {
byte type;
byte value;
};
struct cdk_desig_revoker_s {
struct cdk_desig_revoker_s * next;
byte r_class;
byte algid;
byte fpr[KEY_FPR_LEN];
};
struct cdk_subpkt_s {
struct cdk_subpkt_s * next;
u32 size;
byte type;
byte d[1];
};
struct cdk_keylist_s {
struct cdk_keylist_s * next;
union {
cdk_pkt_pubkey_t pk;
cdk_pkt_seckey_t sk;
} key;
int version;
int type;
};
struct cdk_dek_s {
int algo;
int keylen;
int use_mdc;
byte key[32]; /* 256-bit */
};
struct cdk_strlist_s {
struct cdk_strlist_s * next;
char d[1];
};
#endif /* CDK_CONTEXT_H */
-15
View File
@@ -1,15 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "opencdk.h"
#include "main.h"
#include "filters.h"
#include "packet.h"
cdk_error_t
_cdk_proc_packets (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t data,
const char *output, cdk_stream_t outstream,
gcry_md_hd_t md)
{
return 0;
}
-95
View File
@@ -1,95 +0,0 @@
/* filters.h - Filter structs
* Copyright (C) 2002, 2003 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef CDK_FILTERS_H
#define CDK_FILTERS_H
enum {
STREAMCTL_READ = 0,
STREAMCTL_WRITE = 1,
STREAMCTL_FREE = 2
};
typedef struct {
gcry_cipher_hd_t hd;
gcry_md_hd_t mdc;
int mdc_method;
cdk_dek_t dek;
u32 datalen;
struct {
size_t on;
off_t size;
off_t nleft;
} blkmode;
cdk_stream_t s;
} cipher_filter_t;
typedef struct {
int digest_algo;
gcry_md_hd_t md;
} md_filter_t;
typedef struct {
const char *le; /* line endings */
const char *hdrlines;
u32 crc;
int crc_okay;
int idx, idx2;
} armor_filter_t;
typedef struct {
cdk_lit_format_t mode;
char *orig_filename; /* This original name of the input file. */
char *filename;
gcry_md_hd_t md;
struct {
size_t on;
off_t size;
} blkmode;
} literal_filter_t;
typedef struct {
size_t inbufsize;
byte inbuf[8192];
size_t outbufsize;
byte outbuf[8192];
int algo; /* compress algo */
int level;
} compress_filter_t;
typedef struct {
const char * lf;
} text_filter_t;
/*-- armor.c -*/
int _cdk_filter_armor( void * opaque, int ctl, FILE * in, FILE * out );
/*-- cipher.c --*/
cdk_error_t _cdk_filter_hash( void * opaque, int ctl, FILE * in, FILE * out );
cdk_error_t _cdk_filter_cipher( void * opaque, int ctl,
FILE * in, FILE * out );
/*-- literal.c --*/
int _cdk_filter_literal( void * opaque, int ctl, FILE * in, FILE * out );
int _cdk_filter_text( void * opaque, int ctl, FILE * in, FILE * out );
/*-- compress.c --*/
cdk_error_t _cdk_filter_compress( void * opaque, int ctl,
FILE * in, FILE * out );
#endif /* CDK_FILTERS_H */
-581
View File
@@ -1,581 +0,0 @@
/* kbnode.c - keyblock node utility functions
* Copyright (C) 1998-2001 Free Software Foundation, Inc.
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
/**
* cdk_kbnode_new:
* @pkt: the packet to add
*
* Allocate a new key node and add the packet.
**/
cdk_kbnode_t
cdk_kbnode_new (cdk_packet_t pkt)
{
cdk_kbnode_t n;
n = cdk_calloc (1, sizeof *n);
if (!n)
return NULL;
n->pkt = pkt;
return n;
}
void
_cdk_kbnode_clone (cdk_kbnode_t node)
{
/* Mark the node as clone which means that the packet
will not be freed, just the node itself. */
if (node)
node->is_cloned = 1;
}
/**
* cdk_kbnode_release:
* @n: the key node
*
* Release the memory of the node.
**/
void
cdk_kbnode_release (cdk_kbnode_t node)
{
cdk_kbnode_t n2;
while (node)
{
n2 = node->next;
if (!node->is_cloned)
cdk_pkt_release (node->pkt);
cdk_free (node);
node = n2;
}
}
/**
* cdk_kbnode_delete:
* @node: the key node
*
* Mark the given node as deleted.
**/
void
cdk_kbnode_delete (cdk_kbnode_t node)
{
if (node)
node->is_deleted = 1;
}
/* Append NODE to ROOT. ROOT must exist! */
void
_cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node)
{
cdk_kbnode_t n1;
for (n1 = root; n1->next; n1 = n1->next)
;
n1->next = node;
}
/**
* cdk_kbnode_insert:
* @root: the root key node
* @node: the node to add
* @pkttype: packet type
*
* Insert @node into the list after @root but before a packet which is not of
* type @pkttype (only if @pkttype != 0).
**/
void
cdk_kbnode_insert (cdk_kbnode_t root, cdk_kbnode_t node, int pkttype)
{
if (!pkttype)
{
node->next = root->next;
root->next = node;
}
else
{
cdk_kbnode_t n1;
for (n1 = root; n1->next; n1 = n1->next)
if (pkttype != n1->next->pkt->pkttype)
{
node->next = n1->next;
n1->next = node;
return;
}
/* No such packet, append */
node->next = NULL;
n1->next = node;
}
}
/**
* cdk_kbnode_find_prev:
* @root: the root key node
* @node: the key node
* @pkttype: packet type
*
* Find the previous node (if @pkttype = 0) or the previous node
* with pkttype @pkttype in the list starting with @root of @node.
**/
cdk_kbnode_t
cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node, int pkttype)
{
cdk_kbnode_t n1;
for (n1 = NULL; root && root != node; root = root->next)
{
if (!pkttype || root->pkt->pkttype == pkttype)
n1 = root;
}
return n1;
}
/**
* cdk_kbnode_find_next:
* @node: the key node
* @pkttype: packet type
*
* Ditto, but find the next packet. The behaviour is trivial if
* @pkttype is 0 but if it is specified, the next node with a packet
* of this type is returned. The function has some knowledge about
* the valid ordering of packets: e.g. if the next signature packet
* is requested, the function will not return one if it encounters
* a user-id.
**/
cdk_kbnode_t
cdk_kbnode_find_next (cdk_kbnode_t node, int pkttype)
{
for (node = node->next; node; node = node->next)
{
if (!pkttype)
return node;
else if (pkttype == CDK_PKT_USER_ID &&
(node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
node->pkt->pkttype == CDK_PKT_SECRET_KEY))
return NULL;
else if (pkttype == CDK_PKT_SIGNATURE &&
(node->pkt->pkttype == CDK_PKT_USER_ID ||
node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
node->pkt->pkttype == CDK_PKT_SECRET_KEY))
return NULL;
else if (node->pkt->pkttype == pkttype)
return node;
}
return NULL;
}
/**
* cdk_kbnode_find:
* @node: the key node
* @pkttype: packet type
*
* Try to find the next node with the packettype @pkttype.
**/
cdk_kbnode_t
cdk_kbnode_find (cdk_kbnode_t node, int pkttype)
{
for (; node; node = node->next)
{
if (node->pkt->pkttype == pkttype)
return node;
}
return NULL;
}
/**
* cdk_kbnode_find_packet:
* @node: the key node
* @pkttype: packet type
*
* Same as cdk_kbnode_find but it returns the packet instead of the node.
**/
cdk_packet_t
cdk_kbnode_find_packet (cdk_kbnode_t node, int pkttype)
{
cdk_kbnode_t res;
res = cdk_kbnode_find (node, pkttype);
return res ? res->pkt : NULL;
}
/****************
* Walk through a list of kbnodes. This function returns
* the next kbnode for each call; before using the function the first
* time, the caller must set CONTEXT to NULL (This has simply the effect
* to start with ROOT).
*/
cdk_kbnode_t
cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * context, int all)
{
cdk_kbnode_t n;
do
{
if (!*context)
{
*context = root;
n = root;
}
else
{
n = (*context)->next;
*context = n;
}
}
while (!all && n && n->is_deleted);
return n;
}
/**
* cdk_kbnode_commit:
* @root: the nodes
*
* Commit changes made to the kblist at ROOT. Note that ROOT my change,
* and it is therefore passed by reference.
* The function has the effect of removing all nodes marked as deleted.
* returns true if any node has been changed
*/
int
cdk_kbnode_commit (cdk_kbnode_t * root)
{
cdk_kbnode_t n, nl;
int changed = 0;
for (n = *root, nl = NULL; n; n = nl->next)
{
if (n->is_deleted)
{
if (n == *root)
*root = nl = n->next;
else
nl->next = n->next;
if (!n->is_cloned)
cdk_pkt_release (n->pkt);
cdk_free (n);
changed = 1;
}
else
nl = n;
}
return changed;
}
/**
* cdk_kbnode_remove:
* @root: the root node
* @node: the node to delete
*
* Remove a node from the root node.
*/
void
cdk_kbnode_remove (cdk_kbnode_t * root, cdk_kbnode_t node)
{
cdk_kbnode_t n, nl;
for (n = *root, nl = NULL; n; n = nl->next)
{
if (n == node)
{
if (n == *root)
*root = nl = n->next;
else
nl->next = n->next;
if (!n->is_cloned)
cdk_pkt_release (n->pkt);
cdk_free (n);
}
else
nl = n;
}
}
/**
* cdk_cdknode_move:
* @root: root node
* @node: the node to move
* @where: destination place where to move the node.
*
* Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
*/
void
cdk_kbnode_move (cdk_kbnode_t * root, cdk_kbnode_t node, cdk_kbnode_t where)
{
cdk_kbnode_t tmp, prev;
if (!root || !*root || !node)
return;
for (prev = *root; prev && prev->next != node; prev = prev->next)
;
if (!prev)
return; /* Node is not in the list */
if (!where)
{ /* Move node before root */
if (node == *root)
return;
prev->next = node->next;
node->next = *root;
*root = node;
return;
}
if (node == where) /* Move it after where. */
return;
tmp = node->next;
node->next = where->next;
where->next = node;
prev->next = tmp;
}
/**
* cdk_kbnode_get_packet:
* @node: the key node
*
* Return the packet which is stored inside the node in @node.
**/
cdk_packet_t
cdk_kbnode_get_packet (cdk_kbnode_t node)
{
if (node)
return node->pkt;
return NULL;
}
/**
* cdk_kbnode_read_from_mem:
* @ret_node: the new key node
* @buf: the buffer which stores the key sequence
* @buflen: the length of the buffer
*
* Try to read a key node from the memory buffer @buf.
**/
cdk_error_t
cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
const byte * buf, size_t buflen)
{
cdk_stream_t inp;
cdk_error_t rc;
if (!buflen || !ret_node || !buf)
return CDK_Inv_Value;
*ret_node = NULL;
rc = cdk_stream_tmp_from_mem (buf, buflen, &inp);
if (rc)
return rc;
rc = cdk_keydb_get_keyblock (inp, ret_node);
cdk_stream_close (inp);
return rc;
}
/**
* cdk_kbnode_write_to_mem_alloc:
* @node: the key node
* @r_buf: buffer to hold the raw data
* @r_buflen: buffer length of the allocated raw data.
*
* The function acts similar to cdk_kbnode_write_to_mem but
* it allocates the buffer to avoid the lengthy second run.
*/
cdk_error_t
cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
byte ** r_buf, size_t * r_buflen)
{
cdk_kbnode_t n;
cdk_stream_t s;
cdk_error_t rc;
size_t len;
if (!node)
return CDK_Inv_Value;
*r_buf = NULL;
*r_buflen = 0;
rc = cdk_stream_tmp_new (&s);
if (rc)
return rc;
for (n = node; n; n = n->next)
{
/* Skip all packets which cannot occur in a key composition. */
if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
n->pkt->pkttype != CDK_PKT_SIGNATURE &&
n->pkt->pkttype != CDK_PKT_USER_ID &&
n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
continue;
rc = cdk_pkt_write (s, n->pkt);
if (rc)
{
cdk_stream_close (s);
return rc;
}
}
cdk_stream_seek (s, 0);
len = cdk_stream_get_length (s);
*r_buf = cdk_calloc (1, len);
*r_buflen = cdk_stream_read (s, *r_buf, len);
cdk_stream_close (s);
return 0;
}
/**
* cdk_kbnode_write_to_mem:
* @node: the key node
* @buf: the buffer to store the node data
* @r_nbytes: the new length of the buffer.
*
* Try to write the contents of the key node to the buffer @buf and
* return the length of it in @r_nbytes. If buf is zero, only the
* length of the node is calculated and returned in @r_nbytes.
* Whenever it is possible, the cdk_kbnode_write_to_mem_alloc should be used.
**/
cdk_error_t
cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes)
{
cdk_kbnode_t n;
cdk_stream_t s;
size_t len;
cdk_error_t rc;
if (!node)
return CDK_Inv_Value;
rc = cdk_stream_tmp_new (&s);
if (rc)
return rc;
for (n = node; n; n = n->next)
{
/* Skip all packets which cannot occur in a key composition. */
if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
n->pkt->pkttype != CDK_PKT_SIGNATURE &&
n->pkt->pkttype != CDK_PKT_USER_ID &&
n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
continue;
rc = cdk_pkt_write (s, n->pkt);
if (rc)
{
cdk_stream_close (s);
return rc;
}
}
cdk_stream_seek (s, 0);
len = cdk_stream_get_length (s);
if (!buf)
{
*r_nbytes = len; /* Only return the length of the buffer */
cdk_stream_close (s);
return 0;
}
if (*r_nbytes < len)
rc = CDK_Too_Short;
if (!rc)
*r_nbytes = cdk_stream_read (s, buf, len);
cdk_stream_close (s);
return rc;
}
/**
* cdk_kbnode_hash:
* @node: the key node
* @hashctx: opaque pointer to the hash context
* @is_v4: OpenPGP signature (yes=1, no=0)
* @pkttype: packet type to hash (if zero use the packet type from the node)
* @flags: flags which depend on the operation
*
* Hash the key node contents. Two modes are supported. If the packet
* type is used (!= 0) then the function searches the first node with
* this type. Otherwise the node is seen as a single node and the type
* is extracted from it.
**/
cdk_error_t
cdk_kbnode_hash (cdk_kbnode_t node, gcry_md_hd_t md, int is_v4,
int pkttype, int flags)
{
cdk_packet_t pkt;
if (!node || !md)
return CDK_Inv_Value;
if (!pkttype)
{
pkt = cdk_kbnode_get_packet (node);
pkttype = pkt->pkttype;
}
else
{
pkt = cdk_kbnode_find_packet (node, pkttype);
if (!pkt)
return CDK_Inv_Packet;
}
switch (pkttype)
{
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
_cdk_hash_pubkey (pkt->pkt.public_key, md, flags & 1);
break;
case CDK_PKT_USER_ID:
_cdk_hash_userid (pkt->pkt.user_id, is_v4, md);
break;
case CDK_PKT_SIGNATURE:
_cdk_hash_sig_data (pkt->pkt.signature, md);
break;
default:
return CDK_Inv_Mode;
}
return 0;
}
-2303
View File
@@ -1,2303 +0,0 @@
/* keydb.c - Key database routines
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
#include "filters.h"
#include "stream.h"
#define KEYID_CMP(a, b) ((a[0]) == (b[0]) && (a[1]) == (b[1]))
#define KEYDB_CACHE_ENTRIES 8
/* Internal key index structure. */
struct key_idx_s
{
off_t offset;
u32 keyid[2];
byte fpr[KEY_FPR_LEN];
};
typedef struct key_idx_s *key_idx_t;
/* Internal handle for the search operation. */
struct cdk_dbsearch_s
{
union
{
char *pattern; /* A search is performed by pattern. */
u32 keyid[2]; /* A search by keyid. */
byte fpr[KEY_FPR_LEN]; /* A search by fingerprint. */
} u;
int type;
};
typedef struct cdk_dbsearch_s *cdk_dbsearch_t;
/* Internal key cache to associate a key with an file offset. */
struct key_table_s
{
struct key_table_s *next;
off_t offset;
cdk_dbsearch_t desc;
};
typedef struct key_table_s *key_table_t;
/* Internal key database handle. */
struct cdk_keydb_hd_s
{
int type; /* type of the key db handle. */
int fp_ref; /* 1=means it is a reference and shall not be closed. */
cdk_stream_t fp;
cdk_stream_t idx;
cdk_dbsearch_t dbs;
char *name; /* name of the underlying file or NULL. */
char *idx_name; /* name of the index file or NULL. */
struct key_table_s *cache;
size_t ncache;
unsigned int secret:1; /* contain secret keys. */
unsigned int isopen:1; /* the underlying stream is opened. */
unsigned int no_cache:1; /* disable the index cache. */
unsigned int search:1; /* handle is in search mode. */
/* structure to store some stats about the keydb. */
struct
{
size_t new_keys; /* amount of new keys that were imported. */
} stats;
};
static void keydb_cache_free (key_table_t cache);
static int keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src);
static void keydb_search_free (cdk_dbsearch_t dbs);
static int classify_data (const byte * buf, size_t len);
static cdk_kbnode_t find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk);
static char *
keydb_idx_mkname (const char *file)
{
char *fname, *fmt;
fmt = "%s.idx";
fname = cdk_calloc (1, strlen (file) + strlen (fmt) + 1);
if (!fname)
return NULL;
sprintf (fname, fmt, file);
return fname;
}
/* This functions builds an index of the keyring into a separate file
with the name keyring.ext.idx. It contains the offset of all public-
and public subkeys. The format of the file is:
--------
4 octets offset of the packet
8 octets keyid
20 octets fingerprint
--------
We store the keyid and the fingerprint due to the fact we can't get
the keyid from a v3 fingerprint directly.
*/
static cdk_error_t
keydb_idx_build (const char *file)
{
cdk_packet_t pkt;
cdk_stream_t inp, out = NULL;
byte buf[4 + 8 + KEY_FPR_LEN];
char *idx_name;
u32 keyid[2];
cdk_error_t rc;
if (!file)
return CDK_Inv_Value;
rc = cdk_stream_open (file, &inp);
if (rc)
return rc;
idx_name = keydb_idx_mkname (file);
if (!idx_name)
{
cdk_stream_close (inp);
return CDK_Out_Of_Core;
}
rc = cdk_stream_create (idx_name, &out);
cdk_free (idx_name);
if (rc)
{
cdk_stream_close (inp);
return rc;
}
cdk_pkt_new (&pkt);
while (!cdk_stream_eof (inp))
{
off_t pos = cdk_stream_tell (inp);
rc = cdk_pkt_read (inp, pkt);
if (rc)
{
_cdk_log_debug ("index build failed packet off=%lu\n", pos);
/* FIXME: The index is incomplete */
break;
}
if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
{
_cdk_u32tobuf (pos, buf);
cdk_pk_get_keyid (pkt->pkt.public_key, keyid);
_cdk_u32tobuf (keyid[0], buf + 4);
_cdk_u32tobuf (keyid[1], buf + 8);
cdk_pk_get_fingerprint (pkt->pkt.public_key, buf + 12);
cdk_stream_write (out, buf, 4 + 8 + KEY_FPR_LEN);
}
cdk_pkt_free (pkt);
}
cdk_pkt_release (pkt);
cdk_stream_close (out);
cdk_stream_close (inp);
return rc;
}
/**
* cdk_keydb_idx_rebuild:
* @hd: key database handle
*
* Rebuild the key index files for the given key database.
**/
cdk_error_t
cdk_keydb_idx_rebuild (cdk_keydb_hd_t db)
{
struct stat stbuf;
char *tmp_idx_name;
cdk_error_t rc;
int err;
if (!db || !db->name)
return CDK_Inv_Value;
if (db->secret)
return 0;
tmp_idx_name = keydb_idx_mkname (db->name);
if (!tmp_idx_name)
return CDK_Out_Of_Core;
err = stat (tmp_idx_name, &stbuf);
cdk_free (tmp_idx_name);
/* This function expects an existing index which can be rebuild,
if no index exists we do not build one and just return. */
if (err)
return 0;
cdk_stream_close (db->idx);
db->idx = NULL;
if (!db->idx_name)
{
db->idx_name = keydb_idx_mkname (db->name);
if (!db->idx_name)
return CDK_Out_Of_Core;
}
rc = keydb_idx_build (db->name);
if (!rc)
rc = cdk_stream_open (db->idx_name, &db->idx);
return rc;
}
static cdk_error_t
keydb_idx_parse (cdk_stream_t inp, key_idx_t * r_idx)
{
key_idx_t idx;
byte buf[4];
if (!inp || !r_idx)
return CDK_Inv_Value;
idx = cdk_calloc (1, sizeof *idx);
if (!idx)
return CDK_Out_Of_Core;
while (!cdk_stream_eof (inp))
{
if (cdk_stream_read (inp, buf, 4) == CDK_EOF)
break;
idx->offset = _cdk_buftou32 (buf);
cdk_stream_read (inp, buf, 4);
idx->keyid[0] = _cdk_buftou32 (buf);
cdk_stream_read (inp, buf, 4);
idx->keyid[1] = _cdk_buftou32 (buf);
cdk_stream_read (inp, idx->fpr, KEY_FPR_LEN);
break;
}
*r_idx = idx;
return cdk_stream_eof (inp) ? CDK_EOF : 0;
}
static cdk_error_t
keydb_idx_search (cdk_stream_t inp, u32 * keyid, const byte * fpr,
off_t * r_off)
{
key_idx_t idx;
if (!inp || !r_off)
return CDK_Inv_Value;
if ((keyid && fpr) || (!keyid && !fpr))
return CDK_Inv_Mode;
/* We need an initialize the offset var with a value
because it might be possible the returned offset will
be 0 and then we cannot differ between the begin and an EOF. */
*r_off = 0xFFFFFFFF;
cdk_stream_seek (inp, 0);
while (keydb_idx_parse (inp, &idx) != CDK_EOF)
{
if (keyid && KEYID_CMP (keyid, idx->keyid))
{
*r_off = idx->offset;
break;
}
else if (fpr && !memcmp (idx->fpr, fpr, KEY_FPR_LEN))
{
*r_off = idx->offset;
break;
}
cdk_free (idx);
idx = NULL;
}
cdk_free (idx);
return *r_off != 0xFFFFFFFF ? 0 : CDK_EOF;
}
/**
* cdk_keydb_new_from_mem:
* @r_hd: The keydb output handle.
* @data: The raw key data.
* @datlen: The length of the raw data.
*
* Create a new keyring db handle from the contents of a buffer.
*/
cdk_error_t
cdk_keydb_new_from_mem (cdk_keydb_hd_t * r_db, int secret,
const void *data, size_t datlen)
{
cdk_keydb_hd_t db;
cdk_error_t rc;
if (!r_db)
return CDK_Inv_Value;
*r_db = NULL;
db = calloc (1, sizeof *db);
rc = cdk_stream_tmp_from_mem (data, datlen, &db->fp);
if (!db->fp)
{
cdk_free (db);
return rc;
}
if (cdk_armor_filter_use (db->fp))
cdk_stream_set_armor_flag (db->fp, 0);
db->type = CDK_DBTYPE_DATA;
db->secret = secret;
*r_db = db;
return 0;
}
/**
* cdk_keydb_new_from_stream:
* @r_hd: the output keydb handle
* @secret: does the stream contain secret key data
* @in: the input stream to use
*
* This function creates a new keydb handle based on the given
* stream. The stream is not closed in cdk_keydb_free() and it
* is up to the caller to close it. No decoding is done.
*/
cdk_error_t
cdk_keydb_new_from_stream (cdk_keydb_hd_t * r_hd, int secret, cdk_stream_t in)
{
cdk_keydb_hd_t hd;
if (!r_hd)
return CDK_Inv_Value;
*r_hd = NULL;
hd = calloc (1, sizeof *hd);
hd->fp = in;
hd->fp_ref = 1;
hd->type = CDK_DBTYPE_STREAM;
hd->secret = secret;
*r_hd = hd;
/* We do not push any filters and thus we expect that the format
of the stream has the format the user wanted. */
return 0;
}
cdk_error_t
cdk_keydb_new_from_file (cdk_keydb_hd_t * r_hd, int secret, const char *fname)
{
cdk_keydb_hd_t hd;
if (!r_hd)
return CDK_Inv_Value;
*r_hd = NULL;
hd = calloc (1, sizeof *hd);
hd->name = cdk_strdup (fname);
if (!hd->name)
{
cdk_free (hd);
return CDK_Out_Of_Core;
}
hd->type = secret ? CDK_DBTYPE_SK_KEYRING : CDK_DBTYPE_PK_KEYRING;
hd->secret = secret;
*r_hd = hd;
return 0;
}
/**
* cdk_keydb_new:
* @r_hd: handle to store the new keydb object
* @type: type of the keyring
* @data: data which depends on the keyring type
* @count: length of the data
*
* Create a new keydb object
**/
cdk_error_t
cdk_keydb_new (cdk_keydb_hd_t * r_hd, int type, void *data, size_t count)
{
switch (type)
{
case CDK_DBTYPE_PK_KEYRING:
case CDK_DBTYPE_SK_KEYRING:
return cdk_keydb_new_from_file (r_hd, type == CDK_DBTYPE_SK_KEYRING,
(const char *) data);
case CDK_DBTYPE_DATA:
return cdk_keydb_new_from_mem (r_hd, 0, data, count);
case CDK_DBTYPE_STREAM:
return cdk_keydb_new_from_stream (r_hd, 0, (cdk_stream_t) data);
default:
return CDK_Inv_Mode;
}
return CDK_Inv_Mode;
}
/**
* cdk_keydb_free:
* @hd: the keydb object
*
* Free the keydb object.
**/
void
cdk_keydb_free (cdk_keydb_hd_t hd)
{
if (!hd)
return;
if (hd->name)
{
cdk_free (hd->name);
hd->name = NULL;
}
if (hd->fp && !hd->fp_ref)
{
cdk_stream_close (hd->fp);
hd->fp = NULL;
}
if (hd->idx)
{
cdk_stream_close (hd->idx);
hd->idx = NULL;
}
hd->isopen = 0;
hd->no_cache = 0;
hd->secret = 0;
keydb_cache_free (hd->cache);
hd->cache = NULL;
keydb_search_free (hd->dbs);
hd->dbs = NULL;
cdk_free (hd);
}
cdk_error_t
_cdk_keydb_open (cdk_keydb_hd_t hd, cdk_stream_t * ret_kr)
{
cdk_error_t rc, ec;
if (!hd || !ret_kr)
return CDK_Inv_Value;
rc = 0;
if ((hd->type == CDK_DBTYPE_DATA || hd->type == CDK_DBTYPE_STREAM)
&& hd->fp)
cdk_stream_seek (hd->fp, 0);
else if (hd->type == CDK_DBTYPE_PK_KEYRING ||
hd->type == CDK_DBTYPE_SK_KEYRING)
{
if (!hd->isopen && hd->name)
{
rc = cdk_stream_open (hd->name, &hd->fp);
if (rc)
goto leave;
if (cdk_armor_filter_use (hd->fp))
cdk_stream_set_armor_flag (hd->fp, 0);
hd->isopen = 1;
/* We disable the index cache for smaller keyrings. */
if (cdk_stream_get_length (hd->fp) < 524288)
{
hd->no_cache = 1;
goto leave;
}
cdk_free (hd->idx_name);
hd->idx_name = keydb_idx_mkname (hd->name);
if (!hd->idx_name)
{
rc = CDK_Out_Of_Core;
goto leave;
}
ec = cdk_stream_open (hd->idx_name, &hd->idx);
if (ec && !hd->secret)
{
rc = keydb_idx_build (hd->name);
if (!rc)
rc = cdk_stream_open (hd->idx_name, &hd->idx);
if (!rc)
_cdk_log_debug ("create key index table\n");
else
{
/* This is no real error, it just means we can't create
the index at the given directory. maybe we've no write
access. in this case, we simply disable the index. */
_cdk_log_debug ("disable key index table err=%d\n", rc);
rc = 0;
hd->no_cache = 1;
}
}
}
else
{
/* We use the cache to search keys, so we always rewind the
STREAM. Except when the _NEXT search mode is used because
this mode is an enumeration and no seeking is needed. */
if (!hd->search ||
(hd->search && hd->dbs->type != CDK_DBSEARCH_NEXT))
cdk_stream_seek (hd->fp, 0);
}
}
else
return CDK_Inv_Mode;
leave:
if (rc)
{
cdk_stream_close (hd->fp);
hd->fp = NULL;
}
*ret_kr = hd->fp;
return rc;
}
static int
find_by_keyid (cdk_kbnode_t knode, cdk_dbsearch_t ks)
{
cdk_kbnode_t node;
u32 keyid[2];
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
{
_cdk_pkt_get_keyid (node->pkt, keyid);
switch (ks->type)
{
case CDK_DBSEARCH_SHORT_KEYID:
if (keyid[1] == ks->u.keyid[1])
return 1;
break;
case CDK_DBSEARCH_KEYID:
if (KEYID_CMP (keyid, ks->u.keyid))
return 1;
break;
default:
_cdk_log_debug ("find_by_keyid: invalid mode = %d\n", ks->type);
return 0;
}
}
}
return 0;
}
static int
find_by_fpr (cdk_kbnode_t knode, cdk_dbsearch_t ks)
{
cdk_kbnode_t node;
byte fpr[KEY_FPR_LEN];
if (ks->type != CDK_DBSEARCH_FPR)
return 0;
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
{
_cdk_pkt_get_fingerprint (node->pkt, fpr);
if (!memcmp (ks->u.fpr, fpr, KEY_FPR_LEN))
return 1;
break;
}
}
return 0;
}
static int
find_by_pattern (cdk_kbnode_t knode, cdk_dbsearch_t ks)
{
cdk_kbnode_t node;
size_t uidlen;
char *name;
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype != CDK_PKT_USER_ID)
continue;
if (node->pkt->pkt.user_id->attrib_img != NULL)
continue; /* Skip attribute packets. */
uidlen = node->pkt->pkt.user_id->len;
name = node->pkt->pkt.user_id->name;
switch (ks->type)
{
case CDK_DBSEARCH_EXACT:
if (name &&
(strlen (ks->u.pattern) == uidlen &&
!strncmp (ks->u.pattern, name, uidlen)))
return 1;
break;
case CDK_DBSEARCH_SUBSTR:
if (uidlen > 65536)
break;
if (name && strlen (ks->u.pattern) > uidlen)
break;
if (name && _cdk_memistr (name, uidlen, ks->u.pattern))
return 1;
break;
default: /* Invalid mode */
return 0;
}
}
return 0;
}
static void
keydb_search_free (cdk_dbsearch_t dbs)
{
if (!dbs)
return;
if (dbs->type == CDK_DBSEARCH_EXACT || dbs->type == CDK_DBSEARCH_SUBSTR)
cdk_free (dbs->u.pattern);
dbs->type = 0;
cdk_free (dbs);
}
static void
keydb_cache_free (key_table_t cache)
{
key_table_t c2;
while (cache)
{
c2 = cache->next;
cache->offset = 0;
keydb_search_free (cache->desc);
cdk_free (cache);
cache = c2;
}
}
static key_table_t
keydb_cache_find (key_table_t cache, cdk_dbsearch_t desc)
{
key_table_t t;
for (t = cache; t; t = t->next)
{
if (t->desc->type != desc->type)
continue;
switch (t->desc->type)
{
case CDK_DBSEARCH_SHORT_KEYID:
case CDK_DBSEARCH_KEYID:
if (KEYID_CMP (t->desc->u.keyid, desc->u.keyid))
return t;
break;
case CDK_DBSEARCH_EXACT:
if (strlen (t->desc->u.pattern) == strlen (desc->u.pattern) &&
!strcmp (t->desc->u.pattern, desc->u.pattern))
return t;
break;
case CDK_DBSEARCH_SUBSTR:
if (strstr (t->desc->u.pattern, desc->u.pattern))
return t;
break;
case CDK_DBSEARCH_FPR:
if (!memcmp (t->desc->u.fpr, desc->u.fpr, KEY_FPR_LEN))
return t;
break;
}
}
return NULL;
}
static cdk_error_t
keydb_cache_add (cdk_keydb_hd_t hd, cdk_dbsearch_t dbs, off_t offset)
{
key_table_t k;
if (!hd)
return CDK_Inv_Value;
if (hd->ncache > KEYDB_CACHE_ENTRIES)
return 0; /* FIXME: we should replace the last entry. */
k = cdk_calloc (1, sizeof *k);
if (!k)
return CDK_Out_Of_Core;
k->offset = offset;
keydb_search_copy (&k->desc, dbs);
k->next = hd->cache;
hd->cache = k;
hd->ncache++;
_cdk_log_debug ("cache: add entry off=%d type=%d\n", offset, dbs->type);
return 0;
}
static cdk_error_t
keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src)
{
cdk_dbsearch_t dst;
if (!r_dst || !src)
return CDK_Inv_Value;
*r_dst = NULL;
dst = cdk_calloc (1, sizeof *dst);
if (!dst)
return CDK_Out_Of_Core;
dst->type = src->type;
switch (src->type)
{
case CDK_DBSEARCH_EXACT:
case CDK_DBSEARCH_SUBSTR:
dst->u.pattern = cdk_strdup (src->u.pattern);
if (!dst->u.pattern)
return CDK_Out_Of_Core;
break;
case CDK_DBSEARCH_SHORT_KEYID:
case CDK_DBSEARCH_KEYID:
dst->u.keyid[0] = src->u.keyid[0];
dst->u.keyid[1] = src->u.keyid[1];
break;
case CDK_DBSEARCH_FPR:
memcpy (dst->u.fpr, src->u.fpr, KEY_FPR_LEN);
break;
}
*r_dst = dst;
return 0;
}
/**
* cdk_keydb_search_start:
* @db: key database handle
* @type: specifies the search type
* @desc: description which depends on the type
*
* Create a new keydb search object.
**/
cdk_error_t
cdk_keydb_search_start (cdk_keydb_hd_t db, int type, void *desc)
{
cdk_dbsearch_t dbs;
u32 *keyid;
char *p, tmp[3];
int i;
if (!db)
return CDK_Inv_Value;
if (type != CDK_DBSEARCH_NEXT && !desc)
return CDK_Inv_Mode;
dbs = cdk_calloc (1, sizeof *dbs);
if (!dbs)
return CDK_Out_Of_Core;
dbs->type = type;
switch (type)
{
case CDK_DBSEARCH_EXACT:
case CDK_DBSEARCH_SUBSTR:
cdk_free (dbs->u.pattern);
dbs->u.pattern = cdk_strdup (desc);
if (!dbs->u.pattern)
{
cdk_free (dbs);
return CDK_Out_Of_Core;
}
break;
case CDK_DBSEARCH_SHORT_KEYID:
keyid = desc;
dbs->u.keyid[1] = keyid[0];
break;
case CDK_DBSEARCH_KEYID:
keyid = desc;
dbs->u.keyid[0] = keyid[0];
dbs->u.keyid[1] = keyid[1];
break;
case CDK_DBSEARCH_FPR:
memcpy (dbs->u.fpr, desc, KEY_FPR_LEN);
break;
case CDK_DBSEARCH_NEXT:
break;
case CDK_DBSEARCH_AUTO:
/* Override the type with the actual db search type. */
dbs->type = classify_data (desc, strlen (desc));
switch (dbs->type)
{
case CDK_DBSEARCH_SUBSTR:
case CDK_DBSEARCH_EXACT:
cdk_free (dbs->u.pattern);
p = dbs->u.pattern = cdk_strdup (desc);
if (!p)
{
cdk_free (dbs);
return CDK_Out_Of_Core;
}
break;
case CDK_DBSEARCH_SHORT_KEYID:
case CDK_DBSEARCH_KEYID:
p = desc;
if (!strncmp (p, "0x", 2))
p += 2;
if (strlen (p) == 8)
{
dbs->u.keyid[0] = 0;
dbs->u.keyid[1] = strtoul (p, NULL, 16);
}
else if (strlen (p) == 16)
{
dbs->u.keyid[0] = strtoul (p, NULL, 16);
dbs->u.keyid[1] = strtoul (p + 8, NULL, 16);
}
else
{ /* Invalid key ID object. */
cdk_free (dbs);
return CDK_Inv_Mode;
}
break;
case CDK_DBSEARCH_FPR:
p = desc;
if (strlen (p) != 2 * KEY_FPR_LEN)
{
cdk_free (dbs);
return CDK_Inv_Mode;
}
for (i = 0; i < KEY_FPR_LEN; i++)
{
tmp[0] = p[2 * i];
tmp[1] = p[2 * i + 1];
tmp[2] = 0x00;
dbs->u.fpr[i] = strtoul (tmp, NULL, 16);
}
break;
}
break;
default:
cdk_free (dbs);
_cdk_log_debug ("cdk_keydb_search_start: invalid mode = %d\n", type);
return CDK_Inv_Mode;
}
keydb_search_free (db->dbs);
db->dbs = dbs;
return 0;
}
static cdk_error_t
keydb_pos_from_cache (cdk_keydb_hd_t hd, cdk_dbsearch_t ks,
int *r_cache_hit, off_t * r_off)
{
key_table_t c;
if (!hd || !r_cache_hit || !r_off)
return CDK_Inv_Value;
/* Reset the values. */
*r_cache_hit = 0;
*r_off = 0;
c = keydb_cache_find (hd->cache, ks);
if (c != NULL)
{
_cdk_log_debug ("cache: found entry in cache.\n");
*r_cache_hit = 1;
*r_off = c->offset;
return 0;
}
/* No index cache available so we just return here. */
if (!hd->idx)
return 0;
if (hd->idx)
{
if (ks->type == CDK_DBSEARCH_KEYID)
{
if (keydb_idx_search (hd->idx, ks->u.keyid, NULL, r_off))
return CDK_Error_No_Key;
_cdk_log_debug ("cache: found keyid entry in idx table.\n");
*r_cache_hit = 1;
}
else if (ks->type == CDK_DBSEARCH_FPR)
{
if (keydb_idx_search (hd->idx, NULL, ks->u.fpr, r_off))
return CDK_Error_No_Key;
_cdk_log_debug ("cache: found fpr entry in idx table.\n");
*r_cache_hit = 1;
}
}
return 0;
}
/**
* cdk_keydb_search:
* @hd: the keydb object
* @ks: the keydb search object
* @ret_key: kbnode object to store the key
*
* Search for a key in the given keyring. The search mode is handled
* via @ks. If the key was found, @ret_key contains the key data.
**/
cdk_error_t
cdk_keydb_search (cdk_keydb_hd_t hd, cdk_kbnode_t * ret_key)
{
cdk_stream_t kr;
cdk_kbnode_t knode;
cdk_dbsearch_t ks;
cdk_error_t rc = 0;
off_t pos = 0, off = 0;
int key_found = 0, cache_hit = 0;
if (!hd || !ret_key)
return CDK_Inv_Value;
*ret_key = NULL;
kr = NULL;
hd->search = 1;
rc = _cdk_keydb_open (hd, &kr);
if (rc)
return rc;
if (!hd->no_cache)
{
/* It is possible the index is not up-to-date and thus we do
not find the requesed key. In this case, we reset cache hit
and continue our normal search procedure. */
rc = keydb_pos_from_cache (hd, hd->dbs, &cache_hit, &off);
if (rc)
cache_hit = 0;
}
knode = NULL;
ks = hd->dbs;
while (!key_found && !rc)
{
if (cache_hit && ks->type != CDK_DBSEARCH_NEXT)
cdk_stream_seek (kr, off);
pos = cdk_stream_tell (kr);
rc = cdk_keydb_get_keyblock (kr, &knode);
if (rc)
{
if (rc == CDK_EOF)
break;
else
return rc;
}
switch (ks->type)
{
case CDK_DBSEARCH_SHORT_KEYID:
case CDK_DBSEARCH_KEYID:
key_found = find_by_keyid (knode, ks);
break;
case CDK_DBSEARCH_FPR:
key_found = find_by_fpr (knode, ks);
break;
case CDK_DBSEARCH_EXACT:
case CDK_DBSEARCH_SUBSTR:
key_found = find_by_pattern (knode, ks);
break;
case CDK_DBSEARCH_NEXT:
key_found = knode ? 1 : 0;
break;
}
if (key_found)
{
if (!keydb_cache_find (hd->cache, ks))
keydb_cache_add (hd, ks, pos);
break;
}
cdk_kbnode_release (knode);
knode = NULL;
}
hd->search = 0;
if (key_found && rc == CDK_EOF)
rc = 0;
else if (rc == CDK_EOF && !key_found)
rc = CDK_Error_No_Key;
*ret_key = key_found ? knode : NULL;
return rc;
}
cdk_error_t
cdk_keydb_get_bykeyid (cdk_keydb_hd_t hd, u32 * keyid, cdk_kbnode_t * ret_key)
{
cdk_error_t rc;
if (!hd || !keyid || !ret_key)
return CDK_Inv_Value;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
if (!rc)
rc = cdk_keydb_search (hd, ret_key);
return rc;
}
cdk_error_t
cdk_keydb_get_byfpr (cdk_keydb_hd_t hd, const byte * fpr,
cdk_kbnode_t * r_key)
{
cdk_error_t rc;
if (!hd || !fpr || !r_key)
return CDK_Inv_Value;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_FPR, (byte *) fpr);
if (!rc)
rc = cdk_keydb_search (hd, r_key);
return rc;
}
cdk_error_t
cdk_keydb_get_bypattern (cdk_keydb_hd_t hd, const char *patt,
cdk_kbnode_t * ret_key)
{
cdk_error_t rc;
if (!hd || !patt || !ret_key)
return CDK_Inv_Value;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_SUBSTR, (char *) patt);
if (!rc)
rc = cdk_keydb_search (hd, ret_key);
return rc;
}
static int
keydb_check_key (cdk_packet_t pkt)
{
cdk_pkt_pubkey_t pk;
int is_sk, valid;
if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
{
pk = pkt->pkt.public_key;
is_sk = 0;
}
else if (pkt->pkttype == CDK_PKT_SECRET_KEY ||
pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
{
pk = pkt->pkt.secret_key->pk;
is_sk = 1;
}
else /* No key object. */
return 0;
valid = !pk->is_revoked && !pk->has_expired;
if (is_sk)
return valid;
return valid && !pk->is_invalid;
}
/* Find the first kbnode with the requested packet type
that represents a valid key. */
static cdk_kbnode_t
kbnode_find_valid (cdk_kbnode_t root, int pkttype)
{
cdk_kbnode_t n;
for (n = root; n; n = n->next)
{
if (n->pkt->pkttype != pkttype)
continue;
if (keydb_check_key (n->pkt))
return n;
}
return NULL;
}
static cdk_kbnode_t
keydb_find_byusage (cdk_kbnode_t root, int req_usage, int is_pk)
{
cdk_kbnode_t node, key;
int req_type;
long timestamp;
req_type = is_pk ? CDK_PKT_PUBLIC_KEY : CDK_PKT_SECRET_KEY;
if (!req_usage)
return kbnode_find_valid (root, req_type);
node = cdk_kbnode_find (root, req_type);
if (node && !keydb_check_key (node->pkt))
return NULL;
key = NULL;
timestamp = 0;
/* We iteratre over the all nodes and search for keys or
subkeys which match the usage and which are not invalid.
A timestamp is used to figure out the newest valid key. */
for (node = root; node; node = node->next)
{
if (is_pk && (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
&& keydb_check_key (node->pkt)
&& (node->pkt->pkt.public_key->pubkey_usage & req_usage))
{
if (node->pkt->pkt.public_key->timestamp > timestamp)
key = node;
}
if (!is_pk && (node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
&& keydb_check_key (node->pkt)
&& (node->pkt->pkt.secret_key->pk->pubkey_usage & req_usage))
{
if (node->pkt->pkt.secret_key->pk->timestamp > timestamp)
key = node;
}
}
return key;
}
static cdk_kbnode_t
keydb_find_bykeyid (cdk_kbnode_t root, const u32 * keyid, int search_mode)
{
cdk_kbnode_t node;
u32 kid[2];
for (node = root; node; node = node->next)
{
if (!_cdk_pkt_get_keyid (node->pkt, kid))
continue;
if (search_mode == CDK_DBSEARCH_SHORT_KEYID && kid[1] == keyid[1])
return node;
else if (kid[0] == keyid[0] && kid[1] == keyid[1])
return node;
}
return NULL;
}
cdk_error_t
_cdk_keydb_get_sk_byusage (cdk_keydb_hd_t hd, const char *name,
cdk_seckey_t * ret_sk, int usage)
{
cdk_kbnode_t knode = NULL;
cdk_kbnode_t node, sk_node, pk_node;
cdk_pkt_seckey_t sk;
cdk_error_t rc;
const char *s;
int pkttype;
if (!ret_sk || !usage)
return CDK_Inv_Value;
if (!hd)
return CDK_Error_No_Keyring;
*ret_sk = NULL;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, (char *) name);
if (rc)
return rc;
rc = cdk_keydb_search (hd, &knode);
if (rc)
return rc;
sk_node = keydb_find_byusage (knode, usage, 0);
if (!sk_node)
{
cdk_kbnode_release (knode);
return CDK_Unusable_Key;
}
/* We clone the node with the secret key to avoid that the
packet will be released. */
_cdk_kbnode_clone (sk_node);
sk = sk_node->pkt->pkt.secret_key;
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_USER_ID)
{
s = node->pkt->pkt.user_id->name;
if (sk && !sk->pk->uid && _cdk_memistr (s, strlen (s), name))
{
_cdk_copy_userid (&sk->pk->uid, node->pkt->pkt.user_id);
break;
}
}
}
/* To find the self signature, we need the primary public key because
the selected secret key might be different from the primary key. */
pk_node = cdk_kbnode_find (knode, CDK_PKT_SECRET_KEY);
if (!pk_node)
{
cdk_kbnode_release (knode);
return CDK_Unusable_Key;
}
node = find_selfsig_node (knode, pk_node->pkt->pkt.secret_key->pk);
if (sk->pk->uid && node)
_cdk_copy_signature (&sk->pk->uid->selfsig, node->pkt->pkt.signature);
/* We only release the outer packet. */
_cdk_pkt_detach_free (sk_node->pkt, &pkttype, (void *) &sk);
cdk_kbnode_release (knode);
*ret_sk = sk;
return rc;
}
cdk_error_t
_cdk_keydb_get_pk_byusage (cdk_keydb_hd_t hd, const char *name,
cdk_pubkey_t * ret_pk, int usage)
{
cdk_kbnode_t knode, node, pk_node;
cdk_pkt_pubkey_t pk;
const char *s;
cdk_error_t rc;
if (!ret_pk || !usage)
return CDK_Inv_Value;
if (!hd)
return CDK_Error_No_Keyring;
*ret_pk = NULL;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, (char *) name);
if (!rc)
rc = cdk_keydb_search (hd, &knode);
if (rc)
return rc;
node = keydb_find_byusage (knode, usage, 1);
if (!node)
{
cdk_kbnode_release (knode);
return CDK_Unusable_Key;
}
pk = NULL;
_cdk_copy_pubkey (&pk, node->pkt->pkt.public_key);
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_USER_ID)
{
s = node->pkt->pkt.user_id->name;
if (pk && !pk->uid && _cdk_memistr (s, strlen (s), name))
{
_cdk_copy_userid (&pk->uid, node->pkt->pkt.user_id);
break;
}
}
}
/* Same as in the sk code, the selected key can be a sub key
and thus we need the primary key to find the self sig. */
pk_node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
if (!pk_node)
{
cdk_kbnode_release (knode);
return CDK_Unusable_Key;
}
node = find_selfsig_node (knode, pk_node->pkt->pkt.public_key);
if (pk->uid && node)
_cdk_copy_signature (&pk->uid->selfsig, node->pkt->pkt.signature);
cdk_kbnode_release (knode);
*ret_pk = pk;
return rc;
}
/**
* cdk_keydb_get_pk:
* @hd: key db handle
* @keyid: keyid of the key
* @r_pk: the allocated public key
*
* Perform a key database search by keyid and return the raw public
* key without any signatures or user id's.
**/
cdk_error_t
cdk_keydb_get_pk (cdk_keydb_hd_t hd, u32 * keyid, cdk_pubkey_t * r_pk)
{
cdk_kbnode_t knode = NULL, node;
cdk_pubkey_t pk;
cdk_error_t rc;
size_t s_type;
int pkttype;
if (!keyid || !r_pk)
return CDK_Inv_Value;
if (!hd)
return CDK_Error_No_Keyring;
*r_pk = NULL;
s_type = !keyid[0] ? CDK_DBSEARCH_SHORT_KEYID : CDK_DBSEARCH_KEYID;
rc = cdk_keydb_search_start (hd, s_type, keyid);
if (rc)
return rc;
rc = cdk_keydb_search (hd, &knode);
if (rc)
return rc;
node = keydb_find_bykeyid (knode, keyid, s_type);
if (!node)
{
cdk_kbnode_release (knode);
return CDK_Error_No_Key;
}
/* See comment in cdk_keydb_get_sk() */
_cdk_pkt_detach_free (node->pkt, &pkttype, (void *) &pk);
*r_pk = pk;
_cdk_kbnode_clone (node);
cdk_kbnode_release (knode);
return rc;
}
/**
* cdk_keydb_get_sk:
* @hd: key db handle
* @keyid: the keyid of the key
* @ret_sk: the allocated secret key
*
* Perform a key database search by keyid and return
* only the raw secret key without the additional nodes,
* like the user id or the signatures.
**/
cdk_error_t
cdk_keydb_get_sk (cdk_keydb_hd_t hd, u32 * keyid, cdk_seckey_t * ret_sk)
{
cdk_kbnode_t snode, node;
cdk_seckey_t sk;
cdk_error_t rc;
int pkttype;
if (!keyid || !ret_sk)
return CDK_Inv_Value;
if (!hd)
return CDK_Error_No_Keyring;
*ret_sk = NULL;
rc = cdk_keydb_get_bykeyid (hd, keyid, &snode);
if (rc)
return rc;
node = keydb_find_bykeyid (snode, keyid, CDK_DBSEARCH_KEYID);
if (!node)
{
cdk_kbnode_release (snode);
return CDK_Error_No_Key;
}
/* We need to release the packet itself but not its contents
and thus we detach the openpgp packet and release the structure. */
_cdk_pkt_detach_free (node->pkt, &pkttype, (void *) &sk);
_cdk_kbnode_clone (node);
cdk_kbnode_release (snode);
*ret_sk = sk;
return 0;
}
static int
is_selfsig (cdk_kbnode_t node, const u32 * keyid)
{
cdk_pkt_signature_t sig;
if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
return 0;
sig = node->pkt->pkt.signature;
if ((sig->sig_class >= 0x10 && sig->sig_class <= 0x13) &&
sig->keyid[0] == keyid[0] && sig->keyid[1] == keyid[1])
return 1;
return 0;
}
/* Find the newest self signature for the public key @pk
and return the signature node. */
static cdk_kbnode_t
find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk)
{
cdk_kbnode_t n, sig;
unsigned int ts;
u32 keyid[2];
cdk_pk_get_keyid (pk, keyid);
sig = NULL;
ts = 0;
for (n = key; n; n = n->next)
{
if (is_selfsig (n, keyid) && n->pkt->pkt.signature->timestamp > ts)
{
ts = n->pkt->pkt.signature->timestamp;
sig = n;
}
}
return sig;
}
static cdk_error_t
keydb_merge_selfsig (cdk_kbnode_t key, u32 * keyid)
{
cdk_kbnode_t node, kbnode, unode;
cdk_subpkt_t s = NULL;
cdk_pkt_signature_t sig = NULL;
cdk_pkt_userid_t uid = NULL;
const byte *symalg = NULL, *hashalg = NULL, *compalg = NULL;
size_t nsymalg = 0, nhashalg = 0, ncompalg = 0, n = 0;
size_t key_usage = 0, key_expire = 0;
if (!key)
return CDK_Inv_Value;
for (node = key; node; node = node->next)
{
if (!is_selfsig (node, keyid))
continue;
unode = cdk_kbnode_find_prev (key, node, CDK_PKT_USER_ID);
if (!unode)
return CDK_Error_No_Key;
uid = unode->pkt->pkt.user_id;
sig = node->pkt->pkt.signature;
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PRIMARY_UID);
if (s)
uid->is_primary = 1;
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_FEATURES);
if (s && s->size == 1 && s->d[0] & 0x01)
uid->mdc_feature = 1;
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_KEY_EXPIRE);
if (s && s->size == 4)
key_expire = _cdk_buftou32 (s->d);
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_KEY_FLAGS);
if (s)
{
if (s->d[0] & 0x03) /* cert + sign data */
key_usage |= CDK_KEY_USG_SIGN;
if (s->d[0] & 0x0C) /* encrypt comm. + storage */
key_usage |= CDK_KEY_USG_ENCR;
if (s->d[0] & 0x20)
key_usage |= CDK_KEY_USG_AUTH;
}
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_SYM);
if (s)
{
symalg = s->d;
nsymalg = s->size;
n += s->size + 1;
}
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_HASH);
if (s)
{
hashalg = s->d;
nhashalg = s->size;
n += s->size + 1;
}
s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_ZIP);
if (s)
{
compalg = s->d;
ncompalg = s->size;
n += s->size + 1;
}
if (uid->prefs != NULL)
cdk_free (uid->prefs);
if (!n || !hashalg || !compalg || !symalg)
uid->prefs = NULL;
else
{
uid->prefs = cdk_calloc (1, sizeof (*uid->prefs) * (n + 1));
if (!uid->prefs)
return CDK_Out_Of_Core;
n = 0;
for (; nsymalg; nsymalg--, n++)
{
uid->prefs[n].type = CDK_PREFTYPE_SYM;
uid->prefs[n].value = *symalg++;
}
for (; nhashalg; nhashalg--, n++)
{
uid->prefs[n].type = CDK_PREFTYPE_HASH;
uid->prefs[n].value = *hashalg++;
}
for (; ncompalg; ncompalg--, n++)
{
uid->prefs[n].type = CDK_PREFTYPE_ZIP;
uid->prefs[n].value = *compalg++;
}
uid->prefs[n].type = CDK_PREFTYPE_NONE; /* end of list marker */
uid->prefs[n].value = 0;
uid->prefs_size = n;
}
}
/* Now we add the extracted information to the primary key. */
kbnode = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
if (kbnode)
{
cdk_pkt_pubkey_t pk = kbnode->pkt->pkt.public_key;
if (uid && uid->prefs && n)
{
if (pk->prefs != NULL)
cdk_free (pk->prefs);
pk->prefs = _cdk_copy_prefs (uid->prefs);
pk->prefs_size = n;
}
if (key_expire)
{
pk->expiredate = pk->timestamp + key_expire;
pk->has_expired = pk->expiredate > (u32) time (NULL) ? 0 : 1;
}
if (key_usage)
pk->pubkey_usage = key_usage;
pk->is_invalid = 0;
}
return 0;
}
static cdk_error_t
keydb_parse_allsigs (cdk_kbnode_t knode, cdk_keydb_hd_t hd, int check)
{
cdk_kbnode_t node, kb;
cdk_pkt_signature_t sig;
cdk_pkt_pubkey_t pk;
cdk_subpkt_t s = NULL;
u32 expiredate = 0, curtime = (u32) time (NULL);
u32 keyid[2];
if (!knode)
return CDK_Inv_Value;
if (check && !hd)
return CDK_Inv_Mode;
kb = cdk_kbnode_find (knode, CDK_PKT_SECRET_KEY);
if (kb)
return 0;
/* Reset */
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_USER_ID)
node->pkt->pkt.user_id->is_revoked = 0;
else if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
node->pkt->pkt.public_key->is_revoked = 0;
}
kb = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
if (!kb)
return CDK_Wrong_Format;
cdk_pk_get_keyid (kb->pkt->pkt.public_key, keyid);
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_SIGNATURE)
{
sig = node->pkt->pkt.signature;
/* Revocation certificates for primary keys */
if (sig->sig_class == 0x20)
{
kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_KEY);
if (kb)
{
kb->pkt->pkt.public_key->is_revoked = 1;
if (check)
_cdk_pk_check_sig (hd, kb, node, NULL);
}
else
return CDK_Error_No_Key;
}
/* Revocation certificates for subkeys */
else if (sig->sig_class == 0x28)
{
kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY);
if (kb)
{
kb->pkt->pkt.public_key->is_revoked = 1;
if (check)
_cdk_pk_check_sig (hd, kb, node, NULL);
}
else
return CDK_Error_No_Key;
}
/* Revocation certifcates for user ID's */
else if (sig->sig_class == 0x30)
{
if (sig->keyid[0] != keyid[0] || sig->keyid[1] != keyid[1])
continue; /* revokes an earlier signature, no userID. */
kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_USER_ID);
if (kb)
{
kb->pkt->pkt.user_id->is_revoked = 1;
if (check)
_cdk_pk_check_sig (hd, kb, node, NULL);
}
else
return CDK_Error_No_Key;
}
/* Direct certificates for primary keys */
else if (sig->sig_class == 0x1F)
{
kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_KEY);
if (kb)
{
pk = kb->pkt->pkt.public_key;
pk->is_invalid = 0;
s = cdk_subpkt_find (node->pkt->pkt.signature->hashed,
CDK_SIGSUBPKT_KEY_EXPIRE);
if (s)
{
expiredate = _cdk_buftou32 (s->d);
pk->expiredate = pk->timestamp + expiredate;
pk->has_expired = pk->expiredate > curtime ? 0 : 1;
}
if (check)
_cdk_pk_check_sig (hd, kb, node, NULL);
}
else
return CDK_Error_No_Key;
}
/* Direct certificates for subkeys */
else if (sig->sig_class == 0x18)
{
kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY);
if (kb)
{
pk = kb->pkt->pkt.public_key;
pk->is_invalid = 0;
s = cdk_subpkt_find (node->pkt->pkt.signature->hashed,
CDK_SIGSUBPKT_KEY_EXPIRE);
if (s)
{
expiredate = _cdk_buftou32 (s->d);
pk->expiredate = pk->timestamp + expiredate;
pk->has_expired = pk->expiredate > curtime ? 0 : 1;
}
if (check)
_cdk_pk_check_sig (hd, kb, node, NULL);
}
else
return CDK_Error_No_Key;
}
}
}
node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
if (node && node->pkt->pkt.public_key->version == 3)
{
/* v3 public keys have no additonal signatures for the key directly.
we say the key is valid when we have at least a self signature. */
pk = node->pkt->pkt.public_key;
for (node = knode; node; node = node->next)
{
if (is_selfsig (node, keyid))
{
pk->is_invalid = 0;
break;
}
}
}
if (node && (node->pkt->pkt.public_key->is_revoked ||
node->pkt->pkt.public_key->has_expired))
{
/* If the primary key has been revoked, mark all subkeys as invalid
because without a primary key they are not useable */
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
node->pkt->pkt.public_key->is_invalid = 1;
}
}
return 0;
}
cdk_error_t
cdk_keydb_get_keyblock (cdk_stream_t inp, cdk_kbnode_t * r_knode)
{
cdk_packet_t pkt;
cdk_kbnode_t knode, node;
cdk_desig_revoker_t revkeys;
cdk_error_t rc;
u32 keyid[2], main_keyid[2];
off_t old_off;
int key_seen, got_key;
if (!inp || !r_knode)
return CDK_Inv_Value;
/* Reset all values. */
keyid[0] = keyid[1] = 0;
main_keyid[0] = main_keyid[1] = 0;
revkeys = NULL;
knode = NULL;
key_seen = got_key = 0;
*r_knode = NULL;
rc = CDK_EOF;
while (!cdk_stream_eof (inp))
{
cdk_pkt_new (&pkt);
old_off = cdk_stream_tell (inp);
rc = cdk_pkt_read (inp, pkt);
if (rc)
{
cdk_pkt_release (pkt);
if (rc == CDK_EOF)
break;
else
{ /* Release all packets we reached so far. */
_cdk_log_debug ("keydb_get_keyblock: error %d\n", rc);
cdk_kbnode_release (knode);
return rc;
}
}
if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
pkt->pkttype == CDK_PKT_SECRET_KEY ||
pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
{
if (key_seen && (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
pkt->pkttype == CDK_PKT_SECRET_KEY))
{
/* The next key starts here so set the file pointer
and leave the loop. */
cdk_stream_seek (inp, old_off);
cdk_pkt_release (pkt);
break;
}
if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
pkt->pkttype == CDK_PKT_SECRET_KEY)
{
_cdk_pkt_get_keyid (pkt, main_keyid);
key_seen = 1;
}
else if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
{
if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
{
pkt->pkt.public_key->main_keyid[0] = main_keyid[0];
pkt->pkt.public_key->main_keyid[1] = main_keyid[1];
}
else
{
pkt->pkt.secret_key->main_keyid[0] = main_keyid[0];
pkt->pkt.secret_key->main_keyid[1] = main_keyid[1];
}
}
/* We save this for the signature */
_cdk_pkt_get_keyid (pkt, keyid);
got_key = 1;
}
else if (pkt->pkttype == CDK_PKT_USER_ID)
;
else if (pkt->pkttype == CDK_PKT_SIGNATURE)
{
pkt->pkt.signature->key[0] = keyid[0];
pkt->pkt.signature->key[1] = keyid[1];
if (pkt->pkt.signature->sig_class == 0x1F &&
pkt->pkt.signature->revkeys)
revkeys = pkt->pkt.signature->revkeys;
}
node = cdk_kbnode_new (pkt);
if (!knode)
knode = node;
else
_cdk_kbnode_add (knode, node);
}
if (got_key)
{
keydb_merge_selfsig (knode, main_keyid);
rc = keydb_parse_allsigs (knode, NULL, 0);
if (revkeys)
{
node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
if (node)
node->pkt->pkt.public_key->revkeys = revkeys;
}
}
else
cdk_kbnode_release (knode);
*r_knode = got_key ? knode : NULL;
/* It is possible that we are in an EOF condition after we
successfully read a keyblock. For example if the requested
key is the last in the file. */
if (rc == CDK_EOF && got_key)
rc = 0;
return rc;
}
/* Return the type of the given data. In case it cannot be classified,
a substring search will be performed. */
static int
classify_data (const byte * buf, size_t len)
{
int type;
int i;
if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
{ /* Skip hex prefix. */
buf += 2;
len -= 2;
}
/* The length of the data does not match either a keyid or a fingerprint. */
if (len != 8 && len != 16 && len != 40)
return CDK_DBSEARCH_SUBSTR;
for (i = 0; i < len; i++)
{
if (!isxdigit (buf[i]))
return CDK_DBSEARCH_SUBSTR;
}
if (i != len)
return CDK_DBSEARCH_SUBSTR;
switch (len)
{
case 8:
type = CDK_DBSEARCH_SHORT_KEYID;
break;
case 16:
type = CDK_DBSEARCH_KEYID;
break;
case 40:
type = CDK_DBSEARCH_FPR;
break;
default:
type = CDK_DBSEARCH_SUBSTR;
break;
}
return type;
}
/**
* cdk_keydb_export:
* @hd: the keydb handle
* @out: the output stream
* @remusr: the list of key pattern to export
*
* Export a list of keys to the given output stream.
* Use string list with names for pattering searching.
* This procedure strips local signatures.
**/
cdk_error_t
cdk_keydb_export (cdk_keydb_hd_t hd, cdk_stream_t out, cdk_strlist_t remusr)
{
cdk_kbnode_t knode, node;
cdk_strlist_t r;
cdk_error_t rc;
int old_ctb;
for (r = remusr; r; r = r->next)
{
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, r->d);
if (rc)
return rc;
rc = cdk_keydb_search (hd, &knode);
if (rc)
return rc;
node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
if (!node)
return CDK_Error_No_Key;
/* If the key is a version 3 key, use the old packet
format for the output. */
if (node->pkt->pkt.public_key->version == 3)
old_ctb = 1;
else
old_ctb = 0;
for (node = knode; node; node = node->next)
{
/* No specified format; skip them */
if (node->pkt->pkttype == CDK_PKT_RING_TRUST)
continue;
/* We never export local signed signatures */
if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
!node->pkt->pkt.signature->flags.exportable)
continue;
/* Filter out invalid signatures */
if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
!KEY_CAN_SIGN (node->pkt->pkt.signature->pubkey_algo))
continue;
/* Adjust the ctb flag if needed. */
node->pkt->old_ctb = old_ctb;
rc = cdk_pkt_write (out, node->pkt);
if (rc)
{
cdk_kbnode_release (knode);
return rc;
}
}
cdk_kbnode_release (knode);
knode = NULL;
}
return 0;
}
static cdk_packet_t
find_key_packet (cdk_kbnode_t knode, int *r_is_sk)
{
cdk_packet_t pkt;
pkt = cdk_kbnode_find_packet (knode, CDK_PKT_PUBLIC_KEY);
if (!pkt)
{
pkt = cdk_kbnode_find_packet (knode, CDK_PKT_SECRET_KEY);
if (r_is_sk)
*r_is_sk = pkt ? 1 : 0;
}
return pkt;
}
/* Return 1 if the is allowd in a key node. */
static int
is_key_node (cdk_kbnode_t node)
{
switch (node->pkt->pkttype)
{
case CDK_PKT_SIGNATURE:
case CDK_PKT_SECRET_KEY:
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_SECRET_SUBKEY:
case CDK_PKT_PUBLIC_SUBKEY:
case CDK_PKT_USER_ID:
case CDK_PKT_ATTRIBUTE:
return 1;
default:
return 0;
}
return 0;
}
cdk_error_t
cdk_keydb_import (cdk_keydb_hd_t hd, cdk_kbnode_t knode)
{
cdk_kbnode_t node, chk;
cdk_packet_t pkt;
cdk_stream_t out;
cdk_error_t rc;
u32 keyid[2];
if (!hd || !knode)
return CDK_Inv_Value;
pkt = find_key_packet (knode, NULL);
if (!pkt)
return CDK_Inv_Packet;
_cdk_pkt_get_keyid (pkt, keyid);
chk = NULL;
cdk_keydb_get_bykeyid (hd, keyid, &chk);
if (chk)
{ /* FIXME: search for new signatures */
cdk_kbnode_release (chk);
return 0;
}
/* We append data to the stream so we need to close
the stream here to re-open it later. */
if (hd->fp)
{
cdk_stream_close (hd->fp);
hd->fp = NULL;
}
rc = _cdk_stream_append (hd->name, &out);
if (rc)
return rc;
for (node = knode; node; node = node->next)
{
if (node->pkt->pkttype == CDK_PKT_RING_TRUST)
continue; /* No uniformed syntax for this packet */
if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
!node->pkt->pkt.signature->flags.exportable)
{
_cdk_log_debug ("key db import: skip local signature\n");
continue;
}
if (!is_key_node (node))
{
_cdk_log_debug ("key db import: skip invalid node of type %d\n",
node->pkt->pkttype);
continue;
}
rc = cdk_pkt_write (out, node->pkt);
if (rc)
{
cdk_stream_close (out);
return rc;
}
}
cdk_stream_close (out);
if (!hd->no_cache)
cdk_keydb_idx_rebuild (hd);
hd->stats.new_keys++;
return 0;
}
cdk_error_t
_cdk_keydb_check_userid (cdk_keydb_hd_t hd, u32 * keyid, const char *id)
{
cdk_kbnode_t knode = NULL, unode = NULL;
cdk_error_t rc;
int check;
if (!hd)
return CDK_Inv_Value;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
if (rc)
return rc;
rc = cdk_keydb_search (hd, &knode);
if (rc)
return rc;
rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_EXACT, (char *) id);
if (!rc)
rc = cdk_keydb_search (hd, &unode);
if (rc)
{
cdk_kbnode_release (knode);
return rc;
}
check = 0;
cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
if (unode && find_by_keyid (unode, hd->dbs))
check++;
cdk_kbnode_release (unode);
cdk_keydb_search_start (hd, CDK_DBSEARCH_EXACT, (char *) id);
if (knode && find_by_pattern (knode, hd->dbs))
check++;
cdk_kbnode_release (knode);
return check == 2 ? 0 : CDK_Inv_Value;
}
/**
* cdk_keydb_check_sk:
* @hd: the key db handle
* @keyid: the 64-bit keyid
*
* Check if a secret key with the given key ID is available
* in the key database.
**/
cdk_error_t
cdk_keydb_check_sk (cdk_keydb_hd_t hd, u32 * keyid)
{
cdk_stream_t db;
cdk_packet_t pkt;
cdk_error_t rc;
u32 kid[2];
if (!hd || !keyid)
return CDK_Inv_Value;
if (!hd->secret)
return CDK_Inv_Mode;
rc = _cdk_keydb_open (hd, &db);
if (rc)
return rc;
cdk_pkt_new (&pkt);
while (!cdk_pkt_read (db, pkt))
{
if (pkt->pkttype != CDK_PKT_SECRET_KEY &&
pkt->pkttype != CDK_PKT_SECRET_SUBKEY)
{
cdk_pkt_free (pkt);
continue;
}
cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
if (KEYID_CMP (kid, keyid))
{
cdk_pkt_release (pkt);
return 0;
}
cdk_pkt_free (pkt);
}
cdk_pkt_release (pkt);
return CDK_Error_No_Key;
}
/**
* cdk_listkey_start:
* @r_ctx: pointer to store the new context
* @db: the key database handle
* @patt: string pattern
* @fpatt: recipients from a stringlist to show
*
* Prepare a key listing with the given parameters. Two modes are supported.
* The first mode uses string pattern to determine if the key should be
* returned or not. The other mode uses a string list to request the key
* which should be listed.
**/
cdk_error_t
cdk_listkey_start (cdk_listkey_t * r_ctx, cdk_keydb_hd_t db,
const char *patt, cdk_strlist_t fpatt)
{
cdk_listkey_t ctx;
cdk_stream_t inp;
cdk_error_t rc;
if (!r_ctx || !db)
return CDK_Inv_Value;
if ((patt && fpatt) || (!patt && !fpatt))
return CDK_Inv_Mode;
rc = _cdk_keydb_open (db, &inp);
if (rc)
return rc;
ctx = cdk_calloc (1, sizeof *ctx);
if (!ctx)
return CDK_Out_Of_Core;
ctx->db = db;
ctx->inp = inp;
if (patt)
{
ctx->u.patt = cdk_strdup (patt);
if (!ctx->u.patt)
return CDK_Out_Of_Core;
}
else if (fpatt)
{
cdk_strlist_t l;
for (l = fpatt; l; l = l->next)
cdk_strlist_add (&ctx->u.fpatt, l->d);
}
ctx->type = patt ? 1 : 0;
ctx->init = 1;
*r_ctx = ctx;
return 0;
}
/**
* cdk_listkey_close:
* @ctx: the list key context
*
* Free the list key context.
**/
void
cdk_listkey_close (cdk_listkey_t ctx)
{
if (!ctx)
return;
if (ctx->type)
cdk_free (ctx->u.patt);
else
cdk_strlist_free (ctx->u.fpatt);
cdk_free (ctx);
}
/**
* cdk_listkey_next:
* @ctx: list key context
* @r_key: the pointer to the new key node object
*
* Retrieve the next key from the pattern of the key list context.
**/
cdk_error_t
cdk_listkey_next (cdk_listkey_t ctx, cdk_kbnode_t * ret_key)
{
if (!ctx || !ret_key)
return CDK_Inv_Value;
if (!ctx->init)
return CDK_Inv_Mode;
if (ctx->type && ctx->u.patt[0] == '*')
return cdk_keydb_get_keyblock (ctx->inp, ret_key);
else if (ctx->type)
{
cdk_kbnode_t node;
struct cdk_dbsearch_s ks;
cdk_error_t rc;
for (;;)
{
rc = cdk_keydb_get_keyblock (ctx->inp, &node);
if (rc)
return rc;
memset (&ks, 0, sizeof (ks));
ks.type = CDK_DBSEARCH_SUBSTR;
ks.u.pattern = ctx->u.patt;
if (find_by_pattern (node, &ks))
{
*ret_key = node;
return 0;
}
cdk_kbnode_release (node);
node = NULL;
}
}
else
{
if (!ctx->t)
ctx->t = ctx->u.fpatt;
else if (ctx->t->next)
ctx->t = ctx->t->next;
else
return CDK_EOF;
return cdk_keydb_get_bypattern (ctx->db, ctx->t->d, ret_key);
}
return CDK_General_Error;
}
int
_cdk_keydb_is_secret (cdk_keydb_hd_t db)
{
return db->secret;
}
-307
View File
@@ -1,307 +0,0 @@
/* Literal.c - Literal packet filters
* Copyright (C) 2002, 2003 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <time.h>
#include "opencdk.h"
#include "main.h"
#include "filters.h"
/* Duplicate the string @s but strip of possible
relative folder names of it. */
static char *
dup_trim_filename (const char *s)
{
char *p = NULL;
p = strrchr (s, '/');
if (!p)
p = strrchr (s, '\\');
if (!p)
return cdk_strdup (s);
return cdk_strdup (p + 1);
}
static cdk_error_t
literal_decode (void *opaque, FILE * in, FILE * out)
{
literal_filter_t *pfx = opaque;
cdk_stream_t si, so;
cdk_packet_t pkt;
cdk_pkt_literal_t pt;
byte buf[BUFSIZE];
size_t nread;
int bufsize;
cdk_error_t rc;
_cdk_log_debug ("literal filter: decode\n");
if (!pfx || !in || !out)
return CDK_Inv_Value;
rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
if (rc)
return rc;
cdk_pkt_new (&pkt);
rc = cdk_pkt_read (si, pkt);
if (rc || pkt->pkttype != CDK_PKT_LITERAL)
{
cdk_pkt_release (pkt);
cdk_stream_close (si);
return !rc ? CDK_Inv_Packet : rc;
}
rc = _cdk_stream_fpopen (out, STREAMCTL_WRITE, &so);
if (rc)
{
cdk_pkt_release (pkt);
cdk_stream_close (si);
return rc;
}
pt = pkt->pkt.literal;
pfx->mode = pt->mode;
if (pfx->filename && pt->namelen > 0)
{
/* The name in the literal packet is more authorative. */
cdk_free (pfx->filename);
pfx->filename = dup_trim_filename (pt->name);
}
else if (!pfx->filename && pt->namelen > 0)
pfx->filename = dup_trim_filename (pt->name);
else if (!pt->namelen && !pfx->filename && pfx->orig_filename)
{
/* In this case, we need to derrive the output file name
from the original name and cut off the OpenPGP extension.
If this is not possible, we return an error. */
if (!stristr (pfx->orig_filename, ".gpg") &&
!stristr (pfx->orig_filename, ".pgp") &&
!stristr (pfx->orig_filename, ".asc"))
{
cdk_pkt_release (pkt);
cdk_stream_close (si);
cdk_stream_close (so);
_cdk_log_debug
("literal filter: no file name and no PGP extension\n");
return CDK_Inv_Mode;
}
_cdk_log_debug ("literal filter: derrive file name from original\n");
pfx->filename = dup_trim_filename (pfx->orig_filename);
pfx->filename[strlen (pfx->filename) - 4] = '\0';
}
while (!feof (in))
{
_cdk_log_debug ("literal_decode: part on %d size %lu\n",
pfx->blkmode.on, pfx->blkmode.size);
if (pfx->blkmode.on)
bufsize = pfx->blkmode.size;
else
bufsize = pt->len < DIM (buf) ? pt->len : DIM (buf);
nread = cdk_stream_read (pt->buf, buf, bufsize);
if (nread == EOF)
{
rc = CDK_File_Error;
break;
}
if (pfx->md)
gcry_md_write (pfx->md, buf, nread);
cdk_stream_write (so, buf, nread);
pt->len -= nread;
if (pfx->blkmode.on)
{
pfx->blkmode.size = _cdk_pkt_read_len (in, &pfx->blkmode.on);
if (pfx->blkmode.size == (size_t) EOF)
return CDK_Inv_Packet;
}
if (pt->len <= 0 && !pfx->blkmode.on)
break;
}
cdk_stream_close (si);
cdk_stream_close (so);
cdk_pkt_release (pkt);
return rc;
}
static char
intmode_to_char (int mode)
{
switch (mode)
{
case CDK_LITFMT_BINARY:
return 'b';
case CDK_LITFMT_TEXT:
return 't';
case CDK_LITFMT_UNICODE:
return 'u';
default:
return 'b';
}
return 'b';
}
static cdk_error_t
literal_encode (void *opaque, FILE * in, FILE * out)
{
literal_filter_t *pfx = opaque;
cdk_pkt_literal_t pt;
cdk_stream_t si;
cdk_packet_t pkt;
size_t filelen;
cdk_error_t rc;
_cdk_log_debug ("literal filter: encode\n");
if (!pfx || !in || !out)
return CDK_Inv_Value;
if (!pfx->filename)
{
pfx->filename = cdk_strdup ("_CONSOLE");
if (!pfx->filename)
return CDK_Out_Of_Core;
}
rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
if (rc)
return rc;
filelen = strlen (pfx->filename);
cdk_pkt_new (&pkt);
pt = pkt->pkt.literal = cdk_calloc (1, sizeof *pt + filelen - 1);
if (!pt)
{
cdk_pkt_release (pkt);
cdk_stream_close (si);
return CDK_Out_Of_Core;
}
memcpy (pt->name, pfx->filename, filelen);
pt->namelen = filelen;
pt->name[pt->namelen] = '\0';
pt->timestamp = (u32) time (NULL);
pt->mode = intmode_to_char (pfx->mode);
pt->len = cdk_stream_get_length (si);
pt->buf = si;
pkt->old_ctb = 1;
pkt->pkttype = CDK_PKT_LITERAL;
pkt->pkt.literal = pt;
rc = _cdk_pkt_write_fp (out, pkt);
cdk_pkt_release (pkt);
cdk_stream_close (si);
return rc;
}
int
_cdk_filter_literal (void *opaque, int ctl, FILE * in, FILE * out)
{
if (ctl == STREAMCTL_READ)
return literal_decode (opaque, in, out);
else if (ctl == STREAMCTL_WRITE)
return literal_encode (opaque, in, out);
else if (ctl == STREAMCTL_FREE)
{
literal_filter_t *pfx = opaque;
if (pfx)
{
_cdk_log_debug ("free literal filter\n");
cdk_free (pfx->filename);
pfx->filename = NULL;
cdk_free (pfx->orig_filename);
pfx->orig_filename = NULL;
return 0;
}
}
return CDK_Inv_Mode;
}
static int
text_encode (void *opaque, FILE * in, FILE * out)
{
const char *s;
char buf[2048];
if (!in || !out)
return CDK_Inv_Value;
/* FIXME: This code does not work for very long lines. */
while (!feof (in))
{
s = fgets (buf, DIM (buf) - 1, in);
if (!s)
break;
_cdk_trim_string (buf, 1);
fwrite (buf, 1, strlen (buf), out);
}
return 0;
}
static int
text_decode (void *opaque, FILE * in, FILE * out)
{
text_filter_t *tfx = opaque;
const char *s;
char buf[2048];
if (!tfx || !in || !out)
return CDK_Inv_Value;
while (!feof (in))
{
s = fgets (buf, DIM (buf) - 1, in);
if (!s)
break;
_cdk_trim_string (buf, 0);
fwrite (buf, 1, strlen (buf), out);
fwrite (tfx->lf, 1, strlen (tfx->lf), out);
}
return 0;
}
int
_cdk_filter_text (void *opaque, int ctl, FILE * in, FILE * out)
{
if (ctl == STREAMCTL_READ)
return text_encode (opaque, in, out);
else if (ctl == STREAMCTL_WRITE)
return text_decode (opaque, in, out);
else if (ctl == STREAMCTL_FREE)
{
text_filter_t *tfx = opaque;
if (tfx)
{
_cdk_log_debug ("free text filter\n");
tfx->lf = NULL;
}
}
return CDK_Inv_Mode;
}
-779
View File
@@ -1,779 +0,0 @@
/* main.c
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include "opencdk.h"
#include "main.h"
#include "packet.h"
/* Set a default cipher algorithm and a digest algorithm.
Even if AES and SHA-256 are not 'MUST' in the latest
OpenPGP draft, AES seems to be a good choice. */
#define DEFAULT_CIPHER_ALGO GCRY_CIPHER_AES
#define DEFAULT_DIGEST_ALGO GCRY_MD_SHA256
/* The site of the secure memory which is allocated in gcrypt. */
#define SECMEM_SIZE 16384
/* Hooks to custom memory allocation functions. */
static void *(*alloc_func) (size_t n) = gcry_xmalloc;
static void *(*alloc_secure_func) (size_t n) = gcry_malloc_secure;
static void *(*realloc_func) (void *p, size_t n) = gcry_realloc;
static void *(*calloc_func) (size_t m, size_t n) = gcry_calloc;
static void (*free_func) (void *) = gcry_free;
static int malloc_hooks = 0;
static int secmem_init = 0;
/* Global settings for the logging. */
static cdk_log_fnc_t log_handler = NULL;
static void *log_handler_value = NULL;
static int log_level = CDK_LOG_NONE;
/**
* cdk_strerror:
* @ec: the error number
*
* Return an error text for the given id.
**/
const char *
cdk_strerror (int ec)
{
static char buf[20];
switch (ec)
{
case CDK_EOF:
return "End Of File";
case CDK_Success:
return "No error";
case CDK_General_Error:
return "General error";
case CDK_File_Error:
return strerror (errno);
case CDK_Bad_Sig:
return "Bad signature";
case CDK_Inv_Packet:
return "Invalid packet";
case CDK_Inv_Algo:
return "Invalid algorithm";
case CDK_Not_Implemented:
return "This is not implemented yet";
case CDK_Armor_Error:
return "ASCII armor error";
case CDK_Armor_CRC_Error:
return "ASCII armored damaged (CRC error)";
case CDK_MPI_Error:
return "Invalid or missformed MPI";
case CDK_Inv_Value:
return "Invalid parameter or value";
case CDK_Error_No_Key:
return "No key available or not found";
case CDK_Chksum_Error:
return "Check for key does not match";
case CDK_Time_Conflict:
return "Time conflict";
case CDK_Zlib_Error:
return "ZLIB error";
case CDK_Weak_Key:
return "Weak key was detected";
case CDK_Out_Of_Core:
return "Out of core!!";
case CDK_Wrong_Seckey:
return "Wrong secret key";
case CDK_Wrong_Format:
return "Data has wrong format";
case CDK_Bad_MDC:
return "Manipulated MDC detected";
case CDK_Inv_Mode:
return "Invalid mode";
case CDK_Error_No_Keyring:
return "No keyring available";
case CDK_Inv_Packet_Ver:
return "Invalid version for packet";
case CDK_Too_Short:
return "Buffer or object is too short";
case CDK_Unusable_Key:
return "Unusable public key";
case CDK_No_Data:
return "No data";
case CDK_No_Passphrase:
return "No passphrase supplied";
case CDK_Network_Error:
return "A network error occurred";
default:
sprintf (buf, "ec=%d", ec);
return buf;
}
return NULL;
}
static void
out_of_core (size_t n)
{
fprintf (stderr, "\n ** fatal error: out of memory (%d bytes) **\n", n);
}
/**
* cdk_set_malloc_hooks:
* @new_alloc_func: malloc replacement
* @new_alloc_secure_func: secure malloc replacement
* @new_realloc_func: realloc replacement
* @new_calloc_func: calloc replacement
* @new_free_func: free replacement
*
* Set private memory hooks for the library.
*/
void
cdk_set_malloc_hooks (void *(*new_alloc_func) (size_t n),
void *(*new_alloc_secure_func) (size_t n),
void *(*new_realloc_func) (void *p, size_t n),
void *(*new_calloc_func) (size_t m, size_t n),
void (*new_free_func) (void *))
{
alloc_func = new_alloc_func;
alloc_secure_func = new_alloc_secure_func;
realloc_func = new_realloc_func;
calloc_func = new_calloc_func;
free_func = new_free_func;
malloc_hooks = 1;
}
/**
* cdk_malloc_hook_initialized:
*
* Return if the malloc hooks are already initialized.
**/
int
cdk_malloc_hook_initialized (void)
{
return malloc_hooks;
}
void *
cdk_malloc (size_t size)
{
void *p = alloc_func (size);
if (!p)
out_of_core (size);
return p;
}
/**
* cdk_calloc:
* @n: amount of elements
* @m: size of one element
*
* Safe wrapper around the c-function calloc.
**/
void *
cdk_calloc (size_t n, size_t m)
{
void *p = calloc_func (n, m);
if (!p)
out_of_core (m);
return p;
}
/* Things which need to be done after the secure memory initialisation. */
static void
_secmem_finish (void)
{
gcry_control (GCRYCTL_DROP_PRIVS);
}
/* Initialize the secure memory. */
static void
_secmem_init (size_t size)
{
if (secmem_init == 1)
return;
if (size >= SECMEM_SIZE)
size = SECMEM_SIZE;
/* Check if no other library has already initialized gcrypt. */
if (!gcry_control (GCRYCTL_ANY_INITIALIZATION_P))
{
_cdk_log_debug ("init: libgcrypt initialize.\n");
gcry_control (GCRYCTL_INIT_SECMEM, size, 0);
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
gcry_control (GCRYCTL_DISABLE_SECMEM_WARN);
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
secmem_init = 1;
}
}
/* Things which needs to be done to deinit the secure memory. */
static void
_secmem_end (void)
{
gcry_control (GCRYCTL_TERM_SECMEM);
secmem_init = 0;
}
/* The Windows system needs to startup the Winsock interface first
before we can use any socket related function. */
#ifdef _WIN32
static void
init_sockets (void)
{
static int initialized = 0;
WSADATA wsdata;
if (initialized)
return;
if (WSAStartup (0x202, &wsdata))
_cdk_log_debug ("winsock init failed.\n");
initialized = 1;
}
static void
deinit_sockets (void)
{
WSACleanup ();
}
#else
void
init_sockets (void)
{
}
void
deinit_sockets (void)
{
}
#endif
/**
* cdk_lib_startup:
*
* Prepare the internal structures of the library.
* This function should be called before any other CDK function.
*/
void
cdk_lib_startup (void)
{
_secmem_init (SECMEM_SIZE);
_secmem_finish ();
init_sockets ();
}
/**
* cdk_lib_shutdown:
*
* Shutdown the library and free all internal and globally used
* memory and structures. This function should be called in the
* exit handler of the calling program.
*/
void
cdk_lib_shutdown (void)
{
deinit_sockets ();
_secmem_end ();
}
/**
* cdk_salloc:
* @size: how much bytes should be allocated.
* @clear: shall the buffer cleared after the allocation?
*
* Allocated the requested amount of bytes in 'secure' memory.
*/
void *
cdk_salloc (size_t size, int clear)
{
void *p;
if (!secmem_init)
_secmem_init (SECMEM_SIZE);
p = alloc_secure_func (size);
if (!p)
out_of_core (size);
if (clear)
memset (p, 0, size);
return p;
}
void *
cdk_realloc (void *ptr, size_t size)
{
void *p = realloc_func (ptr, size);
if (!p)
out_of_core (size);
return p;
}
char *
cdk_strdup (const char *ptr)
{
char *p = cdk_malloc (strlen (ptr) + 1);
if (p)
strcpy (p, ptr);
return p;
}
void
cdk_free (void *ptr)
{
if (ptr)
free_func (ptr);
}
/* Internal logging routine. */
static void
_cdk_logv (int level, const char *fmt, va_list arg_ptr)
{
if (log_handler)
log_handler (log_handler_value, level, fmt, arg_ptr);
else
{
if (level == CDK_LOG_NONE)
return;
if (level == CDK_LOG_DEBUG)
fputs ("DBG: ", stderr);
vfprintf (stderr, fmt, arg_ptr);
}
}
/**
* cdk_set_log_handler:
* @logfnc: the function pointer
* @opaque: a private values for the function
*
* Set a custom handler for logging.
**/
void
cdk_set_log_handler (cdk_log_fnc_t logfnc, void *opaque)
{
log_handler = logfnc;
log_handler_value = opaque;
}
/**
* cdk_set_log_level:
* @lvl: the level
*
* Set the verbosity level.
**/
void
cdk_set_log_level (int level)
{
log_level = level;
}
/* Return the current log level of the lib. */
int
_cdk_get_log_level (void)
{
return log_level;
}
void
_cdk_log_info (const char *fmt, ...)
{
va_list arg;
if (log_level == CDK_LOG_NONE)
return;
va_start (arg, fmt);
_cdk_logv (CDK_LOG_INFO, fmt, arg);
va_end (arg);
}
void
_cdk_log_debug (const char *fmt, ...)
{
va_list arg;
if (log_level < CDK_LOG_DEBUG)
return;
va_start (arg, fmt);
_cdk_logv (CDK_LOG_DEBUG, fmt, arg);
va_end (arg);
}
/* Use the passphrase callback in the handle HD or
return NULL if there is no valid callback. */
char *
_cdk_passphrase_get (cdk_ctx_t hd, const char *prompt)
{
if (!hd || !hd->passphrase_cb)
return NULL;
return hd->passphrase_cb (hd->passphrase_cb_value, prompt);
}
static void
handle_set_cipher (cdk_ctx_t hd, int cipher)
{
if (!hd)
return;
if (gcry_cipher_test_algo (cipher))
cipher = DEFAULT_CIPHER_ALGO;
hd->cipher_algo = cipher;
}
static void
handle_set_digest (cdk_ctx_t hd, int digest)
{
if (!hd)
return;
if (gcry_md_test_algo (digest))
digest = DEFAULT_DIGEST_ALGO;
hd->digest_algo = digest;
}
static void
handle_set_s2k (cdk_ctx_t hd, int mode, int digest, int cipher)
{
if (!hd)
return;
if (gcry_cipher_test_algo (cipher))
cipher = DEFAULT_CIPHER_ALGO;
if (gcry_md_test_algo (digest))
digest = DEFAULT_DIGEST_ALGO;
if (mode != CDK_S2K_SIMPLE &&
mode != CDK_S2K_SALTED && mode != CDK_S2K_ITERSALTED)
mode = CDK_S2K_ITERSALTED;
hd->_s2k.mode = mode;
hd->_s2k.digest_algo = digest;
}
static void
handle_set_compress (cdk_ctx_t hd, int algo, int level)
{
if (!hd)
return;
if (algo < 0 || algo > 2)
algo = 0;
hd->compress.algo = algo;
if (!algo)
hd->opt.compress = 0;
else
{
if (level > 0 && level < 10)
hd->compress.level = level;
else
hd->compress.level = 6;
}
}
/**
* cdk_handle_control:
* @hd: session handle
* @action: flag which indicates whether put or get is requested
* @cmd: command id
*
* Perform various control operations for the current session.
**/
int
cdk_handle_control (cdk_ctx_t hd, int action, int cmd, ...)
{
va_list arg_ptr;
int set = action == CDK_CTLF_SET, val = 0;
if (!hd)
return -1;
if (action != CDK_CTLF_SET && action != CDK_CTLF_GET)
return -1;
va_start (arg_ptr, cmd);
switch (cmd)
{
case CDK_CTL_ARMOR:
if (set)
hd->opt.armor = va_arg (arg_ptr, int);
else
val = hd->opt.armor;
break;
case CDK_CTL_CIPHER:
if (set)
handle_set_cipher (hd, va_arg (arg_ptr, int));
else
val = hd->cipher_algo;
break;
case CDK_CTL_DIGEST:
if (set)
handle_set_digest (hd, va_arg (arg_ptr, int));
else
val = hd->digest_algo;
break;
case CDK_CTL_OVERWRITE:
if (set)
hd->opt.overwrite = va_arg (arg_ptr, int);
else
val = hd->opt.overwrite;
break;
case CDK_CTL_COMPRESS:
if (set)
{
int algo = va_arg (arg_ptr, int);
int level = va_arg (arg_ptr, int);
handle_set_compress (hd, algo, level);
}
else
val = hd->compress.algo;
break;
case CDK_CTL_S2K:
if (set)
{
int mode = va_arg (arg_ptr, int);
int digest = va_arg (arg_ptr, int);
int cipher = va_arg (arg_ptr, int);
handle_set_s2k (hd, mode, digest, cipher);
}
else
val = hd->_s2k.mode;
break;
case CDK_CTL_FORCE_DIGEST:
if (set)
hd->opt.force_digest = va_arg (arg_ptr, int);
else
val = hd->opt.force_digest;
break;
case CDK_CTL_BLOCKMODE_ON:
if (set)
hd->opt.blockmode = va_arg (arg_ptr, int);
else
val = hd->opt.blockmode;
break;
default:
val = -1;
break;
}
va_end (arg_ptr);
return val;
}
/**
* cdk_handle_new:
* @r_ctx: context to store the handle
*
* create a new session handle.
**/
cdk_error_t
cdk_handle_new (cdk_ctx_t * r_ctx)
{
cdk_ctx_t c;
if (!r_ctx)
return CDK_Inv_Value;
c = cdk_calloc (1, sizeof *c);
if (!c)
return CDK_Out_Of_Core;
/* For S2K use the iterated and salted mode and use the
default digest and cipher algorithms. Because the MDC
feature will be used, the default cipher should use a
blocksize of 128 bits. */
c->_s2k.mode = CDK_S2K_ITERSALTED;
c->_s2k.digest_algo = DEFAULT_DIGEST_ALGO;
c->opt.mdc = 1;
c->opt.compress = 1;
c->opt.armor = 0;
c->opt.textmode = 0;
c->digest_algo = DEFAULT_DIGEST_ALGO;
c->cipher_algo = DEFAULT_CIPHER_ALGO;
c->compress.algo = CDK_COMPRESS_ZIP;
c->compress.level = 6;
*r_ctx = c;
return 0;
}
/**
* cdk_handle_set_keyring:
* @hd: session handle
* @type: public=0 or secret=1 keyring type
* @kringname: file name of the keyring which shall be used.
*
* Convenient function to set the keyring for the current session.
*/
cdk_error_t
cdk_handle_set_keyring (cdk_ctx_t hd, int type, const char *kringname)
{
cdk_keydb_hd_t db;
cdk_error_t err;
err = cdk_keydb_new_from_file (&db, type, kringname);
if (err)
return err;
if (!type)
hd->db.pub = db;
else
hd->db.sec = db;
hd->db.close_db = 1;
return 0;
}
/**
* cdk_handle_set_keydb:
* @hd: session handle
* @db: the database handle
*
* set the key database handle.
* the function automatically detects whether this is a public or
* secret keyring and the right handle is set.
**/
void
cdk_handle_set_keydb (cdk_ctx_t hd, cdk_keydb_hd_t db)
{
if (!hd)
return;
if (_cdk_keydb_is_secret (db))
hd->db.sec = db;
else
hd->db.pub = db;
}
/**
* cdk_handle_get_keydb:
* @hd: session handle
* @type: type of the keyring
*
* Return the keydb handle from the session handle.
* The caller should not free these handles.
**/
cdk_keydb_hd_t
cdk_handle_get_keydb (cdk_ctx_t hd, int type)
{
if (!hd)
return NULL;
if (type == CDK_DBTYPE_PK_KEYRING)
return hd->db.pub;
else if (type == CDK_DBTYPE_SK_KEYRING)
return hd->db.sec;
return NULL;
}
/**
* cdk_handle_set_passphrase_cb:
* @hd: session handle
* @cb: callback function
* @cb_value: the opaque value for the cb function
*
* set the passphrase callback.
**/
void
cdk_handle_set_passphrase_cb (cdk_ctx_t hd,
char *(*cb) (void *opa, const char *prompt),
void *cb_value)
{
if (!hd)
return;
hd->passphrase_cb = cb;
hd->passphrase_cb_value = cb_value;
}
/**
* cdk_handle_verify_get_result:
* @hd: the session handle
*
* Return the verify result for the current session.
* Do not free the pointer.
**/
cdk_verify_result_t
cdk_handle_verify_get_result (cdk_ctx_t hd)
{
return hd->result.verify;
}
/**
* cdk_handle_free:
* @hd: the handle
*
* Release the main handle.
**/
void
cdk_handle_free (cdk_ctx_t hd)
{
if (!hd)
return;
_cdk_result_verify_free (hd->result.verify);
/* If cdk_handle_set_keyring() were used, we need to free the key db
handles here because the handles are not controlled by the user. */
if (hd->db.close_db)
{
if (hd->db.pub)
cdk_keydb_free (hd->db.pub);
if (hd->db.sec)
cdk_keydb_free (hd->db.sec);
hd->db.pub = hd->db.sec = NULL;
}
cdk_free (hd->dek);
cdk_free (hd);
}
-183
View File
@@ -1,183 +0,0 @@
/* main.h
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef CDK_MAIN_H
#define CDK_MAIN_H
#include <gcrypt.h>
#include "types.h"
/* The general size of a buffer for the variou modules. */
#define BUFSIZE 8192
/* This is the default block size for the partial length packet mode. */
#define DEF_BLOCKSIZE 8192
#define DEF_BLOCKBITS 13 /* 2^13 = 8192 */
/* For now SHA-1 is used to create fingerprint for keys.
But if this will ever change, it is a good idea to
have a constant for it to avoid to change it in all files. */
#define KEY_FPR_LEN 20
#include "context.h"
/* The maximal amount of bits a multi precsion integer can have. */
#define MAX_MPI_BITS 16384
#define MAX_MPI_BYTES (MAX_MPI_BITS/8)
/* Because newer DSA variants are not limited to SHA-1, we must consider
that SHA-512 is used and increase the buffer size of the digest. */
#define MAX_DIGEST_LEN 64
/* Helper to find out if the signature were made over a user ID
or if the signature revokes a previous user ID. */
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
#define IS_UID_REV(s) ((s)->sig_class == 0x30)
#define DEBUG_PKT (_cdk_get_log_level () == (CDK_LOG_DEBUG+1))
/* Helper to find out if a key has the requested capability. */
#define KEY_CAN_ENCRYPT(a) (_cdk_pk_algo_usage ((a)) & CDK_KEY_USG_ENCR)
#define KEY_CAN_SIGN(a) (_cdk_pk_algo_usage ((a)) & CDK_KEY_USG_SIGN)
#define KEY_CAN_AUTH(a) (_cdk_pk_algo_usage ((a)) & CDK_KEY_USG_AUTH)
/* Helper macro to make sure the buffer is overwritten. */
#define wipemem(_ptr,_len) do { \
volatile char *_vptr = (volatile char *)(_ptr); \
size_t _vlen = (_len); \
while (_vlen) \
{ \
*_vptr = 0; \
_vptr++; \
_vlen--; \
} } while (0)
/*-- armor.c --*/
const char * _cdk_armor_get_lineend (void);
/*-- main.c --*/
int _cdk_get_log_level (void);
void _cdk_log_info (const char * fmt, ...);
void _cdk_log_debug (const char * fmt, ...);
char * _cdk_passphrase_get (cdk_ctx_t hd, const char *prompt);
/*-- misc.c --*/
int _cdk_check_args( int overwrite, const char * in, const char * out );
u32 _cdk_buftou32 (const byte * buf);
void _cdk_u32tobuf (u32 u, byte * buf);
const char *_cdk_memistr (const char * buf, size_t buflen, const char * sub);
cdk_error_t _cdk_map_gcry_error (gcry_error_t err);
#define map_gcry_error(err) _cdk_map_gcry_error (err)
/* Helper to provide case insentensive strstr version. */
#define stristr(haystack, needle) \
_cdk_memistr((haystack), strlen (haystack), (needle))
/*-- proc-packet.c --*/
cdk_error_t _cdk_proc_packets (cdk_ctx_t hd, cdk_stream_t inp,
cdk_stream_t data,
const char *output, cdk_stream_t outstream,
gcry_md_hd_t md);
cdk_error_t _cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx);
/*-- pubkey.c --*/
u32 _cdk_pkt_get_keyid (cdk_packet_t pkt, u32 * keyid);
cdk_error_t _cdk_pkt_get_fingerprint (cdk_packet_t pkt, byte *fpr);
int _cdk_pk_algo_usage (int algo);
int _cdk_pk_test_algo (int algo, unsigned int usage);
int _cdk_sk_get_csum (cdk_pkt_seckey_t sk);
/*-- new-packet.c --*/
byte * _cdk_subpkt_get_array (cdk_subpkt_t s, int count, size_t * r_nbytes);
cdk_error_t _cdk_subpkt_copy (cdk_subpkt_t * r_dst, cdk_subpkt_t src);
void _cdk_pkt_detach_free (cdk_packet_t pkt, int *r_pkttype, void **ctx);
/*-- sig-check.c --*/
cdk_error_t _cdk_sig_check (cdk_pkt_pubkey_t pk, cdk_pkt_signature_t sig,
gcry_md_hd_t digest, int * r_expired);
cdk_error_t _cdk_hash_sig_data (cdk_pkt_signature_t sig, gcry_md_hd_t hd);
cdk_error_t _cdk_hash_userid (cdk_pkt_userid_t uid, int sig_version, gcry_md_hd_t md);
cdk_error_t _cdk_hash_pubkey (cdk_pkt_pubkey_t pk, gcry_md_hd_t md,
int use_fpr);
cdk_error_t _cdk_pk_check_sig (cdk_keydb_hd_t hd,
cdk_kbnode_t knode,
cdk_kbnode_t snode, int *is_selfsig);
/*-- kbnode.c --*/
void _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node);
void _cdk_kbnode_clone (cdk_kbnode_t node);
/*-- sesskey.c --*/
cdk_error_t _cdk_digest_encode_pkcs1 (byte **r_md, size_t *r_mdlen,
int pk_algo,
const byte * md,
int digest_algo, unsigned nbits);
cdk_error_t _cdk_sk_unprotect_auto (cdk_ctx_t hd, cdk_pkt_seckey_t sk);
/*-- keydb.c --*/
int _cdk_keydb_is_secret (cdk_keydb_hd_t db);
cdk_error_t _cdk_keydb_get_pk_byusage (cdk_keydb_hd_t hd, const char * name,
cdk_pkt_pubkey_t * ret_pk, int usage);
cdk_error_t _cdk_keydb_get_sk_byusage (cdk_keydb_hd_t hd, const char * name,
cdk_pkt_seckey_t * ret_sk, int usage);
cdk_error_t _cdk_keydb_check_userid (cdk_keydb_hd_t hd, u32 * keyid,
const char * id);
/*-- sign.c --*/
int _cdk_sig_hash_for (cdk_pkt_pubkey_t pk);
void _cdk_trim_string (char * s, int canon);
cdk_error_t _cdk_sig_create (cdk_pkt_pubkey_t pk, cdk_pkt_signature_t sig);
cdk_error_t _cdk_sig_complete (cdk_pkt_signature_t sig, cdk_pkt_seckey_t sk,
gcry_md_hd_t hd);
/*-- stream.c --*/
void _cdk_stream_set_compress_algo (cdk_stream_t s, int algo);
cdk_error_t _cdk_stream_open_mode (const char *file, const char *mode,
cdk_stream_t *ret_s);
void * _cdk_stream_get_opaque( cdk_stream_t s, int fid );
const char * _cdk_stream_get_fname( cdk_stream_t s );
FILE * _cdk_stream_get_fp( cdk_stream_t s );
int _cdk_stream_gets( cdk_stream_t s, char * buf, size_t count );
cdk_error_t _cdk_stream_append( const char * file, cdk_stream_t * ret_s );
int _cdk_stream_get_errno( cdk_stream_t s );
cdk_error_t _cdk_stream_set_blockmode( cdk_stream_t s, size_t nbytes );
int _cdk_stream_get_blockmode( cdk_stream_t s );
int _cdk_stream_puts( cdk_stream_t s, const char * buf );
cdk_error_t _cdk_stream_fpopen (FILE * fp, unsigned write_mode,
cdk_stream_t *ret_out);
/*-- verify.c --*/
void _cdk_result_verify_free (cdk_verify_result_t res);
cdk_verify_result_t _cdk_result_verify_new (void);
/*-- read-packet.c --*/
size_t _cdk_pkt_read_len (FILE * inp, size_t *ret_partial);
/*-- write-packet.c --*/
cdk_error_t _cdk_pkt_write_fp( FILE * out, cdk_packet_t pkt );
/*-- seskey.c --*/
cdk_error_t _cdk_s2k_copy (cdk_s2k_t *r_dst, cdk_s2k_t src);
cdk_error_t cdk_dek_encode_pkcs1 (cdk_dek_t dek, size_t nbits,
gcry_mpi_t *r_enc);
cdk_error_t cdk_dek_decode_pkcs1 (cdk_dek_t * ret_dek, gcry_mpi_t esk);
cdk_error_t cdk_dek_extract (cdk_dek_t * ret_dek, cdk_ctx_t hd,
cdk_pkt_pubkey_enc_t enc,
cdk_pkt_seckey_t sk );
#endif /* CDK_MAIN_H */
-571
View File
@@ -1,571 +0,0 @@
/* misc.c
* Copyright (C) 2002, 2003 Timo Schulz
* Copyright (C) 1998-2002, 2007 Free Software Foundation, Inc.
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include "opencdk.h"
#include "main.h"
u32
_cdk_buftou32 (const byte * buf)
{
u32 u;
if (!buf)
return 0;
u = buf[0] << 24;
u |= buf[1] << 16;
u |= buf[2] << 8;
u |= buf[3];
return u;
}
void
_cdk_u32tobuf (u32 u, byte * buf)
{
if (!buf)
return;
buf[0] = u >> 24;
buf[1] = u >> 16;
buf[2] = u >> 8;
buf[3] = u;
}
static const char *
parse_version_number (const char *s, int *number)
{
int val = 0;
if (*s == '0' && isdigit (s[1]))
return NULL;
/* leading zeros are not allowed */
for (; isdigit (*s); s++)
{
val *= 10;
val += *s - '0';
}
*number = val;
return val < 0 ? NULL : s;
}
static const char *
parse_version_string (const char *s, int *major, int *minor, int *micro)
{
s = parse_version_number (s, major);
if (!s || *s != '.')
return NULL;
s++;
s = parse_version_number (s, minor);
if (!s || *s != '.')
return NULL;
s++;
s = parse_version_number (s, micro);
if (!s)
return NULL;
return s; /* patchlevel */
}
/**
* cdk_check_version:
* @req_version: The requested version
*
* Check that the the version of the library is at minimum the requested
* one and return the version string; return NULL if the condition is
* not satisfied. If a NULL is passed to this function, no check is done,
*but the version string is simply returned.
**/
const char *
cdk_check_version (const char *req_version)
{
const char *ver = VERSION;
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl, *rq_plvl;
if (!req_version)
return ver;
my_plvl = parse_version_string (ver, &my_major, &my_minor, &my_micro);
if (!my_plvl)
return NULL;
/* very strange our own version is bogus */
rq_plvl = parse_version_string (req_version, &rq_major, &rq_minor,
&rq_micro);
if (!rq_plvl)
return NULL; /* req version string is invalid */
if (my_major > rq_major
|| (my_major == rq_major && my_minor > rq_minor)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro > rq_micro)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
return ver;
return NULL;
}
/**
* cdk_strlist_free:
* @sl: the string list
*
* Release the string list object.
**/
void
cdk_strlist_free (cdk_strlist_t sl)
{
cdk_strlist_t sl2;
for (; sl; sl = sl2)
{
sl2 = sl->next;
cdk_free (sl);
}
}
/**
* cdk_strlist_add:
* @list: destination string list
* @string: the string to add
*
* Add the given list to the string list.
**/
cdk_strlist_t
cdk_strlist_add (cdk_strlist_t * list, const char *string)
{
cdk_strlist_t sl;
if (!string)
return NULL;
sl = cdk_calloc (1, sizeof *sl + strlen (string) + 1);
if (!sl)
return NULL;
strcpy (sl->d, string);
sl->next = *list;
*list = sl;
return sl;
}
/**
* cdk_strlist_next:
* @root: the opaque string list.
* @r_str: optional argument to store the string data.
*
* Return the next string list node from @root. The optional
* argument @r_str return the data of the current (!) node.
**/
cdk_strlist_t
cdk_strlist_next (cdk_strlist_t root, const char **r_str)
{
cdk_strlist_t node;
if (root && r_str)
*r_str = root->d;
for (node = root->next; node; node = node->next)
return node;
return NULL;
}
const char *
_cdk_memistr (const char *buf, size_t buflen, const char *sub)
{
const byte *t, *s;
size_t n;
for (t = (byte *) buf, n = buflen, s = (byte *) sub; n; t++, n--)
{
if (toupper (*t) == toupper (*s))
{
for (buf = t++, buflen = n--, s++;
n && toupper (*t) == toupper ((byte) * s); t++, s++, n--)
;
if (!*s)
return buf;
t = (byte *) buf;
n = buflen;
s = (byte *) sub;
}
}
return NULL;
}
/**
* cdk_utf8_encode:
* @string:
*
* Encode the given string in utf8 and return it.
**/
char *
cdk_utf8_encode (const char *string)
{
const byte *s;
char *buffer;
byte *p;
size_t length;
/* FIXME: We should use iconv if possible for utf8 issues. */
for (s = (const byte *) string, length = 0; *s; s++)
{
length++;
if (*s & 0x80)
length++;
}
buffer = cdk_calloc (1, length + 1);
for (p = (byte *) buffer, s = (byte *) string; *s; s++)
{
if (*s & 0x80)
{
*p++ = 0xc0 | ((*s >> 6) & 3);
*p++ = 0x80 | (*s & 0x3f);
}
else
*p++ = *s;
}
*p = 0;
return buffer;
}
/**
* cdk_utf8_decode:
* @string: the string to decode
* @length: the length of the string
* @delim: the delimiter
*
* Decode the given utf8 string and return the native representation.
**/
char *
cdk_utf8_decode (const char *string, size_t length, int delim)
{
int nleft;
int i;
byte encbuf[8];
int encidx;
const byte *s;
size_t n;
byte *buffer = NULL, *p = NULL;
unsigned long val = 0;
size_t slen;
int resync = 0;
/* 1. pass (p==NULL): count the extended utf-8 characters */
/* 2. pass (p!=NULL): create string */
for (;;)
{
for (slen = length, nleft = encidx = 0, n = 0, s = (byte *) string;
slen; s++, slen--)
{
if (resync)
{
if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
{
/* still invalid */
if (p)
{
sprintf ((char *) p, "\\x%02x", *s);
p += 4;
}
n += 4;
continue;
}
resync = 0;
}
if (!nleft)
{
if (!(*s & 0x80))
{ /* plain ascii */
if (*s < 0x20 || *s == 0x7f || *s == delim ||
(delim && *s == '\\'))
{
n++;
if (p)
*p++ = '\\';
switch (*s)
{
case '\n':
n++;
if (p)
*p++ = 'n';
break;
case '\r':
n++;
if (p)
*p++ = 'r';
break;
case '\f':
n++;
if (p)
*p++ = 'f';
break;
case '\v':
n++;
if (p)
*p++ = 'v';
break;
case '\b':
n++;
if (p)
*p++ = 'b';
break;
case 0:
n++;
if (p)
*p++ = '0';
break;
default:
n += 3;
if (p)
{
sprintf ((char *) p, "x%02x", *s);
p += 3;
}
break;
}
}
else
{
if (p)
*p++ = *s;
n++;
}
}
else if ((*s & 0xe0) == 0xc0)
{ /* 110x xxxx */
val = *s & 0x1f;
nleft = 1;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xf0) == 0xe0)
{ /* 1110 xxxx */
val = *s & 0x0f;
nleft = 2;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xf8) == 0xf0)
{ /* 1111 0xxx */
val = *s & 0x07;
nleft = 3;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xfc) == 0xf8)
{ /* 1111 10xx */
val = *s & 0x03;
nleft = 4;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xfe) == 0xfc)
{ /* 1111 110x */
val = *s & 0x01;
nleft = 5;
encidx = 0;
encbuf[encidx++] = *s;
}
else
{ /* invalid encoding: print as \xnn */
if (p)
{
sprintf ((char *) p, "\\x%02x", *s);
p += 4;
}
n += 4;
resync = 1;
}
}
else if (*s < 0x80 || *s >= 0xc0)
{ /* invalid */
if (p)
{
for (i = 0; i < encidx; i++)
{
sprintf ((char *) p, "\\x%02x", encbuf[i]);
p += 4;
}
sprintf ((char *) p, "\\x%02x", *s);
p += 4;
}
n += 4 + 4 * encidx;
nleft = 0;
encidx = 0;
resync = 1;
}
else
{
encbuf[encidx++] = *s;
val <<= 6;
val |= *s & 0x3f;
if (!--nleft)
{ /* ready native set */
if (val >= 0x80 && val < 256)
{
n++; /* we can simply print this character */
if (p)
*p++ = val;
}
else
{ /* we do not have a translation: print utf8 */
if (p)
{
for (i = 0; i < encidx; i++)
{
sprintf ((char *) p, "\\x%02x", encbuf[i]);
p += 4;
}
}
n += encidx * 4;
encidx = 0;
}
}
}
}
if (!buffer) /* allocate the buffer after the first pass */
buffer = p = cdk_malloc (n + 1);
else
{
*p = 0; /* make a string */
return (char *) buffer;
}
}
}
/* Map the gcrypt error to a valid opencdk error constant. */
cdk_error_t
_cdk_map_gcry_error (gcry_error_t err)
{
/* FIXME: We need to catch them all. */
switch (gpg_err_code (err))
{
case GPG_ERR_NO_ERROR:
return CDK_Success;
case GPG_ERR_INV_VALUE:
return CDK_Inv_Value;
case GPG_ERR_GENERAL:
return CDK_General_Error;
case GPG_ERR_INV_PACKET:
return CDK_Inv_Packet;
case GPG_ERR_TOO_SHORT:
return CDK_Too_Short;
case GPG_ERR_TOO_LARGE:
return CDK_Inv_Value;
case GPG_ERR_NO_PUBKEY:
case GPG_ERR_NO_SECKEY:
return CDK_Error_No_Key;
case GPG_ERR_BAD_SIGNATURE:
return CDK_Bad_Sig;
case GPG_ERR_NO_DATA:
return CDK_No_Data;
default:
break;
}
return (cdk_error_t) err;
}
/* Remove all trailing white spaces from the string. */
void
_cdk_trim_string (char *s, int canon)
{
while (s && *s &&
(s[strlen (s) - 1] == '\t' ||
s[strlen (s) - 1] == '\r' ||
s[strlen (s) - 1] == '\n' || s[strlen (s) - 1] == ' '))
s[strlen (s) - 1] = '\0';
if (canon)
strcat (s, "\r\n");
}
int
_cdk_check_args (int overwrite, const char *in, const char *out)
{
struct stat stbuf;
if (!in || !out)
return CDK_Inv_Value;
if (strlen (in) == strlen (out) && strcmp (in, out) == 0)
return CDK_Inv_Mode;
if (!overwrite && !stat (out, &stbuf))
return CDK_Inv_Mode;
return 0;
}
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
FILE *
my_tmpfile (void)
{
/* Because the tmpfile() version of wine is not really useful,
we implement our own version to avoid problems with 'make check'. */
static const char *letters = "abcdefghijklmnopqrstuvwxyz";
char buf[512], rnd[24];
FILE *fp;
int fd, i;
gcry_create_nonce (rnd, DIM (rnd));
for (i = 0; i < DIM (rnd) - 1; i++)
{
char c = letters[(unsigned char) rnd[i] % 26];
rnd[i] = c;
}
rnd[DIM (rnd) - 1] = 0;
if (!GetTempPath (464, buf))
return NULL;
strcat (buf, "_cdk_");
strcat (buf, rnd);
/* We need to make sure the file will be deleted when it is closed. */
fd = _open (buf, _O_CREAT | _O_EXCL | _O_TEMPORARY |
_O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE);
if (fd == -1)
return NULL;
fp = fdopen (fd, "w+b");
if (fp != NULL)
return fp;
_close (fd);
return NULL;
}
#else
FILE *
my_tmpfile (void)
{
return tmpfile ();
}
#endif
-874
View File
@@ -1,874 +0,0 @@
/* new-packet.c - packet handling (freeing, copying, ...)
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
/* Release an array of MPI values. */
void
_cdk_free_mpibuf (size_t n, gcry_mpi_t * array)
{
while (n--)
{
gcry_mpi_release (array[n]);
array[n] = NULL;
}
}
/**
* cdk_pkt_new:
* @r_pkt: the new packet
*
* Allocate a new packet.
**/
cdk_error_t
cdk_pkt_new (cdk_packet_t * r_pkt)
{
cdk_packet_t pkt;
if (!r_pkt)
return CDK_Inv_Value;
pkt = cdk_calloc (1, sizeof *pkt);
if (!pkt)
return CDK_Out_Of_Core;
*r_pkt = pkt;
return 0;
}
static void
free_symkey_enc (cdk_pkt_symkey_enc_t enc)
{
if (!enc)
return;
cdk_s2k_free (enc->s2k);
cdk_free (enc);
}
static void
free_pubkey_enc (cdk_pkt_pubkey_enc_t enc)
{
size_t nenc;
if (!enc)
return;
nenc = cdk_pk_get_nenc (enc->pubkey_algo);
_cdk_free_mpibuf (nenc, enc->mpi);
cdk_free (enc);
}
static void
free_literal (cdk_pkt_literal_t pt)
{
if (!pt)
return;
/* The buffer which is referenced in this packet is closed
elsewhere. To close it here would cause a double close. */
cdk_free (pt);
}
void
_cdk_free_userid (cdk_pkt_userid_t uid)
{
if (!uid)
return;
cdk_free (uid->prefs);
uid->prefs = NULL;
cdk_free (uid->attrib_img);
uid->attrib_img = NULL;
cdk_free (uid);
}
void
_cdk_free_signature (cdk_pkt_signature_t sig)
{
cdk_desig_revoker_t r;
size_t nsig;
if (!sig)
return;
nsig = cdk_pk_get_nsig (sig->pubkey_algo);
_cdk_free_mpibuf (nsig, sig->mpi);
cdk_subpkt_free (sig->hashed);
sig->hashed = NULL;
cdk_subpkt_free (sig->unhashed);
sig->unhashed = NULL;
while (sig->revkeys)
{
r = sig->revkeys->next;
cdk_free (sig->revkeys);
sig->revkeys = r;
}
cdk_free (sig);
}
void
cdk_pk_release (cdk_pubkey_t pk)
{
size_t npkey;
if (!pk)
return;
npkey = cdk_pk_get_npkey (pk->pubkey_algo);
_cdk_free_userid (pk->uid);
pk->uid = NULL;
cdk_free (pk->prefs);
pk->prefs = NULL;
_cdk_free_mpibuf (npkey, pk->mpi);
cdk_free (pk);
}
void
cdk_sk_release (cdk_seckey_t sk)
{
size_t nskey;
if (!sk)
return;
nskey = cdk_pk_get_nskey (sk->pubkey_algo);
_cdk_free_mpibuf (nskey, sk->mpi);
cdk_free (sk->encdata);
sk->encdata = NULL;
cdk_pk_release (sk->pk);
sk->pk = NULL;
cdk_s2k_free (sk->protect.s2k);
sk->protect.s2k = NULL;
cdk_free (sk);
}
static void
free_encrypted (cdk_pkt_encrypted_t enc)
{
if (!enc)
return;
/* This is just a reference for the filters to know where
the encrypted data starts and to read from the sream. It
us closed elsewhere and to close it here would double close it. */
/*cdk_stream_close (enc->buf); */
enc->buf = NULL;
cdk_free (enc);
}
/* Detach the openpgp packet from the packet structure
and release the packet structure itself. */
void
_cdk_pkt_detach_free (cdk_packet_t pkt, int *r_pkttype, void **ctx)
{
/* For now we just allow this for keys. */
switch (pkt->pkttype)
{
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
*ctx = pkt->pkt.public_key;
break;
case CDK_PKT_SECRET_KEY:
case CDK_PKT_SECRET_SUBKEY:
*ctx = pkt->pkt.secret_key;
break;
default:
*r_pkttype = 0;
return;
}
/* The caller might expect a specific packet type and
is not interested to store it for later use. */
if (r_pkttype)
*r_pkttype = pkt->pkttype;
cdk_free (pkt);
}
void
cdk_pkt_free (cdk_packet_t pkt)
{
if (!pkt)
return;
switch (pkt->pkttype)
{
case CDK_PKT_ATTRIBUTE:
case CDK_PKT_USER_ID:
_cdk_free_userid (pkt->pkt.user_id);
break;
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
cdk_pk_release (pkt->pkt.public_key);
break;
case CDK_PKT_SECRET_KEY:
case CDK_PKT_SECRET_SUBKEY:
cdk_sk_release (pkt->pkt.secret_key);
break;
case CDK_PKT_SIGNATURE:
_cdk_free_signature (pkt->pkt.signature);
break;
case CDK_PKT_PUBKEY_ENC:
free_pubkey_enc (pkt->pkt.pubkey_enc);
break;
case CDK_PKT_SYMKEY_ENC:
free_symkey_enc (pkt->pkt.symkey_enc);
break;
case CDK_PKT_MDC:
cdk_free (pkt->pkt.mdc);
break;
case CDK_PKT_ENCRYPTED:
case CDK_PKT_ENCRYPTED_MDC:
free_encrypted (pkt->pkt.encrypted);
break;
case CDK_PKT_ONEPASS_SIG:
cdk_free (pkt->pkt.onepass_sig);
break;
case CDK_PKT_LITERAL:
free_literal (pkt->pkt.literal);
break;
case CDK_PKT_COMPRESSED:
cdk_free (pkt->pkt.compressed);
break;
default:
break;
}
/* Reset the packet type to avoid, when cdk_pkt_release() will be
used, that the second cdk_pkt_free() call will double free the data. */
pkt->pkttype = 0;
}
/**
* cdk_pkt_release:
* @pkt: the packet
*
* Free the contents of the given package and
* release the memory of the structure.
**/
void
cdk_pkt_release (cdk_packet_t pkt)
{
if (!pkt)
return;
cdk_pkt_free (pkt);
cdk_free (pkt);
}
/**
* cdk_pkt_alloc:
* @r_pkt: output is the new packet
* @pkttype: the requested packet type
*
* Allocate a new packet structure with the given packet type.
**/
cdk_error_t
cdk_pkt_alloc (cdk_packet_t * r_pkt, int pkttype)
{
cdk_packet_t pkt;
int rc;
if (!r_pkt)
return CDK_Inv_Value;
rc = cdk_pkt_new (&pkt);
if (rc)
return rc;
switch (pkttype)
{
case CDK_PKT_USER_ID:
pkt->pkt.user_id = cdk_calloc (1, sizeof pkt->pkt.user_id);
if (!pkt->pkt.user_id)
return CDK_Out_Of_Core;
break;
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
if (!pkt->pkt.public_key)
return CDK_Out_Of_Core;
break;
case CDK_PKT_SECRET_KEY:
case CDK_PKT_SECRET_SUBKEY:
pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
pkt->pkt.secret_key->pk =
cdk_calloc (1, sizeof *pkt->pkt.secret_key->pk);
if (!pkt->pkt.secret_key || !pkt->pkt.secret_key->pk)
return CDK_Out_Of_Core;
break;
case CDK_PKT_SIGNATURE:
pkt->pkt.signature = cdk_calloc (1, sizeof *pkt->pkt.signature);
if (!pkt->pkt.signature)
return CDK_Out_Of_Core;
break;
case CDK_PKT_SYMKEY_ENC:
pkt->pkt.symkey_enc = cdk_calloc (1, sizeof *pkt->pkt.symkey_enc);
if (!pkt->pkt.symkey_enc)
return CDK_Out_Of_Core;
break;
case CDK_PKT_PUBKEY_ENC:
pkt->pkt.pubkey_enc = cdk_calloc (1, sizeof *pkt->pkt.pubkey_enc);
if (!pkt->pkt.pubkey_enc)
return CDK_Out_Of_Core;
break;
case CDK_PKT_MDC:
pkt->pkt.mdc = cdk_calloc (1, sizeof *pkt->pkt.mdc);
if (!pkt->pkt.mdc)
return CDK_Out_Of_Core;
break;
case CDK_PKT_ENCRYPTED_MDC:
case CDK_PKT_ENCRYPTED:
pkt->pkt.symkey_enc = cdk_calloc (1, sizeof *pkt->pkt.symkey_enc);
if (!pkt->pkt.symkey_enc)
return CDK_Out_Of_Core;
break;
case CDK_PKT_ONEPASS_SIG:
pkt->pkt.onepass_sig = cdk_calloc (1, sizeof *pkt->pkt.onepass_sig);
if (!pkt->pkt.onepass_sig)
return CDK_Out_Of_Core;
break;
case CDK_PKT_LITERAL:
/* FIXME: We would need the size of the file name to allocate extra
bytes, otherwise the result would be useless. */
pkt->pkt.literal = cdk_calloc (1, sizeof *pkt->pkt.literal);
if (!pkt->pkt.literal)
return CDK_Out_Of_Core;
break;
}
pkt->pkttype = pkttype;
*r_pkt = pkt;
return 0;
}
cdk_prefitem_t
_cdk_copy_prefs (const cdk_prefitem_t prefs)
{
size_t n = 0;
struct cdk_prefitem_s *new_prefs;
if (!prefs)
return NULL;
for (n = 0; prefs[n].type; n++)
;
new_prefs = cdk_calloc (1, sizeof *new_prefs * (n + 1));
if (!new_prefs)
return NULL;
for (n = 0; prefs[n].type; n++)
{
new_prefs[n].type = prefs[n].type;
new_prefs[n].value = prefs[n].value;
}
new_prefs[n].type = CDK_PREFTYPE_NONE;
new_prefs[n].value = 0;
return new_prefs;
}
cdk_error_t
_cdk_copy_userid (cdk_pkt_userid_t * dst, cdk_pkt_userid_t src)
{
cdk_pkt_userid_t u;
if (!dst || !src)
return CDK_Inv_Value;
*dst = NULL;
u = cdk_calloc (1, sizeof *u + strlen (src->name) + 1);
if (!u)
return CDK_Out_Of_Core;
memcpy (u, src, sizeof *u);
memcpy (u->name, src->name, strlen (src->name));
u->prefs = _cdk_copy_prefs (src->prefs);
if (src->selfsig)
_cdk_copy_signature (&u->selfsig, src->selfsig);
*dst = u;
return 0;
}
cdk_error_t
_cdk_copy_pubkey (cdk_pkt_pubkey_t * dst, cdk_pkt_pubkey_t src)
{
cdk_pkt_pubkey_t k;
int i;
if (!dst || !src)
return CDK_Inv_Value;
*dst = NULL;
k = cdk_calloc (1, sizeof *k);
if (!k)
return CDK_Out_Of_Core;
memcpy (k, src, sizeof *k);
if (src->uid)
_cdk_copy_userid (&k->uid, src->uid);
if (src->prefs)
k->prefs = _cdk_copy_prefs (src->prefs);
for (i = 0; i < cdk_pk_get_npkey (src->pubkey_algo); i++)
k->mpi[i] = gcry_mpi_copy (src->mpi[i]);
*dst = k;
return 0;
}
cdk_error_t
_cdk_copy_seckey (cdk_pkt_seckey_t * dst, cdk_pkt_seckey_t src)
{
cdk_pkt_seckey_t k;
int i;
if (!dst || !src)
return CDK_Inv_Value;
*dst = NULL;
k = cdk_calloc (1, sizeof *k);
if (!k)
return CDK_Out_Of_Core;
memcpy (k, src, sizeof *k);
_cdk_copy_pubkey (&k->pk, src->pk);
if (src->encdata)
{
k->encdata = cdk_calloc (1, src->enclen + 1);
if (!k->encdata)
return CDK_Out_Of_Core;
memcpy (k->encdata, src->encdata, src->enclen);
}
_cdk_s2k_copy (&k->protect.s2k, src->protect.s2k);
for (i = 0; i < cdk_pk_get_nskey (src->pubkey_algo); i++)
{
k->mpi[i] = gcry_mpi_copy (src->mpi[i]);
gcry_mpi_set_flag (k->mpi[i], GCRYMPI_FLAG_SECURE);
}
*dst = k;
return 0;
}
cdk_error_t
_cdk_copy_pk_to_sk (cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk)
{
if (!pk || !sk)
return CDK_Inv_Value;
sk->version = pk->version;
sk->expiredate = pk->expiredate;
sk->pubkey_algo = pk->pubkey_algo;
sk->has_expired = pk->has_expired;
sk->is_revoked = pk->is_revoked;
sk->main_keyid[0] = pk->main_keyid[0];
sk->main_keyid[1] = pk->main_keyid[1];
sk->keyid[0] = pk->keyid[0];
sk->keyid[1] = pk->keyid[1];
return 0;
}
cdk_error_t
_cdk_copy_signature (cdk_pkt_signature_t * dst, cdk_pkt_signature_t src)
{
cdk_pkt_signature_t s;
if (!dst || !src)
return CDK_Inv_Value;
*dst = NULL;
s = cdk_calloc (1, sizeof *s);
if (!s)
return CDK_Out_Of_Core;
memcpy (s, src, sizeof *src);
_cdk_subpkt_copy (&s->hashed, src->hashed);
_cdk_subpkt_copy (&s->unhashed, src->unhashed);
/* FIXME: Copy MPI parts */
*dst = s;
return 0;
}
cdk_error_t
_cdk_pubkey_compare (cdk_pkt_pubkey_t a, cdk_pkt_pubkey_t b)
{
int na, nb, i;
if (a->timestamp != b->timestamp || a->pubkey_algo != b->pubkey_algo)
return -1;
if (a->version < 4 && a->expiredate != b->expiredate)
return -1;
na = cdk_pk_get_npkey (a->pubkey_algo);
nb = cdk_pk_get_npkey (b->pubkey_algo);
if (na != nb)
return -1;
for (i = 0; i < na; i++)
{
if (gcry_mpi_cmp (a->mpi[i], b->mpi[i]))
return -1;
}
return 0;
}
/**
* cdk_subpkt_free:
* @ctx: the sub packet node to free
*
* Release the context.
**/
void
cdk_subpkt_free (cdk_subpkt_t ctx)
{
cdk_subpkt_t s;
while (ctx)
{
s = ctx->next;
cdk_free (ctx);
ctx = s;
}
}
/**
* cdk_subpkt_find:
* @ctx: the sub packet node
* @type: the packet type to find
*
* Find the given packet type in the node. If no packet with this
* type was found, return null otherwise pointer to the node.
**/
cdk_subpkt_t
cdk_subpkt_find (cdk_subpkt_t ctx, size_t type)
{
return cdk_subpkt_find_nth (ctx, type, 0);
}
/**
* cdk_subpkt_type_count:
* @ctx: The sub packet context
* @type: The sub packet type.
*
* Return the amount of sub packets with this type.
**/
size_t
cdk_subpkt_type_count (cdk_subpkt_t ctx, size_t type)
{
cdk_subpkt_t s;
size_t count;
count = 0;
for (s = ctx; s; s = s->next)
{
if (s->type == type)
count++;
}
return count;
}
/**
* cdk_subpkt_find_nth:
* @ctx: The sub packet context
* @type: The sub packet type
* @index: The nth packet to retrieve, 0 means the first
*
* Return the nth sub packet of the given type.
**/
cdk_subpkt_t
cdk_subpkt_find_nth (cdk_subpkt_t ctx, size_t type, size_t idx)
{
cdk_subpkt_t s;
size_t pos;
pos = 0;
for (s = ctx; s; s = s->next)
{
if (s->type == type && pos++ == idx)
return s;
}
return NULL;
}
/**
* cdk_subpkt_new:
* @size: the size of the new context
*
* Create a new sub packet node with the size of @size.
**/
cdk_subpkt_t
cdk_subpkt_new (size_t size)
{
cdk_subpkt_t s;
if (!size)
return NULL;
s = cdk_calloc (1, sizeof *s + size + 1);
if (!s)
return NULL;
return s;
}
/**
* cdk_subpkt_get_data:
* @ctx: the sub packet node
* @r_type: pointer store the packet type
* @r_nbytes: pointer to store the packet size
*
* Extract the data from the given sub packet. The type is returned
* in @r_type and the size in @r_nbytes.
**/
const byte *
cdk_subpkt_get_data (cdk_subpkt_t ctx, size_t * r_type, size_t * r_nbytes)
{
if (!ctx || !r_nbytes)
return NULL;
if (r_type)
*r_type = ctx->type;
*r_nbytes = ctx->size;
return ctx->d;
}
/**
* cdk_subpkt_add:
* @root: the root node
* @node: the node to add
*
* Add the node in @node to the root node @root.
**/
cdk_error_t
cdk_subpkt_add (cdk_subpkt_t root, cdk_subpkt_t node)
{
cdk_subpkt_t n1;
if (!root)
return CDK_Inv_Value;
for (n1 = root; n1->next; n1 = n1->next)
;
n1->next = node;
return 0;
}
byte *
_cdk_subpkt_get_array (cdk_subpkt_t s, int count, size_t * r_nbytes)
{
cdk_subpkt_t list;
byte *buf;
size_t n, nbytes;
if (!s)
{
if (r_nbytes)
*r_nbytes = 0;
return NULL;
}
for (n = 0, list = s; list; list = list->next)
{
n++; /* type */
n += list->size;
if (list->size < 192)
n++;
else if (list->size < 8384)
n += 2;
else
n += 5;
}
buf = cdk_calloc (1, n + 1);
if (!buf)
return NULL;
n = 0;
for (list = s; list; list = list->next)
{
nbytes = 1 + list->size; /* type */
if (nbytes < 192)
buf[n++] = nbytes;
else if (nbytes < 8384)
{
buf[n++] = nbytes / 256 + 192;
buf[n++] = nbytes % 256;
}
else
{
buf[n++] = 0xFF;
buf[n++] = nbytes >> 24;
buf[n++] = nbytes >> 16;
buf[n++] = nbytes >> 8;
buf[n++] = nbytes;
}
buf[n++] = list->type;
memcpy (buf + n, list->d, list->size);
n += list->size;
}
if (count)
{
cdk_free (buf);
buf = NULL;
}
if (r_nbytes)
*r_nbytes = n;
return buf;
}
cdk_error_t
_cdk_subpkt_copy (cdk_subpkt_t * r_dst, cdk_subpkt_t src)
{
cdk_subpkt_t root, p, node;
if (!src || !r_dst)
return CDK_Inv_Value;
root = NULL;
for (p = src; p; p = p->next)
{
node = cdk_subpkt_new (p->size);
if (node)
{
memcpy (node->d, p->d, p->size);
node->type = p->type;
node->size = p->size;
}
if (!root)
root = node;
else
cdk_subpkt_add (root, node);
}
*r_dst = root;
return 0;
}
/**
* cdk_subpkt_init:
* @node: the sub packet node
* @type: type of the packet which data should be initialized
* @buf: the buffer with the actual data
* @buflen: the size of the data
*
* Set the packet data of the given root and set the type of it.
**/
void
cdk_subpkt_init (cdk_subpkt_t node, size_t type,
const void *buf, size_t buflen)
{
if (!node)
return;
node->type = type;
node->size = buflen;
memcpy (node->d, buf, buflen);
}
/* FIXME: We need to think of a public interface for it. */
const byte *
cdk_key_desig_revoker_walk (cdk_desig_revoker_t root,
cdk_desig_revoker_t * ctx,
int *r_class, int *r_algid)
{
cdk_desig_revoker_t n;
if (!*ctx)
{
*ctx = root;
n = root;
}
else
{
n = (*ctx)->next;
*ctx = n;
}
if (n && r_class && r_algid)
{
*r_class = n->r_class;
*r_algid = n->algid;
}
return n ? n->fpr : NULL;
}
/**
* cdk_subpkt_find_next:
* @root: the base where to begin the iteration
* @type: the type to find or 0 for the next node.
*
* Try to find the next node after @root with type.
* If type is 0, the next node will be returned.
**/
cdk_subpkt_t
cdk_subpkt_find_next (cdk_subpkt_t root, size_t type)
{
cdk_subpkt_t node;
for (node = root->next; node; node = node->next)
{
if (!type)
return node;
else if (node->type == type)
return node;
}
return NULL;
}
-1169
View File
@@ -1,1169 +0,0 @@
/* opencdk.h - Open Crypto Development Kit (OpenCDK)
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef OPENCDK_H
#define OPENCDK_H
#include <stddef.h> /* for size_t */
#include <stdarg.h>
#include <gcrypt.h>
/* The OpenCDK version as a string. */
#define OPENCDK_VERSION "0.6.6"
/* The OpenCDK version as integer components major.minor.path */
#define OPENCDK_VERSION_MAJOR 0
#define OPENCDK_VERSION_MINOR 6
#define OPENCDK_VERSION_PATCH 6
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
/* General contexts */
/* 'Session' handle to support the various options and run-time
information. */
struct cdk_ctx_s;
typedef struct cdk_ctx_s *cdk_ctx_t;
/* A generic context to store list of strings. */
struct cdk_strlist_s;
typedef struct cdk_strlist_s *cdk_strlist_t;
/* Context used to list keys of a keyring. */
struct cdk_listkey_s;
typedef struct cdk_listkey_s *cdk_listkey_t;
/* Opaque Data Encryption Key (DEK) context. */
struct cdk_dek_s;
typedef struct cdk_dek_s *cdk_dek_t;
/* Opaque String to Key (S2K) handle. */
struct cdk_s2k_s;
typedef struct cdk_s2k_s *cdk_s2k_t;
/* Abstract I/O object, a stream, which is used for most operations. */
struct cdk_stream_s;
typedef struct cdk_stream_s *cdk_stream_t;
/* Opaque handle for the user ID preferences. */
struct cdk_prefitem_s;
typedef struct cdk_prefitem_s *cdk_prefitem_t;
/* Node to store a single key node packet. */
struct cdk_kbnode_s;
typedef struct cdk_kbnode_s *cdk_kbnode_t;
/* Key database handle. */
struct cdk_keydb_hd_s;
typedef struct cdk_keydb_hd_s *cdk_keydb_hd_t;
/* Context to store a list of recipient keys. */
struct cdk_keylist_s;
typedef struct cdk_keylist_s *cdk_keylist_t;
/* Context to encapsulate a single sub packet of a signature. */
struct cdk_subpkt_s;
typedef struct cdk_subpkt_s *cdk_subpkt_t;
/* Context used to generate key pairs. */
struct cdk_keygen_ctx_s;
typedef struct cdk_keygen_ctx_s *cdk_keygen_ctx_t;
/* Handle for a single designated revoker. */
struct cdk_desig_revoker_s;
typedef struct cdk_desig_revoker_s *cdk_desig_revoker_t;
/* Alias for backward compatibility. */
typedef gcry_mpi_t cdk_mpi_t;
/* All valid error constants. */
typedef enum {
CDK_EOF = -1,
CDK_Success = 0,
CDK_General_Error = 1,
CDK_File_Error = 2,
CDK_Bad_Sig = 3,
CDK_Inv_Packet = 4,
CDK_Inv_Algo = 5,
CDK_Not_Implemented = 6,
CDK_Armor_Error = 8,
CDK_Armor_CRC_Error = 9,
CDK_MPI_Error = 10,
CDK_Inv_Value = 11,
CDK_Error_No_Key = 12,
CDK_Chksum_Error = 13,
CDK_Time_Conflict = 14,
CDK_Zlib_Error = 15,
CDK_Weak_Key = 16,
CDK_Out_Of_Core = 17,
CDK_Wrong_Seckey = 18,
CDK_Bad_MDC = 19,
CDK_Inv_Mode = 20,
CDK_Error_No_Keyring = 21,
CDK_Wrong_Format = 22,
CDK_Inv_Packet_Ver = 23,
CDK_Too_Short = 24,
CDK_Unusable_Key = 25,
CDK_No_Data = 26,
CDK_No_Passphrase = 27,
CDK_Network_Error = 28
} cdk_error_t;
enum cdk_control_flags {
CDK_CTLF_SET = 0, /* Value to set an option */
CDK_CTLF_GET = 1, /* Value to get an option */
CDK_CTL_DIGEST = 10, /* Option to set the digest algorithm. */
CDK_CTL_CIPHER = 11, /* Option to set the cipher algorithm. */
CDK_CTL_ARMOR = 12, /* Option to enable armor output. */
CDK_CTL_COMPRESS = 13, /* Option to enable compression. */
CDK_CTL_COMPAT = 14, /* Option to switch in compat mode. */
CDK_CTL_OVERWRITE = 15, /* Option to enable file overwritting. */
CDK_CTL_S2K = 16, /* Option to set S2K values. */
CDK_CTL_FORCE_DIGEST = 19, /* Force the use of a digest algorithm. */
CDK_CTL_BLOCKMODE_ON = 20 /* Enable partial body lengths */
};
/* Specifies all valid log levels. */
enum cdk_log_level_t {
CDK_LOG_NONE = 0, /* No log message will be shown. */
CDK_LOG_INFO = 1,
CDK_LOG_DEBUG = 2,
CDK_LOG_DEBUG_PKT = 3
};
/* All valid compression algorithms in OpenPGP */
enum cdk_compress_algo_t {
CDK_COMPRESS_NONE = 0,
CDK_COMPRESS_ZIP = 1,
CDK_COMPRESS_ZLIB = 2,
CDK_COMPRESS_BZIP2 = 3 /* Not supported in this version */
};
/* All valid public key algorithms valid in OpenPGP */
enum cdk_pubkey_algo_t {
CDK_PK_RSA = 1,
CDK_PK_RSA_E = 2, /* RSA-E and RSA-S are deprecated use RSA instead */
CDK_PK_RSA_S = 3, /* and use the key flags in the self signatures. */
CDK_PK_ELG_E = 16,
CDK_PK_DSA = 17
};
/* All valid message digest algorithms in OpenPGP. */
enum cdk_digest_algo_t {
CDK_MD_NONE = 0,
CDK_MD_MD5 = 1,
CDK_MD_SHA1 = 2,
CDK_MD_RMD160 = 3,
CDK_MD_SHA256 = 8,
CDK_MD_SHA384 = 9,
CDK_MD_SHA512 = 10,
CDK_MD_SHA224 = 11 /* This algorithm is NOT available. */
};
/* All valid symmetric cipher algorithms in OpenPGP */
enum cdk_cipher_algo_t {
CDK_CIPHER_NONE = 0,
CDK_CIPHER_IDEA = 1, /* This algorithm is NOT available */
CDK_CIPHER_3DES = 2,
CDK_CIPHER_CAST5 = 3,
CDK_CIPHER_BLOWFISH = 4,
CDK_CIPHER_AES = 7,
CDK_CIPHER_AES192 = 8,
CDK_CIPHER_AES256 = 9,
CDK_CIPHER_TWOFISH = 10
};
/* The valid 'String-To-Key' modes */
enum cdk_s2k_type_t {
CDK_S2K_SIMPLE = 0,
CDK_S2K_SALTED = 1,
CDK_S2K_ITERSALTED = 3
};
/* The different kind of user ID preferences. */
enum cdk_pref_type_t {
CDK_PREFTYPE_NONE = 0,
CDK_PREFTYPE_SYM = 1, /* Symmetric ciphers */
CDK_PREFTYPE_HASH = 2, /* Message digests */
CDK_PREFTYPE_ZIP = 3 /* Compression algorithms */
};
/* All valid sub packet types. */
enum cdk_sig_subpacket_t {
CDK_SIGSUBPKT_NONE = 0,
CDK_SIGSUBPKT_SIG_CREATED = 2,
CDK_SIGSUBPKT_SIG_EXPIRE = 3,
CDK_SIGSUBPKT_EXPORTABLE = 4,
CDK_SIGSUBPKT_TRUST = 5,
CDK_SIGSUBPKT_REGEXP = 6,
CDK_SIGSUBPKT_REVOCABLE = 7,
CDK_SIGSUBPKT_KEY_EXPIRE = 9,
CDK_SIGSUBPKT_PREFS_SYM = 11,
CDK_SIGSUBPKT_REV_KEY = 12,
CDK_SIGSUBPKT_ISSUER = 16,
CDK_SIGSUBPKT_NOTATION = 20,
CDK_SIGSUBPKT_PREFS_HASH = 21,
CDK_SIGSUBPKT_PREFS_ZIP = 22,
CDK_SIGSUBPKT_KS_FLAGS = 23,
CDK_SIGSUBPKT_PREF_KS = 24,
CDK_SIGSUBPKT_PRIMARY_UID = 25,
CDK_SIGSUBPKT_POLICY = 26,
CDK_SIGSUBPKT_KEY_FLAGS = 27,
CDK_SIGSUBPKT_SIGNERS_UID = 28,
CDK_SIGSUBPKT_REVOC_REASON = 29,
CDK_SIGSUBPKT_FEATURES = 30
};
/* All valid armor types. */
enum cdk_armor_type_t {
CDK_ARMOR_MESSAGE = 0,
CDK_ARMOR_PUBKEY = 1,
CDK_ARMOR_SECKEY = 2,
CDK_ARMOR_SIGNATURE = 3,
CDK_ARMOR_CLEARSIG = 4
};
enum cdk_keydb_flag_t {
/* Valid database search modes */
CDK_DBSEARCH_EXACT = 1, /* Exact string search */
CDK_DBSEARCH_SUBSTR = 2, /* Sub string search */
CDK_DBSEARCH_SHORT_KEYID = 3, /* 32-bit keyid search */
CDK_DBSEARCH_KEYID = 4, /* 64-bit keyid search */
CDK_DBSEARCH_FPR = 5, /* 160-bit fingerprint search */
CDK_DBSEARCH_NEXT = 6, /* Enumerate all keys */
CDK_DBSEARCH_AUTO = 7, /* Try to classify the string */
/* Valid database types */
CDK_DBTYPE_PK_KEYRING = 100, /* A file with one or more public keys */
CDK_DBTYPE_SK_KEYRING = 101, /* A file with one or more secret keys */
CDK_DBTYPE_DATA = 102, /* A buffer with at least one public key */
CDK_DBTYPE_STREAM = 103 /* A stream is used to read keys from */
};
/* All valid modes for cdk_data_transform() */
enum cdk_crypto_mode_t {
CDK_CRYPTYPE_NONE = 0,
CDK_CRYPTYPE_ENCRYPT = 1,
CDK_CRYPTYPE_DECRYPT = 2,
CDK_CRYPTYPE_SIGN = 3,
CDK_CRYPTYPE_VERIFY = 4,
CDK_CRYPTYPE_EXPORT = 5,
CDK_CRYPTYPE_IMPORT = 6
};
/* A list of valid public key usages. */
enum cdk_key_usage_t {
CDK_KEY_USG_ENCR = 1, /* Key can be used for encryption. */
CDK_KEY_USG_SIGN = 2, /* Key can be used for signing and certifying. */
CDK_KEY_USG_AUTH = 4 /* Key can be used for authentication. */
};
/* Valid flags for keys. */
enum cdk_key_flag_t {
CDK_KEY_VALID = 0,
CDK_KEY_INVALID = 1, /* Missing or wrong self signature */
CDK_KEY_EXPIRED = 2, /* Key is expired. */
CDK_KEY_REVOKED = 4, /* Key has been revoked. */
CDK_KEY_NOSIGNER = 8
};
/* Trust values and flags for keys and user IDs */
enum cdk_trust_flag_t {
CDK_TRUST_UNKNOWN = 0,
CDK_TRUST_EXPIRED = 1,
CDK_TRUST_UNDEFINED = 2,
CDK_TRUST_NEVER = 3,
CDK_TRUST_MARGINAL = 4,
CDK_TRUST_FULLY = 5,
CDK_TRUST_ULTIMATE = 6,
/* trust flags */
CDK_TFLAG_REVOKED = 32,
CDK_TFLAG_SUB_REVOKED = 64,
CDK_TFLAG_DISABLED = 128
};
/* Signature states and the signature modes. */
enum cdk_signature_stat_t {
/* Signature status */
CDK_SIGSTAT_NONE = 0,
CDK_SIGSTAT_GOOD = 1,
CDK_SIGSTAT_BAD = 2,
CDK_SIGSTAT_NOKEY = 3,
CDK_SIGSTAT_VALID = 4, /* True if made with a valid key. */
/* FIXME: We need indicators for revoked/expires signatures. */
/* Signature modes */
CDK_SIGMODE_NORMAL = 100,
CDK_SIGMODE_DETACHED = 101,
CDK_SIGMODE_CLEAR = 102
};
/* Key flags. */
typedef enum {
CDK_FLAG_KEY_REVOKED = 256,
CDK_FLAG_KEY_EXPIRED = 512,
CDK_FLAG_SIG_EXPIRED = 1024
} cdk_key_flags_t;
/* Possible format for the literal data. */
typedef enum {
CDK_LITFMT_BINARY = 0,
CDK_LITFMT_TEXT = 1,
CDK_LITFMT_UNICODE= 2
} cdk_lit_format_t;
/* Valid OpenPGP packet types and their IDs */
typedef enum {
CDK_PKT_RESERVED = 0,
CDK_PKT_PUBKEY_ENC = 1,
CDK_PKT_SIGNATURE = 2,
CDK_PKT_SYMKEY_ENC = 3,
CDK_PKT_ONEPASS_SIG = 4,
CDK_PKT_SECRET_KEY = 5,
CDK_PKT_PUBLIC_KEY = 6,
CDK_PKT_SECRET_SUBKEY = 7,
CDK_PKT_COMPRESSED = 8,
CDK_PKT_ENCRYPTED = 9,
CDK_PKT_MARKER = 10,
CDK_PKT_LITERAL = 11,
CDK_PKT_RING_TRUST = 12,
CDK_PKT_USER_ID = 13,
CDK_PKT_PUBLIC_SUBKEY = 14,
CDK_PKT_OLD_COMMENT = 16,
CDK_PKT_ATTRIBUTE = 17,
CDK_PKT_ENCRYPTED_MDC = 18,
CDK_PKT_MDC = 19
} cdk_packet_type_t;
/* Define the maximal number of multiprecion integers for
a public key. */
#define MAX_CDK_PK_PARTS 4
/* Define the maximal number of multiprecision integers for
a signature/encrypted blob issued by a secret key. */
#define MAX_CDK_DATA_PARTS 2
/* Helper macro to figure out if the packet is encrypted */
#define CDK_PKT_IS_ENCRYPTED(pkttype) (\
((pkttype)==CDK_PKT_ENCRYPTED_MDC) \
|| ((pkttype)==CDK_PKT_ENCRYPTED))
struct cdk_pkt_signature_s {
unsigned char version;
unsigned char sig_class;
unsigned int timestamp;
unsigned int expiredate;
unsigned int keyid[2];
unsigned char pubkey_algo;
unsigned char digest_algo;
unsigned char digest_start[2];
unsigned short hashed_size;
cdk_subpkt_t hashed;
unsigned short unhashed_size;
cdk_subpkt_t unhashed;
gcry_mpi_t mpi[MAX_CDK_DATA_PARTS];
cdk_desig_revoker_t revkeys;
struct {
unsigned exportable:1;
unsigned revocable:1;
unsigned policy_url:1;
unsigned notation:1;
unsigned expired:1;
unsigned checked:1;
unsigned valid:1;
unsigned missing_key:1;
} flags;
unsigned int key[2]; /* only valid for key signatures */
};
typedef struct cdk_pkt_signature_s *cdk_pkt_signature_t;
struct cdk_pkt_userid_s {
unsigned int len;
unsigned is_primary:1;
unsigned is_revoked:1;
unsigned mdc_feature:1;
cdk_prefitem_t prefs;
size_t prefs_size;
unsigned char * attrib_img; /* Tag 17 if not null */
size_t attrib_len;
cdk_pkt_signature_t selfsig;
char name[1];
};
typedef struct cdk_pkt_userid_s *cdk_pkt_userid_t;
struct cdk_pkt_pubkey_s {
unsigned char version;
unsigned char pubkey_algo;
unsigned char fpr[20];
unsigned int keyid[2];
unsigned int main_keyid[2];
unsigned int timestamp;
unsigned int expiredate;
gcry_mpi_t mpi[MAX_CDK_PK_PARTS];
unsigned is_revoked:1;
unsigned is_invalid:1;
unsigned has_expired:1;
int pubkey_usage;
cdk_pkt_userid_t uid;
cdk_prefitem_t prefs;
size_t prefs_size;
cdk_desig_revoker_t revkeys;
};
typedef struct cdk_pkt_pubkey_s *cdk_pkt_pubkey_t;
/* Alias to define a generic public key context. */
typedef cdk_pkt_pubkey_t cdk_pubkey_t;
struct cdk_pkt_seckey_s {
cdk_pkt_pubkey_t pk;
unsigned int expiredate;
int version;
int pubkey_algo;
unsigned int keyid[2];
unsigned int main_keyid[2];
unsigned char s2k_usage;
struct {
unsigned char algo;
unsigned char sha1chk; /* SHA1 is used instead of a 16 bit checksum */
cdk_s2k_t s2k;
unsigned char iv[16];
unsigned char ivlen;
} protect;
unsigned short csum;
gcry_mpi_t mpi[MAX_CDK_PK_PARTS];
unsigned char * encdata;
size_t enclen;
unsigned char is_protected;
unsigned is_primary:1;
unsigned has_expired:1;
unsigned is_revoked:1;
};
typedef struct cdk_pkt_seckey_s *cdk_pkt_seckey_t;
/* Alias to define a generic secret key context. */
typedef cdk_pkt_seckey_t cdk_seckey_t;
struct cdk_pkt_onepass_sig_s {
unsigned char version;
unsigned int keyid[2];
unsigned char sig_class;
unsigned char digest_algo;
unsigned char pubkey_algo;
unsigned char last;
};
typedef struct cdk_pkt_onepass_sig_s * cdk_pkt_onepass_sig_t;
struct cdk_pkt_pubkey_enc_s {
unsigned char version;
unsigned int keyid[2];
int throw_keyid;
unsigned char pubkey_algo;
gcry_mpi_t mpi[MAX_CDK_DATA_PARTS];
};
typedef struct cdk_pkt_pubkey_enc_s * cdk_pkt_pubkey_enc_t;
struct cdk_pkt_symkey_enc_s {
unsigned char version;
unsigned char cipher_algo;
cdk_s2k_t s2k;
unsigned char seskeylen;
unsigned char seskey[32];
};
typedef struct cdk_pkt_symkey_enc_s *cdk_pkt_symkey_enc_t;
struct cdk_pkt_encrypted_s {
unsigned int len;
int extralen;
unsigned char mdc_method;
cdk_stream_t buf;
};
typedef struct cdk_pkt_encrypted_s *cdk_pkt_encrypted_t;
struct cdk_pkt_mdc_s {
unsigned char hash[20];
};
typedef struct cdk_pkt_mdc_s *cdk_pkt_mdc_t;
struct cdk_pkt_literal_s {
unsigned int len;
cdk_stream_t buf;
int mode;
unsigned int timestamp;
int namelen;
char name[1];
};
typedef struct cdk_pkt_literal_s *cdk_pkt_literal_t;
struct cdk_pkt_compressed_s {
unsigned int len;
int algorithm;
cdk_stream_t buf;
};
typedef struct cdk_pkt_compressed_s *cdk_pkt_compressed_t;
/* Structure which represents a single OpenPGP packet. */
struct cdk_packet_s {
size_t pktlen; /* real packet length */
size_t pktsize; /* length with all headers */
int old_ctb; /* 1 if RFC1991 mode is used */
cdk_packet_type_t pkttype;
union {
cdk_pkt_mdc_t mdc;
cdk_pkt_userid_t user_id;
cdk_pkt_pubkey_t public_key;
cdk_pkt_seckey_t secret_key;
cdk_pkt_signature_t signature;
cdk_pkt_pubkey_enc_t pubkey_enc;
cdk_pkt_symkey_enc_t symkey_enc;
cdk_pkt_compressed_t compressed;
cdk_pkt_encrypted_t encrypted;
cdk_pkt_literal_t literal;
cdk_pkt_onepass_sig_t onepass_sig;
} pkt;
};
typedef struct cdk_packet_s *cdk_packet_t;
/* memory routines */
typedef void (*cdk_log_fnc_t) (void *, int, const char *, va_list);
/* Set the log level. */
void cdk_set_log_level (int lvl);
/* Set a custom log handler which is used for logging. */
void cdk_set_log_handler (cdk_log_fnc_t logfnc, void *opaque);
/* Return a human readable error description of the given error coe. */
const char* cdk_strerror (int ec);
/* Allow the user to set custom hooks for memory allocation.
If this function is not used, the standard allocation functions
will be used. Extra care must be taken for the 'secure' alloc
function. */
void cdk_set_malloc_hooks (void *(*new_alloc_func) (size_t n),
void *(*new_alloc_secure_func) (size_t n),
void *(*new_realloc_func) (void *p, size_t n),
void *(*new_calloc_func) (size_t m, size_t n),
void (*new_free_func) (void *));
/* Return 1 if the malloc hooks were already set via the function above. */
int cdk_malloc_hook_initialized (void);
/* Standard memory wrapper. */
void *cdk_malloc (size_t size);
void *cdk_calloc (size_t n, size_t m);
void *cdk_realloc (void * ptr, size_t size);
void *cdk_salloc (size_t size, int clear);
char *cdk_strdup (const char * ptr);
void cdk_free (void * ptr);
/* Startup routines. */
/* This function has to be called before any other
CDK function is executed. */
void cdk_lib_startup (void);
/* This function should be called before the application exists
to allow the lib to cleanup its internal structures. */
void cdk_lib_shutdown (void);
/* Session handle routines */
cdk_error_t cdk_handle_new (cdk_ctx_t *r_ctx);
void cdk_handle_free (cdk_ctx_t c);
/* Set the key database handle for the given session handle.
The type of the key db handle (public or secret) decides
which session key db handle to use. */
void cdk_handle_set_keydb (cdk_ctx_t hd, cdk_keydb_hd_t db);
/* Convenient function to avoid to open a key db first.
The user can directly use the file name, the rest is
done internally. */
cdk_error_t cdk_handle_set_keyring (cdk_ctx_t hd, int type,
const char *kringname);
/* Return keydb handle stored in the session handle. */
cdk_keydb_hd_t cdk_handle_get_keydb (cdk_ctx_t hd, int type);
int cdk_handle_control (cdk_ctx_t hd, int action, int cmd, ...);
/* Set a passphrase callback for the given session handle. */
void cdk_handle_set_passphrase_cb (cdk_ctx_t hd,
char *(*cb) (void *opa, const char *prompt),
void *cb_value);
/* shortcuts for some controls */
/* Enable or disable armor output. */
#define cdk_handle_set_armor(a, val) \
cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_ARMOR, (val))
/* Set the compression algorithm and level. 0 means disable compression. */
#define cdk_handle_set_compress(a, algo, level) \
cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_COMPRESS, (algo), (level))
/* Activate partial bodies for the output. This is needed if the length
of the data is not known in advance or for the use with sockets
or pipes. */
#define cdk_handle_set_blockmode(a, val) \
cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_BLOCKMODE_ON, (val))
/* Set the symmetric cipher for encryption. */
#define cdk_handle_set_cipher(a, val) \
cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_CIPHER, (val))
/* Set the digest for the PK signing operation. */
#define cdk_handle_set_digest(a, val) \
cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_DIGEST, (val))
/* Set the mode and the digest for the S2K operation. */
#define cdk_handle_set_s2k(a, val1, val2) \
cdk_handle_control ((a), CDK_CTLF_SET, CDK_CTL_S2K, (val1), (val2))
/* This context holds all information of the verification process. */
struct cdk_verify_result_s {
int sig_ver; /* Version of the signature. */
int sig_status; /* The status (GOOD, BAD) of the signature */
int sig_flags; /* May contain expired or revoked flags */
unsigned int keyid[2]; /* The issuer key ID */
unsigned int created; /* Timestamp when the sig was created. */
unsigned int expires;
int pubkey_algo;
int digest_algo;
char *user_id; /* NULL or user ID which issued the signature. */
char *policy_url; /* If set, the policy the sig was created under. */
size_t sig_len; /* Size of the signature data inbits. */
unsigned char *sig_data; /* Raw signature data. */
};
typedef struct cdk_verify_result_s *cdk_verify_result_t;
/* Return the verify result. Do not free the data. */
cdk_verify_result_t cdk_handle_verify_get_result (cdk_ctx_t hd);
/* Raw packet routines. */
/* Allocate a new packet or a new packet with the given packet type. */
cdk_error_t cdk_pkt_new (cdk_packet_t *r_pkt);
cdk_error_t cdk_pkt_alloc (cdk_packet_t *r_pkt, int pkttype);
/* Only release the contents of the packet but not @PKT itself. */
void cdk_pkt_free (cdk_packet_t pkt);
/* Release the packet contents and the packet structure @PKT itself. */
void cdk_pkt_release (cdk_packet_t pkt);
/* Read or write the given output from or to the stream. */
cdk_error_t cdk_pkt_read (cdk_stream_t inp, cdk_packet_t pkt);
cdk_error_t cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt);
/* Sub packet routines */
cdk_subpkt_t cdk_subpkt_new (size_t size);
void cdk_subpkt_free (cdk_subpkt_t ctx);
cdk_subpkt_t cdk_subpkt_find (cdk_subpkt_t ctx, size_t type);
cdk_subpkt_t cdk_subpkt_find_next (cdk_subpkt_t root, size_t type);
size_t cdk_subpkt_type_count (cdk_subpkt_t ctx, size_t type);
cdk_subpkt_t cdk_subpkt_find_nth (cdk_subpkt_t ctx, size_t type, size_t index);
cdk_error_t cdk_subpkt_add (cdk_subpkt_t root, cdk_subpkt_t node);
const unsigned char * cdk_subpkt_get_data (cdk_subpkt_t ctx,
size_t * r_type, size_t *r_nbytes);
void cdk_subpkt_init (cdk_subpkt_t node, size_t type,
const void *buf, size_t buflen);
/* Designated Revoker routines */
const unsigned char* cdk_key_desig_revoker_walk (cdk_desig_revoker_t root,
cdk_desig_revoker_t * ctx,
int *r_class, int *r_algid);
#define is_RSA(a) ((a) == CDK_PK_RSA \
|| (a) == CDK_PK_RSA_E \
|| (a) == CDK_PK_RSA_S)
#define is_ELG(a) ((a) == CDK_PK_ELG_E)
#define is_DSA(a) ((a) == CDK_PK_DSA)
/* Encrypt the given session key @SK with the public key @PK
and write the contents into the packet @PKE. */
cdk_error_t cdk_pk_encrypt (cdk_pubkey_t pk, cdk_pkt_pubkey_enc_t pke,
gcry_mpi_t sk);
/* Decrypt the given encrypted session key in @PKE with the secret key
@SK and store it in @R_SK. */
cdk_error_t cdk_pk_decrypt (cdk_seckey_t sk, cdk_pkt_pubkey_enc_t pke,
gcry_mpi_t *r_sk);
/* Sign the given message digest @MD with the secret key @SK and
store the signature in the packet @SIG. */
cdk_error_t cdk_pk_sign (cdk_seckey_t sk, cdk_pkt_signature_t sig,
const unsigned char *md);
/* Verify the given signature in @SIG with the public key @PK
and compare it against the message digest @MD. */
cdk_error_t cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
const unsigned char *md);
/* Use cdk_pk_get_npkey() and cdk_pk_get_nskey to find out how much
multiprecision integers a key consists of. */
/* Return a multi precision integer of the public key with the index @IDX
in the buffer @BUF. @R_NWRITTEN will contain the length in octets.
Optional @R_NBITS may contain the size in bits. */
cdk_error_t cdk_pk_get_mpi (cdk_pubkey_t pk, size_t idx,
unsigned char *buf, size_t buflen,
size_t *r_nwritten, size_t *r_nbits);
/* Same as the function above but of the secret key. */
cdk_error_t cdk_sk_get_mpi (cdk_seckey_t sk, size_t idx,
unsigned char * buf, size_t buflen,
size_t *r_nwritten, size_t *r_nbits);
/* Helper to get the exact number of multi precision integers
for the given object. */
int cdk_pk_get_nbits (cdk_pubkey_t pk);
int cdk_pk_get_npkey (int algo);
int cdk_pk_get_nskey (int algo);
int cdk_pk_get_nsig (int algo);
int cdk_pk_get_nenc (int algo);
/* Fingerprint and key ID routines. */
/* Calculate the fingerprint of the given public key.
the FPR parameter must be at least 20 octets to hold the SHA1 hash. */
cdk_error_t cdk_pk_get_fingerprint (cdk_pubkey_t pk, unsigned char *fpr);
/* Same as above, but with additional sanity checks of the buffer size. */
cdk_error_t cdk_pk_to_fingerprint (cdk_pubkey_t pk,
unsigned char *fpr, size_t fprlen,
size_t *r_nout);
/* Derive the keyid from the fingerprint. This is only possible for
modern, version 4 keys. */
unsigned int cdk_pk_fingerprint_get_keyid (const unsigned char *fpr,
size_t fprlen,
unsigned int *keyid);
/* Various functions to get the keyid from the specific packet type. */
unsigned int cdk_pk_get_keyid (cdk_pubkey_t pk, unsigned int *keyid);
unsigned int cdk_sk_get_keyid (cdk_seckey_t sk, unsigned int *keyid);
unsigned int cdk_sig_get_keyid (cdk_pkt_signature_t sig,
unsigned int *keyid);
/* Key release functions. */
void cdk_pk_release (cdk_pubkey_t pk);
void cdk_sk_release (cdk_seckey_t sk);
/* Secret key related functions. */
cdk_error_t cdk_sk_unprotect (cdk_seckey_t sk, const char *pw);
cdk_error_t cdk_sk_protect (cdk_seckey_t sk, const char *pw);
/* Create a public key with the data from the secret key @SK. */
cdk_error_t cdk_pk_from_secret_key (cdk_seckey_t sk,
cdk_pubkey_t *ret_pk);
/* Sexp conversion of keys. */
cdk_error_t cdk_pubkey_to_sexp (cdk_pubkey_t pk,
char **sexp, size_t *len);
cdk_error_t cdk_seckey_to_sexp (cdk_seckey_t sk,
char **sexp, size_t *len);
/* Data Encryption Key (DEK) routines */
cdk_error_t cdk_dek_new (cdk_dek_t *r_dek);
void cdk_dek_free (cdk_dek_t dek);
/* Set the symmetric cipher algorithm which shall be used for this
DEK object. */
cdk_error_t cdk_dek_set_cipher (cdk_dek_t dek, int cipher_algo);
/* Return the symmetric cipher which is used for this DEK object. */
cdk_error_t cdk_dek_get_cipher (cdk_dek_t dek, int *r_cipher_algo);
/* Set the session key for the given DEK object.
If @KEY and @KEYLEN are both NULL/0, a random key will be generated
and stored in the DEK object. */
cdk_error_t cdk_dek_set_key (cdk_dek_t dek, const unsigned char *key,
size_t keylen);
/* Enable the MDC feature for the current DEK object. */
void cdk_dek_set_mdc_flag (cdk_dek_t dek, int val);
/* Return if the MDC feature is enabled for the current DEK object.*/
int cdk_dek_get_mdc_flag (cdk_dek_t dek);
/* Transform the given passphrase into a DEK.
If @rndsalt is set, a random salt will be generated. */
cdk_error_t cdk_dek_from_passphrase (cdk_dek_t *ret_dek, int cipher_algo,
cdk_s2k_t s2k, int rndsalt,
const char *passphrase);
/* String to Key routines. */
cdk_error_t cdk_s2k_new (cdk_s2k_t *ret_s2k, int mode, int digest_algo,
const unsigned char *salt);
void cdk_s2k_free (cdk_s2k_t s2k);
cdk_error_t cdk_file_armor (cdk_ctx_t hd, const char *file,
const char *output);
cdk_error_t cdk_file_dearmor (const char * file, const char *output);
int cdk_armor_filter_use (cdk_stream_t inp);
/* Protect the inbuf with ASCII armor of the specified type.
If @outbuf and @outlen are NULL, the function returns the calculated
size of the base64 encoded data in @nwritten. */
cdk_error_t cdk_armor_encode_buffer (const unsigned char *inbuf, size_t inlen,
char *outbuf, size_t outlen,
size_t *nwritten, int type);
/* This context contain user callbacks for different stream operations.
Some of these callbacks might be NULL to indicate that the callback
is not used. */
struct cdk_stream_cbs_s
{
cdk_error_t (*open)(void *);
cdk_error_t (*release)(void *);
int (*read)(void *, void *buf, size_t);
int (*write)(void *, const void *buf, size_t);
int (*seek)(void *, off_t);
};
typedef struct cdk_stream_cbs_s *cdk_stream_cbs_t;
int cdk_stream_is_compressed (cdk_stream_t s);
/* Return a stream object which is associated to a socket. */
cdk_error_t cdk_stream_sockopen (const char *host, unsigned short port,
cdk_stream_t *ret_out);
/* Return a stream object which is associated to an existing file. */
cdk_error_t cdk_stream_open (const char * file, cdk_stream_t * ret_s);
/* Return a stream object which is associated to a file which will
be created when the stream is closed. */
cdk_error_t cdk_stream_new (const char * file, cdk_stream_t * ret_s);
/* Return a stream object with custom callback functions for the
various core operations. */
cdk_error_t cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa,
cdk_stream_t *ret_s);
cdk_error_t cdk_stream_create (const char * file, cdk_stream_t * ret_s);
cdk_error_t cdk_stream_tmp_new (cdk_stream_t *r_out);
cdk_error_t cdk_stream_tmp_from_mem (const void * buf, size_t buflen,
cdk_stream_t *r_out);
void cdk_stream_tmp_set_mode (cdk_stream_t s, int val);
cdk_error_t cdk_stream_flush (cdk_stream_t s);
cdk_error_t cdk_stream_enable_cache (cdk_stream_t s, int val);
cdk_error_t cdk_stream_filter_disable (cdk_stream_t s, int type);
cdk_error_t cdk_stream_close (cdk_stream_t s);
off_t cdk_stream_get_length (cdk_stream_t s);
int cdk_stream_read (cdk_stream_t s, void * buf, size_t count);
int cdk_stream_write (cdk_stream_t s, const void * buf, size_t count);
int cdk_stream_putc (cdk_stream_t s, int c);
int cdk_stream_getc (cdk_stream_t s);
int cdk_stream_eof (cdk_stream_t s);
off_t cdk_stream_tell (cdk_stream_t s);
cdk_error_t cdk_stream_seek (cdk_stream_t s, off_t offset);
cdk_error_t cdk_stream_set_armor_flag (cdk_stream_t s, int type);
/* Push the literal filter for the given stream. */
cdk_error_t cdk_stream_set_literal_flag (cdk_stream_t s,
cdk_lit_format_t mode,
const char * fname);
cdk_error_t cdk_stream_set_cipher_flag (cdk_stream_t s, cdk_dek_t dek,
int use_mdc);
cdk_error_t cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level);
cdk_error_t cdk_stream_set_hash_flag (cdk_stream_t s, int algo);
cdk_error_t cdk_stream_set_text_flag (cdk_stream_t s, const char * lf);
cdk_error_t cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out);
cdk_error_t cdk_stream_mmap (cdk_stream_t s, unsigned char **ret_buf,
size_t *ret_buflen);
cdk_error_t cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len,
unsigned char **ret_buf, size_t *ret_buflen);
/* Read from the stream but restore the file pointer after reading
the requested amount of bytes. */
int cdk_stream_peek (cdk_stream_t inp, unsigned char *buf, size_t buflen);
/* A wrapper around the various new_from_XXX functions. Because
the function does not support all combinations, the dedicated
functions should be preferred. */
cdk_error_t cdk_keydb_new (cdk_keydb_hd_t *r_hd, int type, void *data,
size_t count);
/* Create a new key db handle from a memory buffer. */
cdk_error_t cdk_keydb_new_from_mem (cdk_keydb_hd_t *r_hd, int secret,
const void *data, size_t datlen);
/* Create a new key db which uses an existing file. */
cdk_error_t cdk_keydb_new_from_file (cdk_keydb_hd_t *r_hd, int secret,
const char *fname);
/* Uses a stream as the key db input. For searching it is important
that the seek function is supported on the stream. Furthermore,
the stream is not closed in cdk_keydb_free(). The caller must do it. */
cdk_error_t cdk_keydb_new_from_stream (cdk_keydb_hd_t *r_hd, int secret,
cdk_stream_t in);
/* Check that a secret key with the given key ID is available. */
cdk_error_t cdk_keydb_check_sk (cdk_keydb_hd_t hd, unsigned int *keyid);
/* Prepare the key db search. */
cdk_error_t cdk_keydb_search_start (cdk_keydb_hd_t hd, int type, void *desc);
/* Return a key which matches a valid description given in
cdk_keydb_search_start(). */
cdk_error_t cdk_keydb_search (cdk_keydb_hd_t hd, cdk_kbnode_t *ret_key);
/* Release the key db handle and all its resources. */
void cdk_keydb_free (cdk_keydb_hd_t hd);
/* The following functions will try to find a key in the given key
db handle either by keyid, by fingerprint or by some pattern. */
cdk_error_t cdk_keydb_get_bykeyid (cdk_keydb_hd_t hd, unsigned int *keyid,
cdk_kbnode_t *ret_pk);
cdk_error_t cdk_keydb_get_byfpr (cdk_keydb_hd_t hd, const unsigned char *fpr,
cdk_kbnode_t *ret_pk);
cdk_error_t cdk_keydb_get_bypattern (cdk_keydb_hd_t hd, const char *patt,
cdk_kbnode_t *ret_pk);
/* These function, in contrast to most other key db functions, only
return the public or secret key packet without the additional
signatures and user IDs. */
cdk_error_t cdk_keydb_get_pk (cdk_keydb_hd_t khd, unsigned int * keyid,
cdk_pubkey_t *ret_pk);
cdk_error_t cdk_keydb_get_sk (cdk_keydb_hd_t khd, unsigned int * keyid,
cdk_seckey_t *ret_sk);
/* Try to read the next key block from the given input stream.
The key will be returned in @RET_KEY on success. */
cdk_error_t cdk_keydb_get_keyblock (cdk_stream_t inp, cdk_kbnode_t * ret_key);
/* Rebuild the key db index if possible. */
cdk_error_t cdk_keydb_idx_rebuild (cdk_keydb_hd_t hd);
/* Export one or more keys from the given key db handle into
the stream @OUT. The export is done by substring search and
uses the string list @REMUSR for the pattern. */
cdk_error_t cdk_keydb_export (cdk_keydb_hd_t hd, cdk_stream_t out,
cdk_strlist_t remusr);
/* Import the given key node @knode into the key db. */
cdk_error_t cdk_keydb_import (cdk_keydb_hd_t hd, cdk_kbnode_t knode);
/* List or enumerate keys from a given key db handle. */
/* Start the key list process. Either use @PATT for a pattern search
or @FPATT for a list of pattern. */
cdk_error_t cdk_listkey_start (cdk_listkey_t *r_ctx, cdk_keydb_hd_t db,
const char *patt, cdk_strlist_t fpatt);
void cdk_listkey_close (cdk_listkey_t ctx);
/* Return the next key which matches the pattern. */
cdk_error_t cdk_listkey_next (cdk_listkey_t ctx, cdk_kbnode_t *ret_key);
cdk_kbnode_t cdk_kbnode_new (cdk_packet_t pkt);
cdk_error_t cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
const unsigned char * buf,
size_t buflen);
cdk_error_t cdk_kbnode_write_to_mem (cdk_kbnode_t node,
unsigned char * buf, size_t * r_nbytes);
cdk_error_t cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
unsigned char **r_buf,
size_t *r_buflen);
void cdk_kbnode_release (cdk_kbnode_t node);
cdk_kbnode_t cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * ctx, int all);
cdk_packet_t cdk_kbnode_find_packet (cdk_kbnode_t node, int pkttype);
cdk_packet_t cdk_kbnode_get_packet (cdk_kbnode_t node);
cdk_kbnode_t cdk_kbnode_find (cdk_kbnode_t node, int pkttype);
cdk_kbnode_t cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node,
int pkttype);
cdk_kbnode_t cdk_kbnode_find_next (cdk_kbnode_t node, int pkttype);
cdk_error_t cdk_kbnode_hash (cdk_kbnode_t node, gcry_md_hd_t md, int is_v4,
int pkttype, int flags);
/* Check each signature in the key node and return a summary of the
key status in @r_status. Values of cdk_key_flag_t are used. */
cdk_error_t cdk_pk_check_sigs (cdk_kbnode_t knode, cdk_keydb_hd_t hd,
int *r_status);
/* Check the self signature of the key to make sure it is valid. */
cdk_error_t cdk_pk_check_self_sig (cdk_kbnode_t knode, int *r_status);
/* Return a matching algorithm from the given public key list.
@PREFTYPE can be either sym-cipher/compress/digest. */
int cdk_pklist_select_algo (cdk_keylist_t pkl, int preftype);
/* Return 0 or 1 if the given key list is able to understand the
MDC feature. */
int cdk_pklist_use_mdc (cdk_keylist_t pkl);
cdk_error_t cdk_pklist_build (cdk_keylist_t *ret_pkl, cdk_keydb_hd_t hd,
cdk_strlist_t remusr, int use);
void cdk_pklist_release (cdk_keylist_t pkl);
/* Encrypt the given DEK key with the list of public keys given
in @PKL. The result will be written to the stream output @OUT. */
cdk_error_t cdk_pklist_encrypt (cdk_keylist_t pkl, cdk_dek_t dek,
cdk_stream_t out);
/* Secret key lists */
cdk_error_t cdk_sklist_build (cdk_keylist_t * ret_skl,
cdk_keydb_hd_t db, cdk_ctx_t hd,
cdk_strlist_t locusr,
int unlock, unsigned int use);
void cdk_sklist_release (cdk_keylist_t skl);
cdk_error_t cdk_sklist_write (cdk_keylist_t skl, cdk_stream_t outp,
gcry_md_hd_t mdctx,
int sigclass, int sigver);
cdk_error_t cdk_sklist_write_onepass (cdk_keylist_t skl, cdk_stream_t outp,
int sigclass, int mdalgo);
/* Encrypt the given stream @INP with the recipients given in @REMUSR.
If @REMUSR is NULL, symmetric encryption will be used. The output
will be written to @OUT. */
cdk_error_t cdk_stream_encrypt (cdk_ctx_t hd, cdk_strlist_t remusr,
cdk_stream_t inp, cdk_stream_t out);
/* Decrypt the @INP stream into @OUT. */
cdk_error_t cdk_stream_decrypt (cdk_ctx_t hd, cdk_stream_t inp,
cdk_stream_t out);
/* Same as the function above but it works on files. */
cdk_error_t cdk_file_encrypt (cdk_ctx_t hd, cdk_strlist_t remusr,
const char *file, const char *output);
cdk_error_t cdk_file_decrypt (cdk_ctx_t hd, const char * file,
const char *output);
/* Generic function to transform data. The mode can be either sign,
verify, encrypt, decrypt, import or export. The meanings of the
parameters are similar to the functions above.
@OUTBUF will contain the output and @OUTSIZE the length of it. */
cdk_error_t cdk_data_transform (cdk_ctx_t hd, enum cdk_crypto_mode_t mode,
cdk_strlist_t locusr, cdk_strlist_t remusr,
const void * inbuf, size_t insize,
unsigned char ** outbuf, size_t * outsize,
int modval);
/* Sign the stream @INP. Optionally, the output will be encrypted
if @REMUSR is not NULL and the @ENCRYPTFLAG is set.
The output will be written to @OUT.
@LOCUSR contains one ore more pattern for the secret key(s) to use. */
cdk_error_t cdk_stream_sign (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t out,
cdk_strlist_t locusr, cdk_strlist_t remusr,
int encryptflag, int sigmode);
/* Same as the function above but it works on files. */
cdk_error_t cdk_file_sign (cdk_ctx_t hd, cdk_strlist_t locusr,
cdk_strlist_t remusr,
const char *file, const char *output,
int sigmode, int encryptflag);
cdk_error_t cdk_stream_verify (cdk_ctx_t hd, cdk_stream_t inp,
cdk_stream_t data,
cdk_stream_t out);
/* Verify the given file @FILE. For a detached signature, @DATA_FILE
contains the actual file data and @FILE is only the signature.
If the @OUTPUT is not NULL, the plaintext will be written to this file. */
cdk_error_t cdk_file_verify (cdk_ctx_t hd, const char *file,
const char *data_file, const char *output);
int cdk_trustdb_get_validity (cdk_stream_t inp, cdk_pkt_userid_t id,
int *r_val);
int cdk_trustdb_get_ownertrust (cdk_stream_t inp, cdk_pubkey_t pk,
int *r_val, int *r_flags);
void cdk_strlist_free (cdk_strlist_t sl);
cdk_strlist_t cdk_strlist_add (cdk_strlist_t * list, const char * string);
cdk_strlist_t cdk_strlist_next (cdk_strlist_t root, const char **r_str);
const char * cdk_check_version (const char * req_version);
/* UTF8 */
char* cdk_utf8_encode (const char * string);
char* cdk_utf8_decode (const char * string, size_t length, int delim);
/* Try to receive the key, which has the key ID @KEYID, from the
keyserver host @HOST and the port @PORT. */
cdk_error_t cdk_keyserver_recv_key (const char *host, int port,
const unsigned char *keyid, int kid_type,
cdk_kbnode_t *r_key);
cdk_error_t cdk_keygen_new (cdk_keygen_ctx_t * r_hd);
void cdk_keygen_free (cdk_keygen_ctx_t hd);
/* Set the preferences of the given type for the new key.
@ARRAY is an array which list of algorithm IDs. */
cdk_error_t cdk_keygen_set_prefs (cdk_keygen_ctx_t hd,
enum cdk_pref_type_t type,
const unsigned char * array, size_t n);
cdk_error_t cdk_keygen_set_algo_info (cdk_keygen_ctx_t hd, int type,
int usage, enum cdk_pubkey_algo_t algo,
unsigned int bits);
int cdk_keygen_set_keyserver_flags (cdk_keygen_ctx_t hd, int no_modify,
const char *pref_url);
int cdk_keygen_set_expire_date (cdk_keygen_ctx_t hd, int type,
long timestamp);
/* Set the user ID specifc parts for the new key.
It is suggested to use a name in the form of
'First Name' 'Last Name' <email-address@host.domain> */
void cdk_keygen_set_name (cdk_keygen_ctx_t hd, const char * name);
void cdk_keygen_set_passphrase (cdk_keygen_ctx_t hd, const char * pass);
cdk_error_t cdk_keygen_start (cdk_keygen_ctx_t hd);
cdk_error_t cdk_keygen_save (cdk_keygen_ctx_t hd,
const char * pubf,
const char * secf);
#ifdef __cplusplus
}
#endif
#endif /* OPENCDK_H */
-40
View File
@@ -1,40 +0,0 @@
/* packet.h
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef CDK_PACKET_H
#define CDK_PACKET_H
struct cdk_kbnode_s
{
struct cdk_kbnode_s *next;
cdk_packet_t pkt;
unsigned int is_deleted:1;
unsigned int is_cloned:1;
};
/*-- new-packet.c --*/
void _cdk_free_mpibuf (size_t n, gcry_mpi_t *array);
void _cdk_free_userid (cdk_pkt_userid_t uid);
void _cdk_free_signature( cdk_pkt_signature_t sig );
cdk_prefitem_t _cdk_copy_prefs( const cdk_prefitem_t prefs );
int _cdk_copy_userid( cdk_pkt_userid_t *dst, cdk_pkt_userid_t src );
int _cdk_copy_pubkey( cdk_pkt_pubkey_t* dst, cdk_pkt_pubkey_t src );
int _cdk_copy_seckey( cdk_pkt_seckey_t* dst, cdk_pkt_seckey_t src );
int _cdk_copy_pk_to_sk( cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk );
int _cdk_copy_signature( cdk_pkt_signature_t* dst, cdk_pkt_signature_t src );
int _cdk_pubkey_compare( cdk_pkt_pubkey_t a, cdk_pkt_pubkey_t b );
#endif /* CDK_PACKET_H */
-1380
View File
@@ -1,1380 +0,0 @@
/* pubkey.c - Public key API
* Copyright (C) 2007 Free Software Foundation, Inc.
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <gcrypt.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
/* Convert the given secret key into a gcrypt SEXP object. */
static int
seckey_to_sexp (gcry_sexp_t * r_skey, cdk_seckey_t sk)
{
gcry_sexp_t sexp = NULL;
gcry_mpi_t *mpk = NULL, *msk = NULL;
gcry_error_t err;
cdk_pubkey_t pk;
const char *fmt;
if (!r_skey || !sk || !sk->pk)
return CDK_Inv_Value;
pk = sk->pk;
mpk = pk->mpi;
msk = sk->mpi;
*r_skey = NULL;
if (is_RSA (sk->pubkey_algo))
{
fmt = "(private-key(openpgp-rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))";
err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1],
msk[0], msk[1], msk[2], msk[3]);
}
else if (is_ELG (sk->pubkey_algo))
{
fmt = "(private-key(openpgp-elg(p%m)(g%m)(y%m)(x%m)))";
err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1],
mpk[2], msk[0]);
}
else if (is_DSA (sk->pubkey_algo))
{
fmt = "(private-key(openpgp-dsa(p%m)(q%m)(g%m)(y%m)(x%m)))";
err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1], mpk[2],
mpk[3], msk[0]);
}
else
return CDK_Inv_Algo;
if (err)
return map_gcry_error (err);
*r_skey = sexp;
return 0;
}
/* Convert the given public key to a gcrypt SEXP object. */
static cdk_error_t
pubkey_to_sexp (gcry_sexp_t * r_key_sexp, cdk_pubkey_t pk)
{
gcry_mpi_t *m;
gcry_error_t err;
const char *fmt = NULL;
cdk_error_t rc = 0;
if (!r_key_sexp || !pk)
return CDK_Inv_Value;
m = pk->mpi;
if (is_RSA (pk->pubkey_algo))
{
fmt = "(public-key(openpgp-rsa(n%m)(e%m)))";
err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1]);
if (err)
rc = map_gcry_error (err);
}
else if (is_ELG (pk->pubkey_algo))
{
fmt = "(public-key(openpgp-elg(p%m)(g%m)(y%m)))";
err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1], m[2]);
if (err)
rc = map_gcry_error (err);
}
else if (is_DSA (pk->pubkey_algo))
{
fmt = "(public-key(openpgp-dsa(p%m)(q%m)(g%m)(y%m)))";
err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1], m[2], m[3]);
if (err)
rc = map_gcry_error (err);
}
else
rc = CDK_Inv_Algo;
return rc;
}
static cdk_error_t
enckey_to_sexp (gcry_sexp_t * r_sexp, gcry_mpi_t esk)
{
gcry_error_t err;
if (!r_sexp || !esk)
return CDK_Inv_Value;
err = gcry_sexp_build (r_sexp, NULL, "%m", esk);
if (err)
return map_gcry_error (err);
return 0;
}
static cdk_error_t
digest_to_sexp (gcry_sexp_t * r_md_sexp, int digest_algo,
const byte * md, size_t mdlen)
{
gcry_mpi_t m;
gcry_error_t err;
if (!r_md_sexp || !md)
return CDK_Inv_Value;
if (!mdlen)
mdlen = gcry_md_get_algo_dlen (digest_algo);
if (!mdlen)
return CDK_Inv_Algo;
err = gcry_mpi_scan (&m, GCRYMPI_FMT_USG, md, mdlen, &mdlen);
if (err)
return map_gcry_error (err);
err = gcry_sexp_build (r_md_sexp, NULL, "%m", m);
gcry_mpi_release (m);
if (err)
return map_gcry_error (err);
return 0;
}
static cdk_error_t
sexp_to_mpi (gcry_sexp_t sexp, const char *val, gcry_mpi_t * ret_buf)
{
gcry_sexp_t list;
if (!sexp || !val || !ret_buf)
return CDK_Inv_Value;
list = gcry_sexp_find_token (sexp, val, 0);
if (!list)
return CDK_Inv_Value;
*ret_buf = gcry_sexp_nth_mpi (list, 1, 0);
gcry_sexp_release (list);
if (!*ret_buf)
return CDK_Inv_Value;
return 0;
}
static cdk_error_t
sexp_to_sig (cdk_pkt_signature_t sig, gcry_sexp_t sexp)
{
if (!sig || !sexp)
return CDK_Inv_Value;
/* ElGamal signatures are not supported any longer. */
if (is_ELG (sig->pubkey_algo))
{
_cdk_log_debug ("sexp_to_sig: unsupported signature type (ElGamal)\n");
return CDK_Not_Implemented;
}
if (is_RSA (sig->pubkey_algo))
return sexp_to_mpi (sexp, "s", &sig->mpi[0]);
else if (is_DSA (sig->pubkey_algo))
{
cdk_error_t rc;
rc = sexp_to_mpi (sexp, "r", &sig->mpi[0]);
if (!rc)
rc = sexp_to_mpi (sexp, "s", &sig->mpi[1]);
return rc;
}
return CDK_Inv_Algo;
}
static cdk_error_t
sig_to_sexp (gcry_sexp_t * r_sig_sexp, cdk_pkt_signature_t sig)
{
gcry_error_t err;
cdk_error_t rc;
const char *fmt;
if (!r_sig_sexp || !sig)
return CDK_Inv_Value;
if (is_ELG (sig->pubkey_algo))
return CDK_Not_Implemented;
rc = 0;
if (is_RSA (sig->pubkey_algo))
{
fmt = "(sig-val(openpgp-rsa(s%m)))";
err = gcry_sexp_build (r_sig_sexp, NULL, fmt, sig->mpi[0]);
if (err)
rc = map_gcry_error (err);
}
else if (is_DSA (sig->pubkey_algo))
{
fmt = "(sig-val(openpgp-dsa(r%m)(s%m)))";
err = gcry_sexp_build (r_sig_sexp, NULL, fmt, sig->mpi[0], sig->mpi[1]);
if (err)
rc = map_gcry_error (err);
}
else
rc = CDK_Inv_Algo;
return rc;
}
static cdk_error_t
sexp_to_pubenc (cdk_pkt_pubkey_enc_t enc, gcry_sexp_t sexp)
{
if (!sexp || !enc)
return CDK_Inv_Value;
if (is_RSA (enc->pubkey_algo))
return sexp_to_mpi (sexp, "a", &enc->mpi[0]);
else if (is_ELG (enc->pubkey_algo))
{
cdk_error_t rc = sexp_to_mpi (sexp, "a", &enc->mpi[0]);
if (!rc)
rc = sexp_to_mpi (sexp, "b", &enc->mpi[1]);
return rc;
}
return CDK_Inv_Algo;
}
static cdk_error_t
pubenc_to_sexp (gcry_sexp_t * r_sexp, cdk_pkt_pubkey_enc_t enc)
{
gcry_sexp_t sexp = NULL;
gcry_error_t err;
const char *fmt;
if (!r_sexp || !enc)
return CDK_Inv_Value;
*r_sexp = NULL;
if (is_RSA (enc->pubkey_algo))
{
fmt = "(enc-val(openpgp-rsa((a%m))))";
err = gcry_sexp_build (&sexp, NULL, fmt, enc->mpi[0]);
}
else if (is_ELG (enc->pubkey_algo))
{
fmt = "(enc-val(openpgp-elg((a%m)(b%m))))";
err = gcry_sexp_build (&sexp, NULL, fmt, enc->mpi[0], enc->mpi[1]);
}
else
return CDK_Inv_Algo;
if (err)
return map_gcry_error (err);
*r_sexp = sexp;
return 0;
}
static int
is_unprotected (cdk_seckey_t sk)
{
if (sk->is_protected && !sk->mpi[0])
return 0;
return 1;
}
/**
* cdk_pk_encrypt:
* @pk: the public key
* @pke: the public key encrypted packet
* @esk: the actual session key
*
* Encrypt the session key in @esk and write its encrypted content
* into the @pke struct.
**/
cdk_error_t
cdk_pk_encrypt (cdk_pubkey_t pk, cdk_pkt_pubkey_enc_t pke, gcry_mpi_t esk)
{
gcry_sexp_t s_data = NULL, s_pkey = NULL, s_ciph = NULL;
gcry_error_t err;
cdk_error_t rc;
if (!pk || !esk || !pke)
return CDK_Inv_Value;
if (!KEY_CAN_ENCRYPT (pk->pubkey_algo))
return CDK_Inv_Algo;
rc = enckey_to_sexp (&s_data, esk);
if (!rc)
rc = pubkey_to_sexp (&s_pkey, pk);
if (!rc)
{
err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
if (err)
return map_gcry_error (err);
}
if (!rc)
rc = sexp_to_pubenc (pke, s_ciph);
gcry_sexp_release (s_data);
gcry_sexp_release (s_pkey);
gcry_sexp_release (s_ciph);
return rc;
}
/**
* cdk_pk_decrypt:
* @sk: the secret key
* @pke: public key encrypted packet
* @r_sk: the object to store the plain session key
*
* Decrypt the encrypted session key from @pke into @r_sk.
**/
cdk_error_t
cdk_pk_decrypt (cdk_seckey_t sk, cdk_pkt_pubkey_enc_t pke, gcry_mpi_t * r_sk)
{
gcry_sexp_t s_data = NULL, s_skey = NULL, s_plain = NULL;
cdk_error_t rc;
gcry_error_t err;
if (!sk || !r_sk || !pke)
return CDK_Inv_Value;
if (!is_unprotected (sk))
return CDK_Inv_Mode;
*r_sk = NULL;
rc = seckey_to_sexp (&s_skey, sk);
if (rc)
return rc;
rc = pubenc_to_sexp (&s_data, pke);
if (rc)
{
gcry_sexp_release (s_skey);
return rc;
}
err = gcry_pk_decrypt (&s_plain, s_data, s_skey);
if (err)
rc = map_gcry_error (err);
else
*r_sk = gcry_sexp_nth_mpi (s_plain, 0, 0);
gcry_sexp_release (s_data);
gcry_sexp_release (s_skey);
gcry_sexp_release (s_plain);
return rc;
}
/**
* cdk_pk_sign:
* @sk: secret key
* @sig: signature
* @md: the message digest
*
* Sign the message digest from @md and write the result into @sig.
**/
cdk_error_t
cdk_pk_sign (cdk_seckey_t sk, cdk_pkt_signature_t sig, const byte * md)
{
gcry_sexp_t s_skey = NULL, s_sig = NULL, s_hash = NULL;
byte *encmd = NULL;
size_t enclen = 0;
int nbits;
cdk_error_t rc;
gcry_error_t err;
if (!sk || !sk->pk || !sig || !md)
return CDK_Inv_Value;
if (!is_unprotected (sk))
return CDK_Inv_Mode;
if (!KEY_CAN_SIGN (sig->pubkey_algo))
return CDK_Inv_Algo;
nbits = cdk_pk_get_nbits (sk->pk);
rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, sk->pk->pubkey_algo, md,
sig->digest_algo, nbits);
if (rc)
return rc;
rc = seckey_to_sexp (&s_skey, sk);
if (!rc)
rc = digest_to_sexp (&s_hash, sig->digest_algo, encmd, enclen);
if (rc)
{
cdk_free (encmd);
gcry_sexp_release (s_skey);
return rc;
}
err = gcry_pk_sign (&s_sig, s_hash, s_skey);
if (err)
rc = map_gcry_error (err);
else
{
rc = sexp_to_sig (sig, s_sig);
if (!rc)
{
sig->digest_start[0] = md[0];
sig->digest_start[1] = md[1];
}
}
gcry_sexp_release (s_skey);
gcry_sexp_release (s_hash);
gcry_sexp_release (s_sig);
cdk_free (encmd);
return rc;
}
/**
* cdk_pk_verify:
* @pk: the public key
* @sig: signature
* @md: the message digest
*
* Verify the signature in @sig and compare it with the message digest in @md.
**/
cdk_error_t
cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md)
{
gcry_sexp_t s_pkey = NULL, s_sig = NULL, s_hash = NULL;
byte *encmd = NULL;
size_t enclen;
cdk_error_t rc;
if (!pk || !sig || !md)
return CDK_Inv_Value;
rc = pubkey_to_sexp (&s_pkey, pk);
if (rc)
return rc;
rc = sig_to_sexp (&s_sig, sig);
if (rc)
goto leave;
rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, pk->pubkey_algo, md,
sig->digest_algo, cdk_pk_get_nbits (pk));
if (rc)
goto leave;
rc = digest_to_sexp (&s_hash, sig->digest_algo, encmd, enclen);
if (rc)
goto leave;
if (gcry_pk_verify (s_sig, s_hash, s_pkey))
rc = CDK_Bad_Sig;
leave:
gcry_sexp_release (s_sig);
gcry_sexp_release (s_hash);
gcry_sexp_release (s_pkey);
cdk_free (encmd);
return rc;
}
/**
* cdk_pk_get_nbits:
* @pk: the public key
*
* Return the length of the public key in bits.
* The meaning of length is actually the size of the 'prime'
* object in the key. For RSA keys the modulus, for ElG/DSA
* the size of the public prime.
**/
int
cdk_pk_get_nbits (cdk_pubkey_t pk)
{
if (!pk || !pk->mpi[0])
return 0;
return gcry_mpi_get_nbits (pk->mpi[0]);
}
/**
* cdk_pk_get_npkey:
* @algo: The public key algorithm.
*
* Return the number of multiprecison integer forming an public
* key with the given algorithm.
*/
int
cdk_pk_get_npkey (int algo)
{
size_t bytes;
if (algo == 16)
algo = 20; /* FIXME: libgcrypt returns 0 for 16 */
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &bytes))
return 0;
return bytes;
}
/**
* cdk_pk_get_nskey:
* @algo: the public key algorithm
*
* Return the number of multiprecision integers forming an
* secret key with the given algorithm.
**/
int
cdk_pk_get_nskey (int algo)
{
size_t bytes;
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &bytes))
return 0;
bytes -= cdk_pk_get_npkey (algo);
return bytes;
}
/**
* cdk_pk_get_nbits:
* @algo: the public key algorithm
*
* Return the number of MPIs a signature consists of.
**/
int
cdk_pk_get_nsig (int algo)
{
size_t bytes;
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &bytes))
return 0;
return bytes;
}
/**
* cdk_pk_get_nenc:
* @algo: the public key algorithm
*
* Return the number of MPI's the encrypted data consists of.
**/
int
cdk_pk_get_nenc (int algo)
{
size_t bytes;
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NENCR, NULL, &bytes))
return 0;
return bytes;
}
int
_cdk_pk_algo_usage (int algo)
{
int usage;
/* The ElGamal sign+encrypt algorithm is not supported any longer. */
switch (algo)
{
case CDK_PK_RSA:
usage = CDK_KEY_USG_SIGN | CDK_KEY_USG_ENCR;
break;
case CDK_PK_RSA_E:
usage = CDK_KEY_USG_ENCR;
break;
case CDK_PK_RSA_S:
usage = CDK_KEY_USG_SIGN;
break;
case CDK_PK_ELG_E:
usage = CDK_KEY_USG_ENCR;
break;
case CDK_PK_DSA:
usage = CDK_KEY_USG_SIGN;
break;
default:
usage = 0;
}
return usage;
}
static cdk_error_t
mpi_to_buffer (gcry_mpi_t a, byte * buf, size_t buflen,
size_t * r_nwritten, size_t * r_nbits)
{
size_t nbits;
if (!a || !buf || !r_nwritten)
return CDK_Inv_Value;
nbits = gcry_mpi_get_nbits (a);
if (r_nbits)
*r_nbits = nbits;
if ((nbits + 7) / 8 + 2 > buflen)
return CDK_Too_Short;
*r_nwritten = (nbits + 7) / 8 + 2;
if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf, buflen, r_nwritten, a))
return CDK_Wrong_Format;
return 0;
}
/**
* cdk_pk_get_mpi:
* @pk: public key
* @idx: index of the MPI to retrieve
* @buf: buffer to hold the raw data
* @r_nwritten: output how large the raw data is
* @r_nbits: size of the MPI in bits.
*
* Return the MPI with the given index of the public key.
**/
cdk_error_t
cdk_pk_get_mpi (cdk_pubkey_t pk, size_t idx,
byte * buf, size_t buflen, size_t * r_nwritten,
size_t * r_nbits)
{
if (!pk || !r_nwritten)
return CDK_Inv_Value;
if (idx > cdk_pk_get_npkey (pk->pubkey_algo))
return CDK_Inv_Value;
return mpi_to_buffer (pk->mpi[idx], buf, buflen, r_nwritten, r_nbits);
}
/**
* cdk_sk_get_mpi:
* @sk: secret key
* @idx: index of the MPI to retrieve
* @buf: buffer to hold the raw data
* @r_nwritten: output length of the raw data
* @r_nbits: length of the MPI data in bits.
*
* Return the MPI of the given secret key with the
* index @idx. It is important to check if the key
* is protected and thus no real MPI data will be returned then.
**/
cdk_error_t
cdk_sk_get_mpi (cdk_pkt_seckey_t sk, size_t idx,
byte * buf, size_t buflen, size_t * r_nwritten,
size_t * r_nbits)
{
if (!sk || !r_nwritten)
return CDK_Inv_Value;
if (idx > cdk_pk_get_nskey (sk->pubkey_algo))
return CDK_Inv_Value;
return mpi_to_buffer (sk->mpi[idx], buf, buflen, r_nwritten, r_nbits);
}
static u16
checksum_mpi (gcry_mpi_t m)
{
byte buf[MAX_MPI_BYTES + 2];
size_t nread;
int i;
u16 chksum = 0;
if (!m)
return 0;
if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf, DIM (buf), &nread, m))
return 0;
for (i = 0; i < nread; i++)
chksum += buf[i];
return chksum;
}
/**
* cdk_sk_unprotect:
* @sk: the secret key
* @pw: the passphrase
*
* Unprotect the given secret key with the passphrase.
**/
cdk_error_t
cdk_sk_unprotect (cdk_pkt_seckey_t sk, const char *pw)
{
gcry_cipher_hd_t hd;
cdk_dek_t dek = NULL;
byte *data = NULL;
u16 chksum = 0;
size_t ndata, nbits, nbytes;
int i, dlen, pos = 0, nskey;
cdk_error_t rc;
gcry_error_t err;
if (!sk)
return CDK_Inv_Value;
nskey = cdk_pk_get_nskey (sk->pubkey_algo);
if (!sk->is_protected)
{
chksum = 0;
for (i = 0; i < nskey; i++)
chksum += checksum_mpi (sk->mpi[i]);
if (chksum != sk->csum)
return CDK_Chksum_Error;
}
rc = cdk_dek_from_passphrase (&dek, sk->protect.algo,
sk->protect.s2k, 0, pw);
if (rc)
return rc;
err = gcry_cipher_open (&hd, sk->protect.algo, GCRY_CIPHER_MODE_CFB,
GCRY_CIPHER_ENABLE_SYNC);
if (!err)
err = gcry_cipher_setiv (hd, sk->protect.iv, sk->protect.ivlen);
if (!err)
err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
if (err)
{
cdk_free (dek);
return map_gcry_error (err);
}
cdk_dek_free (dek);
chksum = 0;
if (sk->version == 4)
{
ndata = sk->enclen;
data = cdk_salloc (ndata, 1);
if (!data)
return CDK_Out_Of_Core;
gcry_cipher_decrypt (hd, data, ndata, sk->encdata, ndata);
if (sk->protect.sha1chk)
{
/* This is the new SHA1 checksum method to detect tampering
with the key as used by the Klima/Rosa attack */
sk->csum = 0;
chksum = 1;
dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
if (ndata < dlen)
{
cdk_free (data);
return CDK_Inv_Packet;
}
else
{
byte mdcheck[20];
gcry_md_hash_buffer (GCRY_MD_SHA1, mdcheck, data, ndata - dlen);
if (!memcmp (mdcheck, data + ndata - dlen, dlen))
chksum = 0; /* Digest does match */
}
}
else
{
for (i = 0; i < ndata - 2; i++)
chksum += data[i];
sk->csum = data[ndata - 2] << 8 | data[ndata - 1];
}
if (sk->csum == chksum)
{
for (i = 0; i < nskey; i++)
{
nbits = data[pos] << 8 | data[pos + 1];
if (gcry_mpi_scan (&sk->mpi[i], GCRYMPI_FMT_PGP, data,
(nbits + 7) / 8 + 2, &nbytes))
{
wipemem (data, sk->enclen);
cdk_free (data);
return CDK_Wrong_Format;
}
gcry_mpi_set_flag (sk->mpi[i], GCRYMPI_FLAG_SECURE);
pos += (nbits + 7) / 8 + 2;
}
}
wipemem (data, sk->enclen);
cdk_free (data);
}
else
{
byte buf[MAX_MPI_BYTES + 2];
chksum = 0;
for (i = 0; i < nskey; i++)
{
gcry_cipher_sync (hd);
gcry_mpi_print (GCRYMPI_FMT_PGP, buf, DIM (buf),
&nbytes, sk->mpi[i]);
gcry_cipher_decrypt (hd, buf + 2, nbytes - 2, NULL, 0);
gcry_mpi_release (sk->mpi[i]);
if (gcry_mpi_scan (&sk->mpi[i], GCRYMPI_FMT_PGP,
buf, nbytes, &nbytes))
return CDK_Wrong_Format;
chksum += checksum_mpi (sk->mpi[i]);
}
}
gcry_cipher_close (hd);
if (chksum != sk->csum)
return CDK_Chksum_Error;
sk->is_protected = 0;
return 0;
}
/**
* cdk_sk_protect:
* @sk: the secret key
* @pw: the passphrase to use
*
* Protect the given secret key with a passphrase.
**/
cdk_error_t
cdk_sk_protect (cdk_pkt_seckey_t sk, const char *pw)
{
gcry_cipher_hd_t hd = NULL;
cdk_dek_t dek = NULL;
cdk_s2k_t s2k;
byte *p = NULL, buf[MAX_MPI_BYTES + 2];
size_t enclen = 0, nskey, i, nbytes;
size_t dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
gcry_error_t err;
cdk_error_t rc;
nskey = cdk_pk_get_nskey (sk->pubkey_algo);
if (!nskey)
return CDK_Inv_Algo;
rc = cdk_s2k_new (&s2k, CDK_S2K_ITERSALTED, GCRY_MD_SHA256, NULL);
if (!rc)
rc = cdk_dek_from_passphrase (&dek, GCRY_CIPHER_AES, s2k, 1, pw);
if (rc)
{
cdk_s2k_free (s2k);
return rc;
}
for (i = 0; i < nskey; i++)
{
enclen += 2;
enclen += (gcry_mpi_get_nbits (sk->mpi[i]) + 7) / 8;
}
p = sk->encdata = cdk_calloc (1, enclen + dlen + 1);
if (!p)
{
cdk_s2k_free (s2k);
return CDK_Out_Of_Core;
}
enclen = 0;
for (i = 0; i < nskey; i++)
{
if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf,
DIM (buf), &nbytes, sk->mpi[i]))
{
cdk_free (p);
cdk_s2k_free (s2k);
return CDK_Wrong_Format;
}
memcpy (p + enclen, buf, nbytes);
enclen += nbytes;
}
enclen += dlen;
sk->enclen = enclen;
sk->protect.s2k = s2k;
sk->protect.algo = GCRY_CIPHER_AES;
sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo);
gcry_randomize (sk->protect.iv, sk->protect.ivlen, GCRY_STRONG_RANDOM);
err = gcry_cipher_open (&hd, sk->protect.algo, GCRY_CIPHER_MODE_CFB,
GCRY_CIPHER_ENABLE_SYNC);
if (err)
{
cdk_dek_free (dek);
rc = map_gcry_error (err);
goto leave;
}
err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
if (!err)
err = gcry_cipher_setiv (hd, sk->protect.iv, sk->protect.ivlen);
cdk_dek_free (dek);
if (err)
{
rc = map_gcry_error (err);
goto leave;
}
sk->protect.sha1chk = 1;
sk->is_protected = 1;
sk->csum = 0;
gcry_md_hash_buffer (GCRY_MD_SHA1, buf, p, enclen - dlen);
memcpy (p + enclen - dlen, buf, dlen);
gcry_cipher_encrypt (hd, p, enclen, NULL, 0);
/* FIXME: We should release all MPI's and set the elements to NULL. */
leave:
gcry_cipher_close (hd);
return rc;
}
/**
* cdk_pk_from_secret_key:
* @sk: the secret key
* @ret_pk: the new public key
*
* Create a new public key from a secret key.
**/
cdk_error_t
cdk_pk_from_secret_key (cdk_pkt_seckey_t sk, cdk_pubkey_t * ret_pk)
{
if (!sk)
return CDK_Inv_Value;
return _cdk_copy_pubkey (ret_pk, sk->pk);
}
#if 0 /* FIXME: Code is not finished yet. */
cdk_error_t
cdk_pk_revoke_cert_create (cdk_pkt_seckey_t sk, int code, const char *inf,
char **ret_revcert)
{
gcry_md_hd_t md;
cdk_subpkt_t node;
cdk_pkt_signature_t sig;
char *p = NULL, *dat;
gcry_error_t err;
cdk_error_t rc = 0;
size_t n;
if (!sk || !ret_revcert)
return CDK_Inv_Value;
if (code < 0 || code > 3)
return CDK_Inv_Value;
sig = cdk_calloc (1, sizeof *sig);
if (!sig)
return CDK_Out_Of_Core;
_cdk_sig_create (sk->pk, sig);
n = 1;
if (inf)
{
n += strlen (p);
p = cdk_utf8_encode (inf);
}
dat = cdk_calloc (1, n + 1);
if (!dat)
{
_cdk_free_signature (sig);
return CDK_Out_Of_Core;
}
dat[0] = code;
if (inf)
memcpy (dat + 1, p, strlen (p));
cdk_free (p);
node = cdk_subpkt_new (n);
if (node)
{
cdk_subpkt_init (node, CDK_SIGSUBPKT_REVOC_REASON, dat, n);
cdk_subpkt_add (sig->hashed, node);
}
cdk_free (dat);
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (err)
rc = map_gcry_error (err);
else
_cdk_hash_pubkey (sk->pk, md, 0);
_cdk_free_signature (sig);
return rc;
}
#endif
int
_cdk_sk_get_csum (cdk_pkt_seckey_t sk)
{
u16 csum = 0, i;
if (!sk)
return 0;
for (i = 0; i < cdk_pk_get_nskey (sk->pubkey_algo); i++)
csum += checksum_mpi (sk->mpi[i]);
return csum;
}
/**
* cdk_pk_get_fingerprint:
* @pk: the public key
* @fpr: the buffer to hold the fingerprint
*
* Return the fingerprint of the given public key.
* The buffer must be at least 20 octets.
* This function should be considered deprecated and
* the new cdk_pk_to_fingerprint() should be used whenever
* possible to avoid overflows.
**/
cdk_error_t
cdk_pk_get_fingerprint (cdk_pubkey_t pk, byte * fpr)
{
gcry_md_hd_t hd;
int md_algo;
int dlen = 0;
gcry_error_t err;
if (!pk || !fpr)
return CDK_Inv_Value;
if (pk->version < 4 && is_RSA (pk->pubkey_algo))
md_algo = GCRY_MD_MD5; /* special */
else
md_algo = GCRY_MD_SHA1;
dlen = gcry_md_get_algo_dlen (md_algo);
err = gcry_md_open (&hd, md_algo, 0);
if (err)
return map_gcry_error (err);
_cdk_hash_pubkey (pk, hd, 1);
gcry_md_final (hd);
memcpy (fpr, gcry_md_read (hd, md_algo), dlen);
gcry_md_close (hd);
if (dlen == 16)
memset (fpr + 16, 0, 4);
return 0;
}
/**
* cdk_pk_to_fingerprint:
* @pk: the public key
* @fprbuf: buffer to save the fingerprint
* @fprbuflen: buffer size
* @r_nout: actual length of the fingerprint.
*
* Calculate a fingerprint of the given key and
* return it in the given byte array.
**/
cdk_error_t
cdk_pk_to_fingerprint (cdk_pubkey_t pk,
byte * fprbuf, size_t fprbuflen, size_t * r_nout)
{
size_t key_fprlen;
cdk_error_t err;
if (!pk)
return CDK_Inv_Value;
if (pk->version < 4)
key_fprlen = 16;
else
key_fprlen = 20;
/* Only return the required buffer size for the fingerprint. */
if (!fprbuf && !fprbuflen && r_nout)
{
*r_nout = key_fprlen;
return 0;
}
if (!fprbuf || key_fprlen > fprbuflen)
return CDK_Too_Short;
err = cdk_pk_get_fingerprint (pk, fprbuf);
if (r_nout)
*r_nout = key_fprlen;
return err;
}
/**
* cdk_pk_fingerprint_get_keyid:
* @fpr: the key fingerprint
* @fprlen: the length of the fingerprint
*
* Derive the key ID from the key fingerprint.
* For version 3 keys, this is not working.
**/
u32
cdk_pk_fingerprint_get_keyid (const byte * fpr, size_t fprlen, u32 * keyid)
{
u32 lowbits = 0;
/* In this case we say the key is a V3 RSA key and we can't
use the fingerprint to get the keyid. */
if (fpr && fprlen == 16)
{
keyid[0] = 0;
keyid[1] = 0;
return 0;
}
else if (keyid && fpr)
{
keyid[0] = _cdk_buftou32 (fpr + 12);
keyid[1] = _cdk_buftou32 (fpr + 16);
lowbits = keyid[1];
}
else if (fpr)
lowbits = _cdk_buftou32 (fpr + 16);
return lowbits;
}
/**
* cdk_pk_get_keyid:
* @pk: the public key
* @keyid: buffer to store the key ID
*
* Calculate the key ID of the given public key.
**/
u32
cdk_pk_get_keyid (cdk_pubkey_t pk, u32 * keyid)
{
u32 lowbits = 0;
byte buf[24];
if (pk && (!pk->keyid[0] || !pk->keyid[1]))
{
if (pk->version < 4 && is_RSA (pk->pubkey_algo))
{
byte p[MAX_MPI_BYTES];
size_t n;
gcry_mpi_print (GCRYMPI_FMT_USG, p, MAX_MPI_BYTES, &n, pk->mpi[0]);
pk->keyid[0] =
p[n - 8] << 24 | p[n - 7] << 16 | p[n - 6] << 8 | p[n - 5];
pk->keyid[1] =
p[n - 4] << 24 | p[n - 3] << 16 | p[n - 2] << 8 | p[n - 1];
}
else if (pk->version == 4)
{
cdk_pk_get_fingerprint (pk, buf);
pk->keyid[0] = _cdk_buftou32 (buf + 12);
pk->keyid[1] = _cdk_buftou32 (buf + 16);
}
}
lowbits = pk ? pk->keyid[1] : 0;
if (keyid && pk)
{
keyid[0] = pk->keyid[0];
keyid[1] = pk->keyid[1];
}
return lowbits;
}
/**
* cdk_sk_get_keyid:
* @sk: the secret key
* @keyid: buffer to hold the key ID
*
* Calculate the key ID of the secret key, actually the public key.
**/
u32
cdk_sk_get_keyid (cdk_pkt_seckey_t sk, u32 * keyid)
{
u32 lowbits = 0;
if (sk && sk->pk)
{
lowbits = cdk_pk_get_keyid (sk->pk, keyid);
sk->keyid[0] = sk->pk->keyid[0];
sk->keyid[1] = sk->pk->keyid[1];
}
return lowbits;
}
/**
* cdk_sig_get_keyid:
* @sig: the signature
* @keyid: buffer to hold the key ID
*
* Retrieve the key ID from the given signature.
**/
u32
cdk_sig_get_keyid (cdk_pkt_signature_t sig, u32 * keyid)
{
u32 lowbits = sig ? sig->keyid[1] : 0;
if (keyid && sig)
{
keyid[0] = sig->keyid[0];
keyid[1] = sig->keyid[1];
}
return lowbits;
}
/* Return the key ID from the given packet.
If this is not possible, 0 is returned */
u32
_cdk_pkt_get_keyid (cdk_packet_t pkt, u32 * keyid)
{
u32 lowbits;
if (!pkt)
return 0;
switch (pkt->pkttype)
{
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
lowbits = cdk_pk_get_keyid (pkt->pkt.public_key, keyid);
break;
case CDK_PKT_SECRET_KEY:
case CDK_PKT_SECRET_SUBKEY:
lowbits = cdk_sk_get_keyid (pkt->pkt.secret_key, keyid);
break;
case CDK_PKT_SIGNATURE:
lowbits = cdk_sig_get_keyid (pkt->pkt.signature, keyid);
break;
default:
lowbits = 0;
break;
}
return lowbits;
}
/* Get the fingerprint of the packet if possible. */
int
_cdk_pkt_get_fingerprint (cdk_packet_t pkt, byte * fpr)
{
if (!pkt || !fpr)
return CDK_Inv_Value;
switch (pkt->pkttype)
{
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
return cdk_pk_get_fingerprint (pkt->pkt.public_key, fpr);
case CDK_PKT_SECRET_KEY:
case CDK_PKT_SECRET_SUBKEY:
return cdk_pk_get_fingerprint (pkt->pkt.secret_key->pk, fpr);
default:
return CDK_Inv_Mode;
}
return 0;
}
/**
* cdk_pubkey_to_sexp:
* @pk: the public key
* @sexp: where to store the S-expression
* @len: the length of sexp
*
* Convert a public key to an S-expression. sexp is allocated by this
* function, but you have to cdk_free() it yourself. The S-expression
* is stored in canonical format as used by libgcrypt
* (GCRYSEXP_FMT_CANON).
**/
cdk_error_t
cdk_pubkey_to_sexp (cdk_pubkey_t pk, char **sexp, size_t * len)
{
char *buf;
size_t sexp_len;
gcry_sexp_t pk_sexp;
cdk_error_t rc;
if (!pk || !sexp)
return CDK_Inv_Value;
rc = pubkey_to_sexp (&pk_sexp, pk);
if (rc)
return rc;
sexp_len = gcry_sexp_sprint (pk_sexp, GCRYSEXP_FMT_CANON, NULL, 0);
if (!sexp_len)
return CDK_Wrong_Format;
buf = (char *) cdk_malloc (sexp_len);
if (!buf)
{
gcry_sexp_release (pk_sexp);
return CDK_Out_Of_Core;
}
sexp_len = gcry_sexp_sprint (pk_sexp, GCRYSEXP_FMT_CANON, buf, sexp_len);
gcry_sexp_release (pk_sexp);
if (!sexp_len)
{
cdk_free (buf);
return CDK_Wrong_Format;
}
if (len)
*len = sexp_len;
*sexp = buf;
return CDK_Success;
}
/**
* cdk_seckey_to_sexp:
* @sk: the secret key
* @sexp: where to store the S-expression
* @len: the length of sexp
*
* Convert a public key to an S-expression. sexp is allocated by this
* function, but you have to cdk_free() it yourself. The S-expression
* is stored in canonical format as used by libgcrypt
* (GCRYSEXP_FMT_CANON).
**/
cdk_error_t
cdk_seckey_to_sexp (cdk_pkt_seckey_t sk, char **sexp, size_t * len)
{
char *buf;
size_t sexp_len;
gcry_sexp_t sk_sexp;
cdk_error_t rc;
if (!sk || !sexp)
return CDK_Inv_Value;
rc = seckey_to_sexp (&sk_sexp, sk);
if (rc)
return rc;
sexp_len = gcry_sexp_sprint (sk_sexp, GCRYSEXP_FMT_CANON, NULL, 0);
if (!sexp_len)
return CDK_Wrong_Format;
buf = (char *) cdk_malloc (sexp_len);
if (!buf)
{
gcry_sexp_release (sk_sexp);
return CDK_Out_Of_Core;
}
sexp_len = gcry_sexp_sprint (sk_sexp, GCRYSEXP_FMT_CANON, buf, sexp_len);
gcry_sexp_release (sk_sexp);
if (!sexp_len)
{
cdk_free (buf);
return CDK_Wrong_Format;
}
if (len)
*len = sexp_len;
*sexp = buf;
return CDK_Success;
}
-1179
View File
@@ -1,1179 +0,0 @@
/* read-packet.c - Read OpenPGP packets
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
#include "types.h"
/* The version of the MDC packet considering the lastest OpenPGP draft. */
#define MDC_PKT_VER 1
static int
stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t * r_nread)
{
*r_nread = cdk_stream_read (s, buf, buflen);
return *r_nread > 0 ? 0 : _cdk_stream_get_errno (s);
}
/* Try to read 4 octets from the stream. */
static u32
read_32 (cdk_stream_t s)
{
byte buf[4];
size_t nread;
assert (s != NULL);
stream_read (s, buf, 4, &nread);
if (nread != 4)
return (u32) - 1;
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
/* Try to read 2 octets from a stream. */
static u16
read_16 (cdk_stream_t s)
{
byte buf[2];
size_t nread;
assert (s != NULL);
stream_read (s, buf, 2, &nread);
if (nread != 2)
return (u16) - 1;
return buf[0] << 8 | buf[1];
}
static int
read_s2k (cdk_stream_t inp, cdk_s2k_t s2k)
{
size_t nread;
if (!inp || !s2k)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_s2k:\n");
s2k->mode = cdk_stream_getc (inp);
if (cdk_stream_eof (inp))
return CDK_Inv_Packet;
if (s2k->mode != CDK_S2K_SIMPLE && s2k->mode != CDK_S2K_SALTED &&
s2k->mode != CDK_S2K_ITERSALTED)
return CDK_Inv_Packet;
s2k->hash_algo = cdk_stream_getc (inp);
if (s2k->mode == CDK_S2K_SIMPLE) /* No additional elements. */
memset (s2k->salt, 0, sizeof (s2k->salt));
else if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
{
if (stream_read (inp, s2k->salt, DIM (s2k->salt), &nread))
return CDK_Inv_Packet;
if (nread != DIM (s2k->salt))
return CDK_Inv_Packet;
if (s2k->mode == CDK_S2K_ITERSALTED)
{
s2k->count = cdk_stream_getc (inp);
if (cdk_stream_eof (inp))
return CDK_Inv_Packet;
}
}
else
return CDK_Inv_Mode;
return 0;
}
static cdk_error_t
read_mpi (cdk_stream_t inp, gcry_mpi_t * ret_m, int secure)
{
gcry_mpi_t m;
gcry_error_t err;
byte buf[MAX_MPI_BYTES + 2];
size_t nread, nbits;
cdk_error_t rc;
if (!inp || !ret_m)
return CDK_Inv_Value;
*ret_m = NULL;
nbits = read_16 (inp);
nread = (nbits + 7) / 8;
if (nbits > MAX_MPI_BITS || nbits == 0)
{
_cdk_log_debug ("read_mpi: too large %d bits\n", nbits);
return CDK_MPI_Error; /* Sanity check */
}
rc = stream_read (inp, buf + 2, nread, &nread);
if (!rc && nread != ((nbits + 7) / 8))
{
_cdk_log_debug ("read_mpi: too short %d < %d\n", nread,
(nbits + 7) / 8);
return CDK_MPI_Error;
}
buf[0] = nbits >> 8;
buf[1] = nbits >> 0;
err = gcry_mpi_scan (&m, GCRYMPI_FMT_PGP, buf, nread + 2, &nread);
if (err)
return map_gcry_error (err);
if (secure)
gcry_mpi_set_flag (m, GCRYMPI_FLAG_SECURE);
*ret_m = m;
return rc;
}
/* Read the encoded packet length directly from the file
object INP and return it. Reset RET_PARTIAL if this is
the last packet in block mode. */
size_t
_cdk_pkt_read_len (FILE * inp, size_t * ret_partial)
{
int c1, c2;
size_t pktlen;
c1 = fgetc (inp);
if (c1 == EOF)
return (size_t) EOF;
if (c1 < 224 || c1 == 255)
*ret_partial = 0; /* End of partial data */
if (c1 < 192)
pktlen = c1;
else if (c1 >= 192 && c1 <= 223)
{
c2 = fgetc (inp);
if (c2 == EOF)
return (size_t) EOF;
pktlen = ((c1 - 192) << 8) + c2 + 192;
}
else if (c1 == 255)
{
pktlen = fgetc (inp) << 24;
pktlen |= fgetc (inp) << 16;
pktlen |= fgetc (inp) << 8;
pktlen |= fgetc (inp) << 0;
}
else
pktlen = 1 << (c1 & 0x1f);
return pktlen;
}
static cdk_error_t
read_encrypted (cdk_stream_t inp, size_t pktlen, cdk_pkt_encrypted_t enc,
int is_partial, int is_mdc)
{
if (!inp || !enc)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_encrypted: %d octets\n", pktlen);
if (is_mdc)
{
int version = cdk_stream_getc (inp);
if (version != MDC_PKT_VER)
return CDK_Inv_Packet;
enc->mdc_method = CDK_MD_SHA1;
pktlen--;
}
/* The packet must at least contain blocksize + 2 octets. */
if (pktlen < 10)
return CDK_Inv_Packet;
if (is_partial)
_cdk_stream_set_blockmode (inp, pktlen);
enc->len = pktlen;
enc->buf = inp;
return 0;
}
static cdk_error_t
read_symkey_enc (cdk_stream_t inp, size_t pktlen, cdk_pkt_symkey_enc_t ske)
{
cdk_s2k_t s2k;
size_t minlen;
size_t nread, nleft;
if (!inp || !ske)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_symkey_enc: %d octets\n", pktlen);
ske->version = cdk_stream_getc (inp);
if (ske->version != 4 || cdk_stream_eof (inp))
return CDK_Inv_Packet;
s2k = ske->s2k = cdk_calloc (1, sizeof *ske->s2k);
if (!ske->s2k)
return CDK_Out_Of_Core;
ske->cipher_algo = cdk_stream_getc (inp);
s2k->mode = cdk_stream_getc (inp);
switch (s2k->mode)
{
case CDK_S2K_SIMPLE:
minlen = 0;
break;
case CDK_S2K_SALTED:
minlen = 8;
break;
case CDK_S2K_ITERSALTED:
minlen = 9;
break;
default:
/* Invalid S2K mode. */
return CDK_Inv_Packet;
}
s2k->hash_algo = cdk_stream_getc (inp);
if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
{
if (stream_read (inp, s2k->salt, DIM (s2k->salt), &nread))
return CDK_Inv_Packet;
if (nread != DIM (s2k->salt))
return CDK_Inv_Packet;
if (s2k->mode == CDK_S2K_ITERSALTED)
s2k->count = cdk_stream_getc (inp);
}
ske->seskeylen = pktlen - 4 - minlen;
/* We check if there is an encrypted session key and if it fits into
the buffer. The maximal key length is 256-bit. */
if (ske->seskeylen > DIM (ske->seskey))
return CDK_Inv_Packet;
nleft = ske->seskeylen;
for (nread = 0; nread < ske->seskeylen; nread++)
{
ske->seskey[nread] = cdk_stream_getc (inp);
if (cdk_stream_eof (inp) && --nleft > 0)
return CDK_Inv_Packet;
}
return 0;
}
static cdk_error_t
read_pubkey_enc (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_enc_t pke)
{
size_t i, nenc;
if (!inp || !pke)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_pubkey_enc: %d octets\n", pktlen);
if (pktlen < 12)
return CDK_Inv_Packet;
pke->version = cdk_stream_getc (inp);
if (pke->version < 2 || pke->version > 3)
return CDK_Inv_Packet;
pke->keyid[0] = read_32 (inp);
pke->keyid[1] = read_32 (inp);
if (!pke->keyid[0] && !pke->keyid[1])
pke->throw_keyid = 1; /* RFC2440 "speculative" keyID */
pke->pubkey_algo = cdk_stream_getc (inp);
nenc = cdk_pk_get_nenc (pke->pubkey_algo);
if (!nenc)
return CDK_Inv_Algo;
for (i = 0; i < nenc; i++)
{
cdk_error_t rc = read_mpi (inp, &pke->mpi[i], 0);
if (rc)
return rc;
}
return 0;
}
static cdk_error_t
read_mdc (cdk_stream_t inp, cdk_pkt_mdc_t mdc)
{
size_t n;
cdk_error_t rc;
if (!inp || !mdc)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_mdc:\n");
rc = stream_read (inp, mdc->hash, DIM (mdc->hash), &n);
if (rc)
return rc;
return n != DIM (mdc->hash) ? CDK_Inv_Packet : 0;
}
static cdk_error_t
read_compressed (cdk_stream_t inp, size_t pktlen, cdk_pkt_compressed_t c)
{
if (!inp || !c)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_compressed: %d octets\n", pktlen);
c->algorithm = cdk_stream_getc (inp);
if (c->algorithm > 3)
return CDK_Inv_Packet;
/* don't know the size, so we read until EOF */
if (!pktlen)
{
c->len = 0;
c->buf = inp;
}
/* FIXME: Support partial bodies. */
return 0;
}
static cdk_error_t
read_public_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_t pk)
{
size_t i, ndays, npkey;
if (!inp || !pk)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_public_key: %d octets\n", pktlen);
pk->is_invalid = 1; /* default to detect missing self signatures */
pk->is_revoked = 0;
pk->has_expired = 0;
pk->version = cdk_stream_getc (inp);
if (pk->version < 2 || pk->version > 4)
return CDK_Inv_Packet_Ver;
pk->timestamp = read_32 (inp);
if (pk->version < 4)
{
ndays = read_16 (inp);
if (ndays)
pk->expiredate = pk->timestamp + ndays * 86400L;
}
pk->pubkey_algo = cdk_stream_getc (inp);
npkey = cdk_pk_get_npkey (pk->pubkey_algo);
if (!npkey)
{
_cdk_log_debug ("invalid public key algorithm %d\n", pk->pubkey_algo);
return CDK_Inv_Algo;
}
for (i = 0; i < npkey; i++)
{
cdk_error_t rc = read_mpi (inp, &pk->mpi[i], 0);
if (rc)
return rc;
}
/* These values are just for the first run and should be
replaced with the actual key flags from the self signature. */
pk->pubkey_usage = _cdk_pk_algo_usage (pk->pubkey_algo);
return 0;
}
static cdk_error_t
read_public_subkey (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_t pk)
{
if (!inp || !pk)
return CDK_Inv_Value;
return read_public_key (inp, pktlen, pk);
}
static cdk_error_t
read_secret_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_seckey_t sk)
{
size_t p1, p2, nread;
int i, nskey;
int rc;
if (!inp || !sk || !sk->pk)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_secret_key: %d octets\n", pktlen);
p1 = cdk_stream_tell (inp);
rc = read_public_key (inp, pktlen, sk->pk);
if (rc)
return rc;
sk->s2k_usage = cdk_stream_getc (inp);
sk->protect.sha1chk = 0;
if (sk->s2k_usage == 254 || sk->s2k_usage == 255)
{
sk->protect.sha1chk = (sk->s2k_usage == 254);
sk->protect.algo = cdk_stream_getc (inp);
sk->protect.s2k = cdk_calloc (1, sizeof *sk->protect.s2k);
if (!sk->protect.s2k)
return CDK_Out_Of_Core;
rc = read_s2k (inp, sk->protect.s2k);
if (rc)
return rc;
sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo);
if (!sk->protect.ivlen)
return CDK_Inv_Packet;
rc = stream_read (inp, sk->protect.iv, sk->protect.ivlen, &nread);
if (rc)
return rc;
if (nread != sk->protect.ivlen)
return CDK_Inv_Packet;
}
else
sk->protect.algo = sk->s2k_usage;
if (sk->protect.algo == GCRY_CIPHER_NONE)
{
sk->csum = 0;
nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
if (!nskey)
return CDK_Inv_Algo;
for (i = 0; i < nskey; i++)
{
rc = read_mpi (inp, &sk->mpi[i], 1);
if (rc)
return rc;
}
sk->csum = read_16 (inp);
sk->is_protected = 0;
}
else if (sk->pk->version < 4)
{
/* The length of each multiprecision integer is stored in plaintext. */
nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
if (!nskey)
return CDK_Inv_Algo;
for (i = 0; i < nskey; i++)
{
rc = read_mpi (inp, &sk->mpi[i], 1);
if (rc)
return rc;
}
sk->csum = read_16 (inp);
sk->is_protected = 1;
}
else
{
/* We need to read the rest of the packet because we do not
have any information how long the encrypted mpi's are */
p2 = cdk_stream_tell (inp);
p2 -= p1;
sk->enclen = pktlen - p2;
if (sk->enclen < 2)
return CDK_Inv_Packet; /* at least 16 bits for the checksum! */
sk->encdata = cdk_calloc (1, sk->enclen + 1);
if (!sk->encdata)
return CDK_Out_Of_Core;
if (stream_read (inp, sk->encdata, sk->enclen, &nread))
return CDK_Inv_Packet;
nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
if (!nskey)
return CDK_Inv_Algo;
/* We mark each MPI entry with NULL to indicate a protected key. */
for (i = 0; i < nskey; i++)
sk->mpi[i] = NULL;
sk->is_protected = 1;
}
sk->is_primary = 1;
_cdk_copy_pk_to_sk (sk->pk, sk);
return 0;
}
static cdk_error_t
read_secret_subkey (cdk_stream_t inp, size_t pktlen, cdk_pkt_seckey_t sk)
{
cdk_error_t rc;
if (!inp || !sk || !sk->pk)
return CDK_Inv_Value;
rc = read_secret_key (inp, pktlen, sk);
sk->is_primary = 0;
return rc;
}
static cdk_error_t
read_attribute (cdk_stream_t inp, size_t pktlen, cdk_pkt_userid_t attr)
{
const byte *p;
byte *buf;
size_t len, nread;
cdk_error_t rc;
if (!inp || !attr || !pktlen)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_attribute: %d octets\n", pktlen);
strcpy (attr->name, "[attribute]");
attr->len = strlen (attr->name);
buf = cdk_calloc (1, pktlen);
if (!buf)
return CDK_Out_Of_Core;
rc = stream_read (inp, buf, pktlen, &nread);
if (rc)
{
cdk_free (buf);
return CDK_Inv_Packet;
}
p = buf;
len = *p++;
pktlen--;
if (len == 255)
{
len = _cdk_buftou32 (p);
p += 4;
pktlen -= 4;
}
else if (len >= 192)
{
if (pktlen < 2)
{
cdk_free (buf);
return CDK_Inv_Packet;
}
len = ((len - 192) << 8) + *p + 192;
p++;
pktlen--;
}
if (*p != 1) /* Currently only 1, meaning an image, is defined. */
{
cdk_free (buf);
return CDK_Inv_Packet;
}
p++;
len--;
if (pktlen - (len + 1) > 0)
return CDK_Inv_Packet;
attr->attrib_img = cdk_calloc (1, len);
if (!attr->attrib_img)
{
cdk_free (buf);
return CDK_Out_Of_Core;
}
attr->attrib_len = len;
memcpy (attr->attrib_img, p, len);
cdk_free (buf);
return rc;
}
static cdk_error_t
read_user_id (cdk_stream_t inp, size_t pktlen, cdk_pkt_userid_t user_id)
{
size_t nread;
cdk_error_t rc;
if (!inp || !user_id)
return CDK_Inv_Value;
if (!pktlen)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("read_user_id: %lu octets\n", pktlen);
user_id->len = pktlen;
rc = stream_read (inp, user_id->name, pktlen, &nread);
if (rc)
return rc;
if (nread != pktlen)
return CDK_Inv_Packet;
user_id->name[nread] = '\0';
return rc;
}
static cdk_error_t
read_subpkt (cdk_stream_t inp, cdk_subpkt_t * r_ctx, size_t * r_nbytes)
{
byte c, c1;
size_t size, nread, n;
cdk_subpkt_t node;
cdk_error_t rc;
if (!inp || !r_nbytes)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_subpkt:\n");
n = 0;
*r_nbytes = 0;
c = cdk_stream_getc (inp);
n++;
if (c == 255)
{
size = read_32 (inp);
n += 4;
}
else if (c >= 192 && c < 255)
{
c1 = cdk_stream_getc (inp);
n++;
if (c1 == 0)
return 0;
size = ((c - 192) << 8) + c1 + 192;
}
else if (c < 192)
size = c;
else
return CDK_Inv_Packet;
node = cdk_subpkt_new (size);
if (!node)
return CDK_Out_Of_Core;
node->size = size;
node->type = cdk_stream_getc (inp);
if (DEBUG_PKT)
_cdk_log_debug (" %d octets %d type\n", node->size, node->type);
n++;
node->size--;
rc = stream_read (inp, node->d, node->size, &nread);
n += nread;
if (rc)
return rc;
*r_nbytes = n;
if (!*r_ctx)
*r_ctx = node;
else
cdk_subpkt_add (*r_ctx, node);
return rc;
}
static cdk_error_t
read_onepass_sig (cdk_stream_t inp, size_t pktlen, cdk_pkt_onepass_sig_t sig)
{
if (!inp || !sig)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_onepass_sig: %d octets\n", pktlen);
if (pktlen != 13)
return CDK_Inv_Packet;
sig->version = cdk_stream_getc (inp);
if (sig->version != 3)
return CDK_Inv_Packet_Ver;
sig->sig_class = cdk_stream_getc (inp);
sig->digest_algo = cdk_stream_getc (inp);
sig->pubkey_algo = cdk_stream_getc (inp);
sig->keyid[0] = read_32 (inp);
sig->keyid[1] = read_32 (inp);
sig->last = cdk_stream_getc (inp);
return 0;
}
static cdk_error_t
parse_sig_subpackets (cdk_pkt_signature_t sig)
{
cdk_subpkt_t node;
/* Setup the standard packet entries, so we can use V4
signatures similar to V3. */
for (node = sig->unhashed; node; node = node->next)
{
if (node->type == CDK_SIGSUBPKT_ISSUER && node->size >= 8)
{
sig->keyid[0] = _cdk_buftou32 (node->d);
sig->keyid[1] = _cdk_buftou32 (node->d + 4);
}
else if (node->type == CDK_SIGSUBPKT_EXPORTABLE && node->d[0] == 0)
{
/* Sometimes this packet might be placed in the unhashed area */
sig->flags.exportable = 0;
}
}
for (node = sig->hashed; node; node = node->next)
{
if (node->type == CDK_SIGSUBPKT_SIG_CREATED && node->size >= 4)
sig->timestamp = _cdk_buftou32 (node->d);
else if (node->type == CDK_SIGSUBPKT_SIG_EXPIRE && node->size >= 4)
{
sig->expiredate = _cdk_buftou32 (node->d);
if (sig->expiredate > 0 && sig->expiredate < (u32) time (NULL))
sig->flags.expired = 1;
}
else if (node->type == CDK_SIGSUBPKT_POLICY)
sig->flags.policy_url = 1;
else if (node->type == CDK_SIGSUBPKT_NOTATION)
sig->flags.notation = 1;
else if (node->type == CDK_SIGSUBPKT_REVOCABLE && node->d[0] == 0)
sig->flags.revocable = 0;
else if (node->type == CDK_SIGSUBPKT_EXPORTABLE && node->d[0] == 0)
sig->flags.exportable = 0;
}
if (sig->sig_class == 0x1F)
{
cdk_desig_revoker_t r, rnode;
for (node = sig->hashed; node; node = node->next)
{
if (node->type == CDK_SIGSUBPKT_REV_KEY)
{
if (node->size < 22)
continue;
rnode = cdk_calloc (1, sizeof *rnode);
if (!rnode)
return CDK_Out_Of_Core;
rnode->r_class = node->d[0];
rnode->algid = node->d[1];
memcpy (rnode->fpr, node->d + 2, KEY_FPR_LEN);
if (!sig->revkeys)
sig->revkeys = rnode;
else
{
for (r = sig->revkeys; r->next; r = r->next)
;
r->next = rnode;
}
}
}
}
return 0;
}
static cdk_error_t
read_signature (cdk_stream_t inp, size_t pktlen, cdk_pkt_signature_t sig)
{
size_t nbytes;
size_t i, size, nsig;
cdk_error_t rc;
if (!inp || !sig)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_signature: %d octets\n", pktlen);
if (pktlen < 16)
return CDK_Inv_Packet;
sig->version = cdk_stream_getc (inp);
if (sig->version < 2 || sig->version > 4)
return CDK_Inv_Packet_Ver;
sig->flags.exportable = 1;
sig->flags.revocable = 1;
if (sig->version < 4)
{
if (cdk_stream_getc (inp) != 5)
return CDK_Inv_Packet;
sig->sig_class = cdk_stream_getc (inp);
sig->timestamp = read_32 (inp);
sig->keyid[0] = read_32 (inp);
sig->keyid[1] = read_32 (inp);
sig->pubkey_algo = cdk_stream_getc (inp);
sig->digest_algo = cdk_stream_getc (inp);
sig->digest_start[0] = cdk_stream_getc (inp);
sig->digest_start[1] = cdk_stream_getc (inp);
nsig = cdk_pk_get_nsig (sig->pubkey_algo);
if (!nsig)
return CDK_Inv_Algo;
for (i = 0; i < nsig; i++)
{
rc = read_mpi (inp, &sig->mpi[i], 0);
if (rc)
return rc;
}
}
else
{
sig->sig_class = cdk_stream_getc (inp);
sig->pubkey_algo = cdk_stream_getc (inp);
sig->digest_algo = cdk_stream_getc (inp);
sig->hashed_size = read_16 (inp);
size = sig->hashed_size;
sig->hashed = NULL;
while (size > 0)
{
rc = read_subpkt (inp, &sig->hashed, &nbytes);
if (rc)
return rc;
size -= nbytes;
}
sig->unhashed_size = read_16 (inp);
size = sig->unhashed_size;
sig->unhashed = NULL;
while (size > 0)
{
rc = read_subpkt (inp, &sig->unhashed, &nbytes);
if (rc)
return rc;
size -= nbytes;
}
rc = parse_sig_subpackets (sig);
if (rc)
return rc;
sig->digest_start[0] = cdk_stream_getc (inp);
sig->digest_start[1] = cdk_stream_getc (inp);
nsig = cdk_pk_get_nsig (sig->pubkey_algo);
if (!nsig)
return CDK_Inv_Algo;
for (i = 0; i < nsig; i++)
{
rc = read_mpi (inp, &sig->mpi[i], 0);
if (rc)
return rc;
}
}
return 0;
}
static cdk_error_t
read_literal (cdk_stream_t inp, size_t pktlen,
cdk_pkt_literal_t * ret_pt, int is_partial)
{
cdk_pkt_literal_t pt = *ret_pt;
size_t nread;
cdk_error_t rc;
if (!inp || !pt)
return CDK_Inv_Value;
if (DEBUG_PKT)
_cdk_log_debug ("read_literal: %d octets\n", pktlen);
pt->mode = cdk_stream_getc (inp);
if (pt->mode != 0x62 && pt->mode != 0x74 && pt->mode != 0x75)
return CDK_Inv_Packet;
if (cdk_stream_eof (inp))
return CDK_Inv_Packet;
pt->namelen = cdk_stream_getc (inp);
if (pt->namelen > 0)
{
*ret_pt = pt = cdk_realloc (pt, sizeof *pt + pt->namelen + 1);
if (!pt)
return CDK_Out_Of_Core;
rc = stream_read (inp, pt->name, pt->namelen, &nread);
if (rc)
return rc;
if (nread != pt->namelen)
return CDK_Inv_Packet;
pt->name[pt->namelen] = '\0';
}
pt->timestamp = read_32 (inp);
pktlen = pktlen - 6 - pt->namelen;
if (is_partial)
_cdk_stream_set_blockmode (inp, pktlen);
pt->buf = inp;
pt->len = pktlen;
return 0;
}
/* Read an old packet CTB and return the length of the body. */
static void
read_old_length (cdk_stream_t inp, int ctb, size_t * r_len, size_t * r_size)
{
int llen = ctb & 0x03;
if (llen == 0)
{
*r_len = cdk_stream_getc (inp);
(*r_size)++;
}
else if (llen == 1)
{
*r_len = read_16 (inp);
(*r_size) += 2;
}
else if (llen == 2)
{
*r_len = read_32 (inp);
(*r_size) += 4;
}
else
{
*r_len = 0;
*r_size = 0;
}
}
/* Read a new CTB and decode the body length. */
static void
read_new_length (cdk_stream_t inp,
size_t * r_len, size_t * r_size, size_t * r_partial)
{
int c, c1;
c = cdk_stream_getc (inp);
(*r_size)++;
if (c < 192)
*r_len = c;
else if (c >= 192 && c <= 223)
{
c1 = cdk_stream_getc (inp);
(*r_size)++;
*r_len = ((c - 192) << 8) + c1 + 192;
}
else if (c == 255)
{
*r_len = read_32 (inp);
(*r_size) += 4;
}
else
{
*r_len = 1 << (c & 0x1f);
*r_partial = 1;
}
}
/* Skip the current packet body. */
static void
skip_packet (cdk_stream_t inp, size_t pktlen)
{
byte buf[BUFSIZE];
size_t nread, buflen = DIM (buf);
while (pktlen > 0)
{
stream_read (inp, buf, pktlen > buflen ? buflen : pktlen, &nread);
pktlen -= nread;
}
assert (pktlen == 0);
}
/**
* cdk_pkt_read:
* @inp: the input stream
* @pkt: allocated packet handle to store the packet
*
* Parse the next packet on the @inp stream and return its contents in @pkt.
**/
cdk_error_t
cdk_pkt_read (cdk_stream_t inp, cdk_packet_t pkt)
{
int use_mdc = 0;
int ctb, is_newctb;
int pkttype;
size_t pktlen = 0, pktsize = 0, is_partial = 0;
cdk_error_t rc;
if (!inp || !pkt)
return CDK_Inv_Value;
ctb = cdk_stream_getc (inp);
if (cdk_stream_eof (inp) || ctb == EOF)
return CDK_EOF;
else if (!ctb)
return CDK_Inv_Packet;
pktsize++;
if (!(ctb & 0x80))
{
_cdk_log_info ("cdk_pkt_read: no openpgp data found. "
"(ctb=%02X; fpos=%02X)\n", ctb, cdk_stream_tell (inp));
return CDK_Inv_Packet;
}
if (ctb & 0x40) /* RFC2440 packet format. */
{
pkttype = ctb & 0x3f;
is_newctb = 1;
}
else /* the old RFC1991 packet format. */
{
pkttype = ctb & 0x3f;
pkttype >>= 2;
is_newctb = 0;
}
if (pkttype > 63)
{
_cdk_log_info ("cdk_pkt_read: unknown type %d\n", pkttype);
return CDK_Inv_Packet;
}
if (is_newctb)
read_new_length (inp, &pktlen, &pktsize, &is_partial);
else
read_old_length (inp, ctb, &pktlen, &pktsize);
pkt->pkttype = pkttype;
pkt->pktlen = pktlen;
pkt->pktsize = pktsize + pktlen;
pkt->old_ctb = is_newctb ? 0 : 1;
rc = 0;
switch (pkt->pkttype)
{
case CDK_PKT_ATTRIBUTE:
pkt->pkt.user_id = cdk_calloc (1, sizeof *pkt->pkt.user_id
+ pkt->pktlen + 16 + 1);
if (!pkt->pkt.user_id)
return CDK_Out_Of_Core;
rc = read_attribute (inp, pktlen, pkt->pkt.user_id);
pkt->pkttype = CDK_PKT_ATTRIBUTE;
break;
case CDK_PKT_USER_ID:
pkt->pkt.user_id = cdk_calloc (1, sizeof *pkt->pkt.user_id
+ pkt->pktlen);
if (!pkt->pkt.user_id)
return CDK_Out_Of_Core;
rc = read_user_id (inp, pktlen, pkt->pkt.user_id);
break;
case CDK_PKT_PUBLIC_KEY:
pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
if (!pkt->pkt.public_key)
return CDK_Out_Of_Core;
rc = read_public_key (inp, pktlen, pkt->pkt.public_key);
break;
case CDK_PKT_PUBLIC_SUBKEY:
pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
if (!pkt->pkt.public_key)
return CDK_Out_Of_Core;
rc = read_public_subkey (inp, pktlen, pkt->pkt.public_key);
break;
case CDK_PKT_SECRET_KEY:
pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
if (!pkt->pkt.secret_key)
return CDK_Out_Of_Core;
pkt->pkt.secret_key->pk = cdk_calloc (1,
sizeof *pkt->pkt.secret_key->pk);
if (!pkt->pkt.secret_key->pk)
return CDK_Out_Of_Core;
rc = read_secret_key (inp, pktlen, pkt->pkt.secret_key);
break;
case CDK_PKT_SECRET_SUBKEY:
pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
if (!pkt->pkt.secret_key)
return CDK_Out_Of_Core;
pkt->pkt.secret_key->pk = cdk_calloc (1,
sizeof *pkt->pkt.secret_key->pk);
if (!pkt->pkt.secret_key->pk)
return CDK_Out_Of_Core;
rc = read_secret_subkey (inp, pktlen, pkt->pkt.secret_key);
break;
case CDK_PKT_LITERAL:
pkt->pkt.literal = cdk_calloc (1, sizeof *pkt->pkt.literal);
if (!pkt->pkt.literal)
return CDK_Out_Of_Core;
rc = read_literal (inp, pktlen, &pkt->pkt.literal, is_partial);
break;
case CDK_PKT_ONEPASS_SIG:
pkt->pkt.onepass_sig = cdk_calloc (1, sizeof *pkt->pkt.onepass_sig);
if (!pkt->pkt.onepass_sig)
return CDK_Out_Of_Core;
rc = read_onepass_sig (inp, pktlen, pkt->pkt.onepass_sig);
break;
case CDK_PKT_SIGNATURE:
pkt->pkt.signature = cdk_calloc (1, sizeof *pkt->pkt.signature);
if (!pkt->pkt.signature)
return CDK_Out_Of_Core;
rc = read_signature (inp, pktlen, pkt->pkt.signature);
break;
case CDK_PKT_ENCRYPTED_MDC:
case CDK_PKT_ENCRYPTED:
pkt->pkt.encrypted = cdk_calloc (1, sizeof *pkt->pkt.encrypted);
if (!pkt->pkt.encrypted)
return CDK_Out_Of_Core;
use_mdc = (pkt->pkttype == CDK_PKT_ENCRYPTED_MDC) ? 1 : 0;
rc = read_encrypted (inp, pktlen, pkt->pkt.encrypted,
is_partial, use_mdc);
break;
case CDK_PKT_SYMKEY_ENC:
pkt->pkt.symkey_enc = cdk_calloc (1, sizeof *pkt->pkt.symkey_enc);
if (!pkt->pkt.symkey_enc)
return CDK_Out_Of_Core;
rc = read_symkey_enc (inp, pktlen, pkt->pkt.symkey_enc);
break;
case CDK_PKT_PUBKEY_ENC:
pkt->pkt.pubkey_enc = cdk_calloc (1, sizeof *pkt->pkt.pubkey_enc);
if (!pkt->pkt.pubkey_enc)
return CDK_Out_Of_Core;
rc = read_pubkey_enc (inp, pktlen, pkt->pkt.pubkey_enc);
break;
case CDK_PKT_COMPRESSED:
pkt->pkt.compressed = cdk_calloc (1, sizeof *pkt->pkt.compressed);
if (!pkt->pkt.compressed)
return CDK_Out_Of_Core;
rc = read_compressed (inp, pktlen, pkt->pkt.compressed);
break;
case CDK_PKT_MDC:
pkt->pkt.mdc = cdk_calloc (1, sizeof *pkt->pkt.mdc);
if (!pkt->pkt.mdc)
return CDK_Out_Of_Core;
rc = read_mdc (inp, pkt->pkt.mdc);
break;
default:
/* Skip all packets we don't understand */
skip_packet (inp, pktlen);
break;
}
return rc;
}
-717
View File
@@ -1,717 +0,0 @@
/* seskey.c - Session key routines
* Copyright (C) 2002, 2003, 2007 Timo Schulz
* Copyright (C) 1998-2000, 2002 Free Software Foundation, Inc.
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <gcrypt.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
/* We encode the MD in this way:
*
* 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
*
* PAD consists of FF bytes.
*/
static cdk_error_t
do_encode_md (byte ** r_frame, size_t * r_flen, const byte * md, int algo,
size_t len, unsigned nbits, const byte * asn, size_t asnlen)
{
byte *frame = NULL;
size_t nframe = (nbits + 7) / 8;
size_t i, n = 0;
if (!asn || !md || !r_frame || !r_flen)
return CDK_Inv_Value;
if (len + asnlen + 4 > nframe)
return CDK_General_Error;
frame = cdk_calloc (1, nframe);
if (!frame)
return CDK_Out_Of_Core;
frame[n++] = 0;
frame[n++] = 1;
i = nframe - len - asnlen - 3;
if (i < 0)
{
cdk_free (frame);
return CDK_Inv_Value;
}
memset (frame + n, 0xFF, i);
n += i;
frame[n++] = 0;
memcpy (frame + n, asn, asnlen);
n += asnlen;
memcpy (frame + n, md, len);
n += len;
if (n != nframe)
{
cdk_free (frame);
return CDK_Inv_Value;
}
*r_frame = frame;
*r_flen = n;
return 0;
}
/* RFC2437 format:
*
* 0 2 RND(n bytes) 0 [A DEK(k bytes) CSUM(2 bytes)]
*
* RND - randomized bytes for padding.
* A - cipher algorithm.
* DEK - random session key.
* CKSUM - algebraic checksum of the DEK.
*/
/**
* cdk_dek_encode_pkcs1
* @dek: DEK object
* @nbits: size of the multi precision integer frame
* @r_enc: output of the encoded multiprecision integer
*
* Encode the given random session key in the DEK object
* into a multiprecision integer.
**/
cdk_error_t
cdk_dek_encode_pkcs1 (cdk_dek_t dek, size_t nbits, gcry_mpi_t * r_enc)
{
gcry_mpi_t a = NULL;
gcry_error_t err;
byte *p, *frame;
size_t n;
size_t nframe;
size_t i;
u16 chksum;
if (!r_enc || !dek)
return CDK_Inv_Value;
*r_enc = NULL;
chksum = 0;
for (i = 0; i < dek->keylen; i++)
chksum += dek->key[i];
nframe = (nbits + 7) / 8;
frame = cdk_salloc (nframe + 1, 1);
if (!frame)
return CDK_Out_Of_Core;
n = 0;
frame[n++] = 0x00;
frame[n++] = 0x02;
i = nframe - 6 - dek->keylen;
p = gcry_random_bytes (i, GCRY_STRONG_RANDOM);
/* Replace zero bytes by new values */
for (;;)
{
size_t j, k;
byte *pp;
/* count the zero bytes */
for (j = k = 0; j < i; j++)
{
if (!p[j])
k++;
}
if (!k)
break; /* No zeroes remain. */
k += k / 128; /* better get some more */
pp = gcry_random_bytes (k, GCRY_STRONG_RANDOM);
for (j = 0; j < i && k; j++)
{
if (!p[j])
p[j] = pp[--k];
}
cdk_free (pp);
}
memcpy (frame + n, p, i);
cdk_free (p);
n += i;
frame[n++] = 0;
frame[n++] = dek->algo;
memcpy (frame + n, dek->key, dek->keylen);
n += dek->keylen;
frame[n++] = chksum >> 8;
frame[n++] = chksum;
err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, nframe, &nframe);
cdk_free (frame);
if (err)
return map_gcry_error (err);
*r_enc = a;
return 0;
}
/**
* cdk_dek_decode_pkcs1:
* @ret_dek: the decoded DEK object
* @esk: the pkcs#1 encoded session key.
*
* Decode the given multi precision integer in pkcs#1 and
* store it into the DEK object.
**/
cdk_error_t
cdk_dek_decode_pkcs1 (cdk_dek_t * ret_dek, gcry_mpi_t esk)
{
cdk_dek_t dek;
byte frame[MAX_MPI_BYTES + 2 + 1];
size_t nframe, n;
u16 csum, csum2;
gcry_error_t err;
if (!ret_dek || !esk)
return CDK_Inv_Value;
*ret_dek = NULL; /* reset */
nframe = DIM (frame) - 1;
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, esk);
if (err)
return map_gcry_error (err);
dek = cdk_salloc (sizeof *dek, 1);
if (!dek)
return CDK_Out_Of_Core;
/* Now get the DEK (data encryption key) from the frame
*
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
*
* (gcry_mpi_print already removed the leading zero).
*
* RND are non-zero randow bytes.
* A is the cipher algorithm
* DEK is the encryption key (session key) with length k
* CSUM
*/
n = 0;
if (frame[n] != 2)
{
cdk_free (dek);
return CDK_Inv_Mode;
}
for (n++; n < nframe && frame[n]; n++)
;
n++;
dek->keylen = nframe - (n + 1) - 2;
dek->algo = frame[n++];
if (dek->keylen != gcry_cipher_get_algo_keylen (dek->algo))
{
_cdk_log_debug ("pkcs1 decode: invalid cipher keylen %d\n",
dek->keylen);
cdk_free (dek);
return CDK_Inv_Algo;
}
csum = frame[nframe - 2] << 8;
csum |= frame[nframe - 1];
memcpy (dek->key, frame + n, dek->keylen);
csum2 = 0;
for (n = 0; n < dek->keylen; n++)
csum2 += dek->key[n];
if (csum != csum2)
{
_cdk_log_debug ("pkcs decode: checksum does not match\n");
cdk_free (dek);
return CDK_Chksum_Error;
}
*ret_dek = dek;
return 0;
}
/* Encode the given digest into a pkcs#1 compatible format. */
cdk_error_t
_cdk_digest_encode_pkcs1 (byte ** r_md, size_t * r_mdlen, int pk_algo,
const byte * md, int digest_algo, unsigned nbits)
{
gcry_error_t err;
size_t dlen;
if (!md || !r_md || !r_mdlen)
return CDK_Inv_Value;
dlen = gcry_md_get_algo_dlen (digest_algo);
if (!dlen)
return CDK_Inv_Algo;
if (is_DSA (pk_algo)) /* DSS does not use a special encoding. */
{
*r_md = cdk_malloc (dlen + 1);
if (!*r_md)
return CDK_Out_Of_Core;
*r_mdlen = dlen;
memcpy (*r_md, md, dlen);
return 0;
}
else
{
byte *asn;
size_t asnlen;
cdk_error_t rc;
err = gcry_md_get_asnoid (digest_algo, NULL, &asnlen);
if (err)
return map_gcry_error (err);
asn = cdk_malloc (asnlen + 1);
if (!asn)
return CDK_Out_Of_Core;
err = gcry_md_get_asnoid (digest_algo, asn, &asnlen);
if (err)
{
cdk_free (asn);
return map_gcry_error (err);
}
rc = do_encode_md (r_md, r_mdlen, md, digest_algo, dlen,
nbits, asn, asnlen);
cdk_free (asn);
return rc;
}
return 0;
}
/* FIXME: The prompt should be provided in a more generic way.
Like: (keyid, algorithm, [user-id]) */
static char *
passphrase_prompt (cdk_pkt_seckey_t sk)
{
u32 keyid = cdk_pk_get_keyid (sk->pk, NULL);
int bits = cdk_pk_get_nbits (sk->pk), pk_algo = sk->pubkey_algo;
const char *algo = "???", *fmt;
char *p;
if (is_RSA (pk_algo))
algo = "RSA";
else if (is_ELG (pk_algo))
algo = "ELG";
else if (is_DSA (pk_algo))
algo = "DSA";
fmt = "%d-bit %s key, ID %08lX\nEnter Passphrase: ";
p = cdk_calloc (1, 64 + strlen (fmt) + strlen (algo) + 1);
if (!p)
return NULL;
sprintf (p, fmt, bits, algo, keyid);
return p;
}
/* Try to unprotect the secret key, if needed, automatically.
The passphrase callback is used to get the passphrase directly
from the user. */
cdk_error_t
_cdk_sk_unprotect_auto (cdk_ctx_t hd, cdk_pkt_seckey_t sk)
{
char *pw, *p;
cdk_error_t rc;
if (!sk->is_protected)
return 0;
p = passphrase_prompt (sk);
pw = _cdk_passphrase_get (hd, p);
cdk_free (p);
if (!pw)
return CDK_No_Passphrase;
rc = cdk_sk_unprotect (sk, pw);
wipemem (pw, strlen (pw));
cdk_free (pw);
return rc;
}
/**
* cdk_dek_extract:
* @ret_dek: the raw DEK object
* @hd: the session handle
* @enc: the public key encrypted packet
* @sk: the secret key.
*
* Try to extract the DEK from the public key encrypted packet.
**/
cdk_error_t
cdk_dek_extract (cdk_dek_t * ret_dek, cdk_ctx_t hd,
cdk_pkt_pubkey_enc_t enc, cdk_pkt_seckey_t sk)
{
gcry_mpi_t skey = NULL;
cdk_dek_t dek;
cdk_error_t rc;
if (!enc || !sk || !ret_dek)
return CDK_Inv_Value;
/* FIXME: it is not very elegant that we need the session handle here. */
if (sk->is_protected)
{
rc = _cdk_sk_unprotect_auto (hd, sk);
if (rc)
return rc;
}
rc = cdk_pk_decrypt (sk, enc, &skey);
if (rc)
return rc;
rc = cdk_dek_decode_pkcs1 (&dek, skey);
gcry_mpi_release (skey);
if (rc)
{
cdk_dek_free (dek);
dek = NULL;
}
*ret_dek = dek;
return rc;
}
/**
* cdk_dek_new:
* @r_dek: the new DEK object
*
* Create a new DEK object.
**/
cdk_error_t
cdk_dek_new (cdk_dek_t * r_dek)
{
cdk_dek_t dek;
if (!r_dek)
return CDK_Inv_Value;
*r_dek = NULL;
dek = cdk_salloc (sizeof *dek, 1);
if (!dek)
return CDK_Out_Of_Core;
*r_dek = dek;
return 0;
}
/**
* cdk_dek_set_cipher:
* @dek: the DEK object
* @algo: the cipher algorithm to use
*
* Set the cipher for the given DEK object.
**/
cdk_error_t
cdk_dek_set_cipher (cdk_dek_t dek, int algo)
{
if (!dek)
return CDK_Inv_Value;
if (!algo)
algo = GCRY_CIPHER_AES128;
if (gcry_cipher_test_algo (algo))
return CDK_Inv_Algo;
dek->algo = algo;
dek->keylen = gcry_cipher_get_algo_keylen (dek->algo);
return 0;
}
cdk_error_t
cdk_dek_get_cipher (cdk_dek_t dek, int *r_algo)
{
if (!dek || !r_algo)
return CDK_Inv_Value;
*r_algo = dek->algo;
return 0;
}
/**
* cdk_dek_set_key:
* @dek: the DEK object
* @key: the random session key
* @keylen: the length of the session key.
*
* Set the random session key for the given DEK object.
* If @key and @keylen is NULL (0) a random key will be generated.
* In any case, cdk_dek_set_cipher must be called first.
**/
cdk_error_t
cdk_dek_set_key (cdk_dek_t dek, const byte * key, size_t keylen)
{
gcry_cipher_hd_t hd;
size_t i;
if (!dek)
return CDK_Inv_Value;
/* The given key must be compatible with the symmetric
cipher algorithm set before. */
if (keylen > 0 && keylen != dek->keylen)
return CDK_Inv_Mode;
if (!key && !keylen)
{
gcry_error_t err;
/* Used to generate a random session key. The extra code is used
to detect weak keys, if they are possible at all. */
err = gcry_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB,
GCRY_CIPHER_ENABLE_SYNC);
if (err)
return map_gcry_error (err);
gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM);
for (i = 0; i < 8; i++)
{
if (!gcry_cipher_setkey (hd, dek->key, dek->keylen))
{
gcry_cipher_close (hd);
return 0;
}
gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM);
}
gcry_cipher_close (hd);
return CDK_Weak_Key;
}
memcpy (dek->key, key, dek->keylen);
return 0;
}
/**
* cdk_dek_set_mdc_flag:
* @dek: the DEK object
* @val: value to enable or disable the use
*
* Enable or disable the MDC flag for the given DEK object.
**/
void
cdk_dek_set_mdc_flag (cdk_dek_t dek, int val)
{
if (dek)
dek->use_mdc = val;
}
int
cdk_dek_get_mdc_flag (cdk_dek_t dek)
{
if (!dek)
return 0;
return dek->use_mdc;
}
/**
* cdk_dek_free:
* @dek: the DEK object
*
* Release the DEK object.
**/
void
cdk_dek_free (cdk_dek_t dek)
{
if (!dek)
return;
/* Make sure sentensive data is overwritten. */
wipemem (dek->key, sizeof (dek->key));
cdk_free (dek);
}
/* Hash the passphrase to produce the a DEK.
If create is set, a random salt will be generated. */
static cdk_error_t
hash_passphrase (cdk_dek_t dek, const char *pw, cdk_s2k_t s2k, int create)
{
gcry_md_hd_t md;
byte zero[1] = { 0x00 };
int pass, i;
int used = 0, pwlen;
gcry_error_t err;
if (!dek || !pw || !s2k)
return CDK_Inv_Value;
if (!s2k->hash_algo)
s2k->hash_algo = GCRY_MD_SHA1;
pwlen = strlen (pw);
dek->keylen = gcry_cipher_get_algo_keylen (dek->algo);
err = gcry_md_open (&md, s2k->hash_algo, 0);
if (err)
return map_gcry_error (err);
for (pass = 0; used < dek->keylen; pass++)
{
if (pass)
{
gcry_md_reset (md);
for (i = 0; i < pass; i++) /* preset the hash context */
gcry_md_write (md, zero, 1);
}
if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
{
int len2 = pwlen + 8;
u32 count = len2;
if (create && !pass)
{
gcry_randomize (s2k->salt, 8, GCRY_STRONG_RANDOM);
if (s2k->mode == 3)
s2k->count = 96; /* 65536 iterations */
}
if (s2k->mode == 3)
{
count = (16ul + (s2k->count & 15)) << ((s2k->count >> 4) + 6);
if (count < len2)
count = len2;
}
/* a little bit complicated because we need a ulong for count */
while (count > len2)
{ /* maybe iterated+salted */
gcry_md_write (md, s2k->salt, 8);
gcry_md_write (md, pw, pwlen);
count -= len2;
}
if (count < 8)
gcry_md_write (md, s2k->salt, count);
else
{
gcry_md_write (md, s2k->salt, 8);
count -= 8;
gcry_md_write (md, pw, count);
}
}
else
gcry_md_write (md, pw, pwlen);
gcry_md_final (md);
i = gcry_md_get_algo_dlen (s2k->hash_algo);
if (i > dek->keylen - used)
i = dek->keylen - used;
memcpy (dek->key + used, gcry_md_read (md, s2k->hash_algo), i);
used += i;
}
gcry_md_close (md);
return 0;
}
/**
* cdk_dek_from_passphrase:
* @ret_dek: the new DEK.
* @cipher_algo: symmetric key algorithm to use
* @s2k: the S2K to use
* @rndsalt: 1=create random salt
* @pw: the passphrase.
*
* Transform a passphrase into a DEK object.
*/
cdk_error_t
cdk_dek_from_passphrase (cdk_dek_t * ret_dek, int cipher_algo, cdk_s2k_t s2k,
int rndsalt, const char *pw)
{
cdk_dek_t dek;
cdk_error_t rc;
if (!ret_dek)
return CDK_Inv_Value;
*ret_dek = NULL;
rc = cdk_dek_new (&dek);
if (rc)
return rc;
rc = cdk_dek_set_cipher (dek, cipher_algo);
if (!rc)
rc = hash_passphrase (dek, pw, s2k, rndsalt);
if (rc)
{
cdk_dek_free (dek);
return rc;
}
*ret_dek = dek;
return 0;
}
/**
* cdk_s2k_new:
* @ret_s2k: output for the new S2K object
* @mode: the S2K mode (simple, salted, iter+salted)
* @digest_algo: the hash algorithm
* @salt: random salt
*
* Create a new S2K object with the given parameter.
* The @salt parameter must be always 8 octets.
**/
cdk_error_t
cdk_s2k_new (cdk_s2k_t * ret_s2k, int mode, int digest_algo,
const byte * salt)
{
cdk_s2k_t s2k;
if (!ret_s2k)
return CDK_Inv_Value;
if (mode != 0x00 && mode != 0x01 && mode != 0x03)
return CDK_Inv_Mode;
if (gcry_md_test_algo (digest_algo))
return CDK_Inv_Algo;
s2k = cdk_calloc (1, sizeof *s2k);
if (!s2k)
return CDK_Out_Of_Core;
s2k->mode = mode;
s2k->hash_algo = digest_algo;
if (salt)
memcpy (s2k->salt, salt, 8);
*ret_s2k = s2k;
return 0;
}
/**
* cdk_s2k_free:
* @s2k: the S2K object
*
* Release the given S2K object.
**/
void
cdk_s2k_free (cdk_s2k_t s2k)
{
cdk_free (s2k);
}
/* Make a copy of the source s2k into R_DST. */
cdk_error_t
_cdk_s2k_copy (cdk_s2k_t * r_dst, cdk_s2k_t src)
{
cdk_s2k_t dst;
cdk_error_t err;
err = cdk_s2k_new (&dst, src->mode, src->hash_algo, src->salt);
if (err)
return err;
dst->count = src->count;
*r_dst = dst;
return 0;
}
-489
View File
@@ -1,489 +0,0 @@
/* sig-check.c - Check signatures
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
* Copyright (C) 1998-2002 Free Software Foundation, Inc.
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <time.h>
#include <gcrypt.h>
#include <assert.h>
#include "opencdk.h"
#include "main.h"
#include "packet.h"
/* Hash all multi precision integers of the key PK with the given
message digest context MD. */
static int
hash_mpibuf (cdk_pubkey_t pk, gcry_md_hd_t md, int usefpr)
{
byte buf[MAX_MPI_BYTES]; /* FIXME: do not use hardcoded length. */
size_t nbytes;
size_t i, npkey;
gcry_error_t err;
/* We have to differ between two modes for v3 keys. To form the
fingerprint, we hash the MPI values without the length prefix.
But if we calculate the hash for verifying/signing we use all data. */
npkey = cdk_pk_get_npkey (pk->pubkey_algo);
for (i = 0; i < npkey; i++)
{
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buf, MAX_MPI_BYTES,
&nbytes, pk->mpi[i]);
if (err)
return map_gcry_error (err);
if (!usefpr || pk->version == 4)
gcry_md_write (md, buf, nbytes);
else /* without the prefix. */
gcry_md_write (md, buf + 2, nbytes - 2);
}
return 0;
}
/* Hash an entire public key PK with the given message digest context
MD. The @usefpr param is only valid for version 3 keys because of
the different way to calculate the fingerprint. */
cdk_error_t
_cdk_hash_pubkey (cdk_pubkey_t pk, gcry_md_hd_t md, int usefpr)
{
byte buf[12];
size_t i, n, npkey;
if (!pk || !md)
return CDK_Inv_Value;
if (usefpr && pk->version < 4 && is_RSA (pk->pubkey_algo))
return hash_mpibuf (pk, md, 1);
/* The version 4 public key packet does not have the 2 octets for
the expiration date. */
n = pk->version < 4 ? 8 : 6;
npkey = cdk_pk_get_npkey (pk->pubkey_algo);
for (i = 0; i < npkey; i++)
n = n + (gcry_mpi_get_nbits (pk->mpi[i]) + 7) / 8 + 2;
i = 0;
buf[i++] = 0x99;
buf[i++] = n >> 8;
buf[i++] = n >> 0;
buf[i++] = pk->version;
buf[i++] = pk->timestamp >> 24;
buf[i++] = pk->timestamp >> 16;
buf[i++] = pk->timestamp >> 8;
buf[i++] = pk->timestamp >> 0;
if (pk->version < 4)
{
u16 a = 0;
/* Convert the expiration date into days. */
if (pk->expiredate)
a = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
buf[i++] = a >> 8;
buf[i++] = a;
}
buf[i++] = pk->pubkey_algo;
gcry_md_write (md, buf, i);
return hash_mpibuf (pk, md, 0);
}
/* Hash the user ID @uid with the given message digest @md.
Use openpgp mode if @is_v4 is 1. */
cdk_error_t
_cdk_hash_userid (cdk_pkt_userid_t uid, int is_v4, gcry_md_hd_t md)
{
const byte *data;
byte buf[5];
u32 dlen;
if (!uid || !md)
return CDK_Inv_Value;
if (!is_v4)
{
gcry_md_write (md, (byte *) uid->name, uid->len);
return 0;
}
dlen = uid->attrib_img ? uid->attrib_len : uid->len;
data = uid->attrib_img ? uid->attrib_img : (byte *) uid->name;
buf[0] = uid->attrib_img ? 0xD1 : 0xB4;
buf[1] = dlen >> 24;
buf[2] = dlen >> 16;
buf[3] = dlen >> 8;
buf[4] = dlen >> 0;
gcry_md_write (md, buf, 5);
gcry_md_write (md, data, dlen);
return 0;
}
/* Hash all parts of the signature which are needed to derive
the correct message digest to verify the sig. */
cdk_error_t
_cdk_hash_sig_data (cdk_pkt_signature_t sig, gcry_md_hd_t md)
{
byte buf[4];
if (!sig || !md)
return CDK_Inv_Value;
if (sig->version == 4)
gcry_md_putc (md, sig->version);
gcry_md_putc (md, sig->sig_class);
if (sig->version < 4)
{
buf[0] = sig->timestamp >> 24;
buf[1] = sig->timestamp >> 16;
buf[2] = sig->timestamp >> 8;
buf[3] = sig->timestamp >> 0;
gcry_md_write (md, buf, 4);
}
else
{
size_t n;
gcry_md_putc (md, sig->pubkey_algo);
gcry_md_putc (md, sig->digest_algo);
if (sig->hashed != NULL)
{
byte *p = _cdk_subpkt_get_array (sig->hashed, 0, &n);
assert (p != NULL);
buf[0] = n >> 8;
buf[1] = n >> 0;
gcry_md_write (md, buf, 2);
gcry_md_write (md, p, n);
cdk_free (p);
sig->hashed_size = n;
n = sig->hashed_size + 6;
}
else
{
gcry_md_putc (md, 0x00);
gcry_md_putc (md, 0x00);
n = 6;
}
gcry_md_putc (md, sig->version);
gcry_md_putc (md, 0xFF);
buf[0] = n >> 24;
buf[1] = n >> 16;
buf[2] = n >> 8;
buf[3] = n >> 0;
gcry_md_write (md, buf, 4);
}
return 0;
}
/* Cache the signature result and store it inside the sig. */
static void
cache_sig_result (cdk_pkt_signature_t sig, int res)
{
sig->flags.checked = 0;
sig->flags.valid = 0;
if (res == 0)
{
sig->flags.checked = 1;
sig->flags.valid = 1;
}
else if (res == CDK_Bad_Sig)
{
sig->flags.checked = 1;
sig->flags.valid = 0;
}
}
/* Check the given signature @sig with the public key @pk.
Use the digest handle @digest. */
cdk_error_t
_cdk_sig_check (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
gcry_md_hd_t digest, int *r_expired)
{
cdk_error_t rc;
byte md[MAX_DIGEST_LEN];
time_t cur_time = (u32) time (NULL);
if (!pk || !sig || !digest)
return CDK_Inv_Value;
if (sig->flags.checked)
return sig->flags.valid ? 0 : CDK_Bad_Sig;
if (!KEY_CAN_SIGN (pk->pubkey_algo))
return CDK_Inv_Algo;
if (pk->timestamp > sig->timestamp || pk->timestamp > cur_time)
return CDK_Time_Conflict;
if (r_expired && pk->expiredate
&& (pk->expiredate + pk->timestamp) > cur_time)
*r_expired = 1;
_cdk_hash_sig_data (sig, digest);
gcry_md_final (digest);
memcpy (md, gcry_md_read (digest, sig->digest_algo),
gcry_md_get_algo_dlen (sig->digest_algo));
if (md[0] != sig->digest_start[0] || md[1] != sig->digest_start[1])
return CDK_Chksum_Error;
rc = cdk_pk_verify (pk, sig, md);
cache_sig_result (sig, rc);
return rc;
}
/* Check the given key signature.
@knode is the key node and @snode the signature node. */
cdk_error_t
_cdk_pk_check_sig (cdk_keydb_hd_t keydb,
cdk_kbnode_t knode, cdk_kbnode_t snode, int *is_selfsig)
{
gcry_md_hd_t md;
gcry_error_t err;
cdk_pubkey_t pk;
cdk_pkt_signature_t sig;
cdk_kbnode_t node;
cdk_error_t rc = 0;
int is_expired;
if (!knode || !snode)
return CDK_Inv_Value;
if (is_selfsig)
*is_selfsig = 0;
if (knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY ||
snode->pkt->pkttype != CDK_PKT_SIGNATURE)
return CDK_Inv_Value;
pk = knode->pkt->pkt.public_key;
sig = snode->pkt->pkt.signature;
err = gcry_md_open (&md, sig->digest_algo, 0);
if (err)
return map_gcry_error (err);
is_expired = 0;
if (sig->sig_class == 0x20)
{ /* key revocation */
cdk_kbnode_hash (knode, md, 0, 0, 0);
rc = _cdk_sig_check (pk, sig, md, &is_expired);
}
else if (sig->sig_class == 0x28)
{ /* subkey revocation */
node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
if (!node)
{ /* no subkey for subkey revocation packet */
rc = CDK_Error_No_Key;
goto fail;
}
cdk_kbnode_hash (knode, md, 0, 0, 0);
cdk_kbnode_hash (node, md, 0, 0, 0);
rc = _cdk_sig_check (pk, sig, md, &is_expired);
}
else if (sig->sig_class == 0x18 || sig->sig_class == 0x19)
{ /* primary/secondary key binding */
node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
if (!node)
{ /* no subkey for subkey binding packet */
rc = CDK_Error_No_Key;
goto fail;
}
cdk_kbnode_hash (knode, md, 0, 0, 0);
cdk_kbnode_hash (node, md, 0, 0, 0);
rc = _cdk_sig_check (pk, sig, md, &is_expired);
}
else if (sig->sig_class == 0x1F)
{ /* direct key signature */
cdk_kbnode_hash (knode, md, 0, 0, 0);
rc = _cdk_sig_check (pk, sig, md, &is_expired);
}
else
{ /* all other classes */
node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_USER_ID);
if (!node)
{ /* no user ID for key signature packet */
rc = CDK_Error_No_Key;
goto fail;
}
cdk_kbnode_hash (knode, md, 0, 0, 0);
cdk_kbnode_hash (node, md, sig->version == 4, 0, 0);
if (pk->keyid[0] == sig->keyid[0] && pk->keyid[1] == sig->keyid[1])
{
rc = _cdk_sig_check (pk, sig, md, &is_expired);
if (is_selfsig)
*is_selfsig = 1;
}
else if (keydb != NULL)
{
cdk_pubkey_t sig_pk;
rc = cdk_keydb_get_pk (keydb, sig->keyid, &sig_pk);
if (!rc)
rc = _cdk_sig_check (sig_pk, sig, md, &is_expired);
cdk_pk_release (sig_pk);
}
}
fail:
gcry_md_close (md);
return rc;
}
/**
* cdk_pk_check_sigs:
* @key: the public key
* @hd: an optinal key database handle
* @r_status: variable to store the status of the key
*
* Check all signatures. When no key is available for checking, the
* sigstat is marked as 'NOKEY'. The @r_status contains the key flags
* which are or-ed or zero when there are no flags.
**/
cdk_error_t
cdk_pk_check_sigs (cdk_kbnode_t key, cdk_keydb_hd_t keydb, int *r_status)
{
cdk_pkt_signature_t sig;
cdk_kbnode_t node;
cdk_error_t rc;
u32 keyid;
int key_status, is_selfsig = 0;
int no_signer, n_sigs = 0;
if (!key || !r_status)
return CDK_Inv_Value;
*r_status = 0;
node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
if (!node)
return CDK_Error_No_Key;
key_status = 0;
/* Continue with the signature check but adjust the
key status flags accordingly. */
if (node->pkt->pkt.public_key->is_revoked)
key_status |= CDK_KEY_REVOKED;
if (node->pkt->pkt.public_key->has_expired)
key_status |= CDK_KEY_EXPIRED;
rc = 0;
no_signer = 0;
keyid = cdk_pk_get_keyid (node->pkt->pkt.public_key, NULL);
for (node = key; node; node = node->next)
{
if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
continue;
sig = node->pkt->pkt.signature;
rc = _cdk_pk_check_sig (keydb, key, node, &is_selfsig);
if (IS_UID_SIG (sig))
{
if (is_selfsig == 0)
n_sigs++;
}
if (rc && IS_UID_SIG (sig) && rc == CDK_Error_No_Key)
{
/* We do not consider it a problem when the signing key
is not avaiable. We just mark the signature accordingly
and contine. */
sig->flags.missing_key = 1;
no_signer++;
}
else if (rc && rc != CDK_Error_No_Key)
{
/* It might be possible that a single signature has been
corrupted, thus we do not consider it a problem when
one ore more signatures are bad. But at least the self
signature has to be valid. */
if (is_selfsig)
{
key_status |= CDK_KEY_INVALID;
break;
}
}
_cdk_log_debug ("signature %s: signer %08lX keyid %08lX\n",
rc == CDK_Bad_Sig ? "BAD" : "good", sig->keyid[1],
keyid);
}
if (n_sigs == no_signer)
key_status |= CDK_KEY_NOSIGNER;
*r_status = key_status;
if (rc == CDK_Error_No_Key)
rc = 0;
return rc;
}
/**
* cdk_pk_check_self_sig:
* @key: the key node
* @r_status: output the status of the key.
*
* A convenient function to make sure the key is valid.
* Valid means the self signature is ok.
**/
cdk_error_t
cdk_pk_check_self_sig (cdk_kbnode_t key, int *r_status)
{
cdk_pkt_signature_t sig;
cdk_kbnode_t node;
cdk_error_t rc;
u32 keyid[2], sigid[2];
int is_selfsig, sig_ok;
if (!key || !r_status)
return CDK_Inv_Value;
node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
if (!node)
return CDK_Error_No_Key;
/* FIXME: we should set expire/revoke here also but callers
expect CDK_KEY_VALID=0 if the key is okay. */
cdk_pk_get_keyid (key->pkt->pkt.public_key, keyid);
sig_ok = 0;
for (node = key; node; node = node->next)
{
if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
continue;
sig = node->pkt->pkt.signature;
if (!IS_UID_SIG (sig))
continue;
cdk_sig_get_keyid (sig, sigid);
if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
continue;
/* FIXME: Now we check all self signatures. */
rc = _cdk_pk_check_sig (NULL, key, node, &is_selfsig);
if (rc)
{
*r_status = CDK_KEY_INVALID;
return rc;
}
else /* For each valid self sig we increase this counter. */
sig_ok++;
}
/* A key without a self signature is not valid. */
if (!sig_ok)
{
*r_status = CDK_KEY_INVALID;
return CDK_General_Error;
}
/* No flags indicate a valid key. */
*r_status = CDK_KEY_VALID;
return 0;
}
-1446
View File
@@ -1,1446 +0,0 @@
/* stream.c - The stream implementation
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "opencdk.h"
#include "main.h"
#include "filters.h"
#include "stream.h"
#include "types.h"
/* This is the maximal amount of bytes we map. */
#define MAX_MAP_SIZE 16777216
static int stream_flush (cdk_stream_t s);
static int stream_filter_write (cdk_stream_t s);
static int stream_cache_flush (cdk_stream_t s, FILE * fp);
/* Customized tmpfile() version from misc.c */
FILE *my_tmpfile (void);
/* FIXME: The read/write/putc/getc function cannot directly
return an error code. It is stored in an error variable
inside the string. Right now there is no code to
return the error code or to reset it. */
/**
* cdk_stream_open:
* @file: The file to open
* @ret_s: The new STREAM object
*
* Create a new stream based on an existing file. The stream is
* opened in read-only mode.
**/
cdk_error_t
cdk_stream_open (const char *file, cdk_stream_t * ret_s)
{
return _cdk_stream_open_mode (file, "rb", ret_s);
}
/* Helper function to allow to open a stream in different modes. */
cdk_error_t
_cdk_stream_open_mode (const char *file, const char *mode,
cdk_stream_t * ret_s)
{
cdk_stream_t s;
if (!file || !ret_s)
return CDK_Inv_Value;
_cdk_log_debug ("open stream `%s'\n", file);
*ret_s = NULL;
s = cdk_calloc (1, sizeof *s);
if (!s)
return CDK_Out_Of_Core;
s->fname = cdk_strdup (file);
if (!s->fname)
{
cdk_free (s);
return CDK_Out_Of_Core;
}
s->fp = fopen (file, mode);
if (!s->fp)
{
cdk_free (s->fname);
cdk_free (s);
return CDK_File_Error;
}
_cdk_log_debug ("open stream fd=%d\n", fileno (s->fp));
s->flags.write = 0;
*ret_s = s;
return 0;
}
/**
* cdk_stream_new_from_cbs:
* @cbs: the callback context with all user callback functions
* @opa: opaque handle which is passed to all callbacks.
* @ret_s: the allocated stream
*
* This function creates a stream which uses user callback
* for the core operations (open, close, read, write, seek).
*/
cdk_error_t
cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa,
cdk_stream_t * ret_s)
{
cdk_stream_t s;
if (!cbs || !opa || !ret_s)
return CDK_Inv_Value;
*ret_s = NULL;
s = cdk_calloc (1, sizeof *s);
if (!s)
return CDK_Out_Of_Core;
s->cbs.read = cbs->read;
s->cbs.write = cbs->write;
s->cbs.seek = cbs->seek;
s->cbs.release = cbs->release;
s->cbs.open = cbs->open;
s->cbs_hd = opa;
*ret_s = s;
/* If there is a user callback for open, we need to call it
here because read/write expects an open stream. */
if (s->cbs.open)
return s->cbs.open (s->cbs_hd);
return 0;
}
/**
* cdk_stream_new: Create a new stream into into the given file.
* @file: The name of the new file
* @ret_s: The new STREAM object
**/
cdk_error_t
cdk_stream_new (const char *file, cdk_stream_t * ret_s)
{
cdk_stream_t s;
if (!ret_s)
return CDK_Inv_Value;
_cdk_log_debug ("new stream `%s'\n", file ? file : "[temp]");
*ret_s = NULL;
s = cdk_calloc (1, sizeof *s);
if (!s)
return CDK_Out_Of_Core;
s->flags.write = 1;
if (!file)
s->flags.temp = 1;
else
{
s->fname = cdk_strdup (file);
if (!s->fname)
{
cdk_free (s);
return CDK_Out_Of_Core;
}
}
s->fp = my_tmpfile ();
if (!s->fp)
{
cdk_free (s->fname);
cdk_free (s);
return CDK_File_Error;
}
_cdk_log_debug ("new stream fd=%d\n", fileno (s->fp));
*ret_s = s;
return 0;
}
/**
* cdk_stream_create: create a new stream.
* @file: the filename
* @ret_s: the object
*
* The difference to cdk_stream_new is, that no filtering can be used with
* this kind of stream and everything is written directly to the stream.
**/
cdk_error_t
cdk_stream_create (const char *file, cdk_stream_t * ret_s)
{
cdk_stream_t s;
if (!file || !ret_s)
return CDK_Inv_Value;
_cdk_log_debug ("create stream `%s'\n", file);
*ret_s = NULL;
s = cdk_calloc (1, sizeof *s);
if (!s)
return CDK_Out_Of_Core;
s->flags.write = 1;
s->flags.filtrated = 1;
s->fname = cdk_strdup (file);
if (!s->fname)
{
cdk_free (s);
return CDK_Out_Of_Core;
}
s->fp = fopen (file, "w+b");
if (!s->fp)
{
cdk_free (s->fname);
cdk_free (s);
return CDK_File_Error;
}
_cdk_log_debug ("stream create fd=%d\n", fileno (s->fp));
*ret_s = s;
return 0;
}
/**
* cdk_stream_tmp_new:
* @r_out: the new temp stream.
*
* Allocate a new tempory stream which is not associated with a file.
*/
cdk_error_t
cdk_stream_tmp_new (cdk_stream_t * r_out)
{
return cdk_stream_new (NULL, r_out);
}
/**
* cdk_stream_tmp_from_mem:
* @buf: the buffer which shall be written to the temp stream.
* @buflen: how large the buffer is
* @r_out: the new stream with the given contents.
*
* Create a new tempory stream with the given contests.
*/
cdk_error_t
cdk_stream_tmp_from_mem (const void *buf, size_t buflen, cdk_stream_t * r_out)
{
cdk_stream_t s;
cdk_error_t rc;
int nwritten;
*r_out = NULL;
rc = cdk_stream_tmp_new (&s);
if (rc)
return rc;
nwritten = cdk_stream_write (s, buf, buflen);
if (nwritten == EOF)
{
cdk_stream_close (s);
return s->error;
}
cdk_stream_seek (s, 0);
*r_out = s;
return 0;
}
cdk_error_t
_cdk_stream_fpopen (FILE * fp, unsigned write_mode, cdk_stream_t * ret_out)
{
cdk_stream_t s;
*ret_out = NULL;
s = cdk_calloc (1, sizeof *s);
if (!s)
return CDK_Out_Of_Core;
_cdk_log_debug ("stream ref fd=%d\n", fileno (fp));
s->fp = fp;
s->fp_ref = 1;
s->flags.filtrated = 1;
s->flags.write = write_mode;
*ret_out = s;
return 0;
}
cdk_error_t
_cdk_stream_append (const char *file, cdk_stream_t * ret_s)
{
cdk_stream_t s;
cdk_error_t rc;
if (!ret_s)
return CDK_Inv_Value;
*ret_s = NULL;
rc = _cdk_stream_open_mode (file, "a+b", &s);
if (rc)
return rc;
/* In the append mode, we need to write to the flag. */
s->flags.write = 1;
*ret_s = s;
return 0;
}
/**
* cdk_stream_is_compressed:
* @s: the stream
*
* Return 0 if the stream is uncompressed, otherwise the
* compression algorithm.
*/
int
cdk_stream_is_compressed (cdk_stream_t s)
{
if (!s)
return 0;
return s->flags.compressed;
}
void
_cdk_stream_set_compress_algo (cdk_stream_t s, int algo)
{
if (!s)
return;
s->flags.compressed = algo;
}
cdk_error_t
cdk_stream_flush (cdk_stream_t s)
{
cdk_error_t rc;
if (!s)
return CDK_Inv_Value;
/* The user callback does not support flush */
if (s->cbs_hd)
return 0;
/* For read-only streams, no flush is needed. */
if (!s->flags.write)
return 0;
if (!s->flags.filtrated)
{
if (!cdk_stream_get_length (s))
return 0;
rc = cdk_stream_seek (s, 0);
if (!rc)
rc = stream_flush (s);
if (!rc)
rc = stream_filter_write (s);
s->flags.filtrated = 1;
if (rc)
{
s->error = rc;
return rc;
}
}
return 0;
}
void
cdk_stream_tmp_set_mode (cdk_stream_t s, int val)
{
if (s && s->flags.temp)
s->fmode = val;
}
/**
* cdk_stream_close: Close a stream and flush all buffers.
* @s: The STREAM object.
*
* This function work different for read or write streams. When the
* stream is for reading, the filtering is already done and we can
* simply close the file and all buffers.
* But for the case it's a write stream, we need to apply all registered
* filters now. The file is closed in the filter function and not here.
**/
cdk_error_t
cdk_stream_close (cdk_stream_t s)
{
struct stream_filter_s *f, *f2;
cdk_error_t rc;
if (!s)
return CDK_Inv_Value;
_cdk_log_debug ("close stream ref=%d `%s'\n",
s->fp_ref, s->fname ? s->fname : "[temp]");
/* In the user callback mode, we call the release cb if possible
and just free the stream. */
if (s->cbs_hd)
{
if (s->cbs.release)
rc = s->cbs.release (s->cbs_hd);
else
rc = 0;
cdk_free (s);
return rc;
}
rc = 0;
if (!s->flags.filtrated && !s->error)
rc = cdk_stream_flush (s);
if (!s->fp_ref && (s->fname || s->flags.temp))
{
int err;
_cdk_log_debug ("close stream fd=%d\n", fileno (s->fp));
err = fclose (s->fp);
s->fp = NULL;
if (err)
rc = CDK_File_Error;
}
/* Iterate over the filter list and use the cleanup flag to
free the allocated internal structures. */
f = s->filters;
while (f)
{
f2 = f->next;
if (f->fnct)
f->fnct (f->opaque, STREAMCTL_FREE, NULL, NULL);
cdk_free (f);
f = f2;
}
if (s->fname)
{
cdk_free (s->fname);
s->fname = NULL;
}
cdk_free (s->cache.buf);
s->cache.alloced = 0;
cdk_free (s);
return rc;
}
/**
* cdk_stream_eof: Return if the associated file handle was set to EOF.
* @s: The STREAM object.
*
* This function will only work with read streams.
**/
int
cdk_stream_eof (cdk_stream_t s)
{
return s ? s->flags.eof : -1;
}
const char *
_cdk_stream_get_fname (cdk_stream_t s)
{
if (!s)
return NULL;
if (s->flags.temp)
return NULL;
return s->fname ? s->fname : NULL;
}
/* Return the underlying FP of the stream.
WARNING: This handle should not be closed. */
FILE *
_cdk_stream_get_fp (cdk_stream_t s)
{
return s ? s->fp : NULL;
}
int
_cdk_stream_get_errno (cdk_stream_t s)
{
return s ? s->error : CDK_Inv_Value;
}
/**
* cdk_stream_get_length: Return the length of the associated file handle.
* @s: The STREAM object.
*
* This function should work for both read and write streams. For write
* streams an additional flush is used to write possible pending data.
**/
off_t
cdk_stream_get_length (cdk_stream_t s)
{
struct stat statbuf;
cdk_error_t rc;
if (!s)
return (off_t) - 1;
/* The user callback does not support stat. */
if (s->cbs_hd)
return 0;
rc = stream_flush (s);
if (rc)
{
s->error = rc;
return (off_t) - 1;
}
if (fstat (fileno (s->fp), &statbuf))
{
s->error = CDK_File_Error;
return (off_t) - 1;
}
return statbuf.st_size;
}
static struct stream_filter_s *
filter_add2 (cdk_stream_t s)
{
struct stream_filter_s *f;
assert (s);
f = cdk_calloc (1, sizeof *f);
if (!f)
return NULL;
f->next = s->filters;
s->filters = f;
return f;
}
static struct stream_filter_s *
filter_search (cdk_stream_t s, filter_fnct_t fnc)
{
struct stream_filter_s *f;
assert (s);
for (f = s->filters; f; f = f->next)
{
if (f->fnct == fnc)
return f;
}
return NULL;
}
struct stream_filter_s *
filter_add (cdk_stream_t s, filter_fnct_t fnc, int type)
{
struct stream_filter_s *f;
assert (s);
s->flags.filtrated = 0;
f = filter_search (s, fnc);
if (f)
return f;
f = filter_add2 (s);
if (!f)
return NULL;
f->fnct = fnc;
f->flags.enabled = 1;
f->tmp = NULL;
f->type = type;
switch (type)
{
case fARMOR:
f->opaque = &f->u.afx;
break;
case fCIPHER:
f->opaque = &f->u.cfx;
break;
case fLITERAL:
f->opaque = &f->u.pfx;
break;
case fCOMPRESS:
f->opaque = &f->u.zfx;
break;
case fHASH:
f->opaque = &f->u.mfx;
break;
case fTEXT:
f->opaque = &f->u.tfx;
break;
default:
f->opaque = NULL;
}
return f;
}
static int
stream_get_mode (cdk_stream_t s)
{
assert (s);
if (s->flags.temp)
return s->fmode;
return s->flags.write;
}
static filter_fnct_t
stream_id_to_filter (int type)
{
switch (type)
{
case fARMOR:
return _cdk_filter_armor;
case fLITERAL:
return _cdk_filter_literal;
case fTEXT:
return _cdk_filter_text;
case fCIPHER:
return _cdk_filter_cipher;
case fCOMPRESS:
return _cdk_filter_compress;
default:
return NULL;
}
}
/**
* cdk_stream_filter_disable: Disable the filter with the type 'type'
* @s: The STREAM object
* @type: The numberic filter ID.
*
**/
cdk_error_t
cdk_stream_filter_disable (cdk_stream_t s, int type)
{
struct stream_filter_s *f;
filter_fnct_t fnc;
if (!s)
return CDK_Inv_Value;
fnc = stream_id_to_filter (type);
if (!fnc)
return CDK_Inv_Value;
f = filter_search (s, fnc);
if (f)
f->flags.enabled = 0;
return 0;
}
/* WARNING: tmp should not be closed by the caller. */
static cdk_error_t
stream_fp_replace (cdk_stream_t s, FILE ** tmp)
{
int rc;
assert (s);
_cdk_log_debug ("replace stream fd=%d with fd=%d\n",
fileno (s->fp), fileno (*tmp));
rc = fclose (s->fp);
if (rc)
return CDK_File_Error;
s->fp = *tmp;
*tmp = NULL;
return 0;
}
/* This function is exactly like filter_read, except the fact that we can't
use tmpfile () all the time. That's why we open the real file when there
is no last filter. */
static cdk_error_t
stream_filter_write (cdk_stream_t s)
{
struct stream_filter_s *f;
cdk_error_t rc = 0;
assert (s);
if (s->flags.filtrated)
return CDK_Inv_Value;
for (f = s->filters; f; f = f->next)
{
if (!f->flags.enabled)
continue;
/* if there is no next filter, create the final output file */
_cdk_log_debug ("filter [write]: last filter=%d fname=%s\n",
f->next ? 1 : 0, s->fname);
if (!f->next && s->fname)
f->tmp = fopen (s->fname, "w+b");
else
f->tmp = my_tmpfile ();
if (!f->tmp)
{
rc = CDK_File_Error;
break;
}
/* If there is no next filter, flush the cache. We also do this
when the next filter is the armor filter because this filter
is special and before it starts, all data should be written. */
if ((!f->next || f->next->type == fARMOR) && s->cache.size)
{
rc = stream_cache_flush (s, f->tmp);
if (rc)
break;
}
rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
_cdk_log_debug ("filter [write]: type=%d rc=%d\n", f->type, rc);
if (!rc)
rc = stream_fp_replace (s, &f->tmp);
if (!rc)
rc = cdk_stream_seek (s, 0);
if (rc)
{
_cdk_log_debug ("filter [close]: fd=%d\n", fileno (f->tmp));
fclose (f->tmp);
break;
}
}
return rc;
}
/* Here all data from the file handle is passed through all filters.
The scheme works like this:
Create a tempfile and use it for the output of the filter. Then the
original file handle will be closed and replace with the temp handle.
The file pointer will be set to the begin and the game starts again. */
static cdk_error_t
stream_filter_read (cdk_stream_t s)
{
struct stream_filter_s *f;
cdk_error_t rc = 0;
assert (s);
if (s->flags.filtrated)
return 0;
for (f = s->filters; f; f = f->next)
{
if (!f->flags.enabled)
continue;
if (f->flags.error)
{
_cdk_log_debug ("filter %s [read]: has the error flag; skipped\n",
s->fname ? s->fname : "[temp]");
continue;
}
f->tmp = my_tmpfile ();
if (!f->tmp)
{
rc = CDK_File_Error;
break;
}
rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
_cdk_log_debug ("filter %s [read]: type=%d rc=%d\n",
s->fname ? s->fname : "[temp]", f->type, rc);
if (rc)
{
f->flags.error = 1;
break;
}
f->flags.error = 0;
/* If the filter is read-only, do not replace the FP because
the contents were not altered in any way. */
if (!f->flags.rdonly)
{
rc = stream_fp_replace (s, &f->tmp);
if (rc)
break;
}
else
{
fclose (f->tmp);
f->tmp = NULL;
}
rc = cdk_stream_seek (s, 0);
if (rc)
break;
/* Disable the filter after it was successfully used. The idea
is the following: let's say the armor filter was pushed and
later more filters were added. The second time the filter code
will be executed, only the new filter should be started but
not the old because we already used it. */
f->flags.enabled = 0;
}
return rc;
}
void *
_cdk_stream_get_opaque (cdk_stream_t s, int fid)
{
struct stream_filter_s *f;
if (!s)
return NULL;
for (f = s->filters; f; f = f->next)
{
if (f->type == fid)
return f->opaque;
}
return NULL;
}
/**
* cdk_stream_read: Try to read count bytes from the STREAM object.
* @s: The STREAM object.
* @buf: The buffer to insert the readed bytes.
* @count: Request so much bytes.
*
* When this function is called the first time, it can take a while
* because all filters need to be processed. Please remember that you
* need to add the filters in reserved order.
**/
int
cdk_stream_read (cdk_stream_t s, void *buf, size_t buflen)
{
int nread;
int rc;
if (!s)
{
s->error = CDK_Inv_Value;
return EOF;
}
if (s->cbs_hd)
{
if (s->cbs.read)
return s->cbs.read (s->cbs_hd, buf, buflen);
return 0;
}
if (s->flags.write && !s->flags.temp)
{
s->error = CDK_Inv_Mode;
return EOF; /* This is a write stream */
}
if (!s->flags.no_filter && !s->cache.on && !s->flags.filtrated)
{
rc = stream_filter_read (s);
if (rc)
{
s->error = rc;
if (feof (s->fp))
s->flags.eof = 1;
return EOF;
}
s->flags.filtrated = 1;
}
if (!buf && !buflen)
return 0;
nread = fread (buf, 1, buflen, s->fp);
if (!nread)
nread = EOF;
if (feof (s->fp))
{
s->error = 0;
s->flags.eof = 1;
}
return nread;
}
int
cdk_stream_getc (cdk_stream_t s)
{
unsigned char buf[2];
int nread;
if (!s)
{
s->error = CDK_Inv_Value;
return EOF;
}
nread = cdk_stream_read (s, buf, 1);
if (nread == EOF)
{
s->error = CDK_File_Error;
return EOF;
}
return buf[0];
}
/**
* cdk_stream_write: Try to write count bytes into the stream.
* @s: The STREAM object
* @buf: The buffer with the values to write.
* @count: The size of the buffer.
*
* In this function we simply write the bytes to the stream. We can't
* use the filters here because it would mean they have to support
* partial flushing.
**/
int
cdk_stream_write (cdk_stream_t s, const void *buf, size_t count)
{
int nwritten;
if (!s)
{
s->error = CDK_Inv_Value;
return EOF;
}
if (s->cbs_hd)
{
if (s->cbs.write)
return s->cbs.write (s->cbs_hd, buf, count);
return 0;
}
if (!s->flags.write)
{
s->error = CDK_Inv_Mode; /* this is a read stream */
return EOF;
}
if (!buf && !count)
return stream_flush (s);
if (s->cache.on)
{
/* We need to resize the buffer if the additional data wouldn't
fit into it. We allocate more memory to avoid to resize it the
next time the function is used. */
if (s->cache.size + count > s->cache.alloced)
{
byte *old = s->cache.buf;
s->cache.buf =
cdk_calloc (1, s->cache.alloced + count + STREAM_BUFSIZE);
s->cache.alloced += (count + STREAM_BUFSIZE);
memcpy (s->cache.buf, old, s->cache.size);
cdk_free (old);
_cdk_log_debug ("stream: enlarge cache to %d octets\n",
s->cache.alloced);
}
memcpy (s->cache.buf + s->cache.size, buf, count);
s->cache.size += count;
return count;
}
nwritten = fwrite (buf, 1, count, s->fp);
if (!nwritten)
nwritten = EOF;
return nwritten;
}
int
cdk_stream_putc (cdk_stream_t s, int c)
{
byte buf[2];
int nwritten;
if (!s)
{
s->error = CDK_Inv_Value;
return EOF;
}
buf[0] = c;
nwritten = cdk_stream_write (s, buf, 1);
if (nwritten == EOF)
return EOF;
return 0;
}
off_t
cdk_stream_tell (cdk_stream_t s)
{
return s ? ftell (s->fp) : (off_t) - 1;
}
cdk_error_t
cdk_stream_seek (cdk_stream_t s, off_t offset)
{
off_t len;
if (!s)
return CDK_Inv_Value;
if (s->cbs_hd)
{
if (s->cbs.seek)
return s->cbs.seek (s->cbs_hd, offset);
return 0;
}
/* Set or reset the EOF flag. */
len = cdk_stream_get_length (s);
if (len == offset)
s->flags.eof = 1;
else
s->flags.eof = 0;
if (fseek (s->fp, offset, SEEK_SET))
return CDK_File_Error;
return 0;
}
static cdk_error_t
stream_flush (cdk_stream_t s)
{
assert (s);
/* For some constellations it cannot be assured that the
return value is defined, thus we ignore it for now. */
(void) fflush (s->fp);
return 0;
}
/**
* cdk_stream_set_armor_flag:
* @s: the stream object
* @type: the type of armor to use
*
* If the file is in read-mode, no armor type needs to be
* defined (armor_type=0) because the armor filter will be
* used for decoding existing armor data.
* For the write mode, @armor_type can be set to any valid
* armor type (message, key, sig).
**/
cdk_error_t
cdk_stream_set_armor_flag (cdk_stream_t s, int armor_type)
{
struct stream_filter_s *f;
if (!s)
return CDK_Inv_Value;
f = filter_add (s, _cdk_filter_armor, fARMOR);
if (!f)
return CDK_Out_Of_Core;
f->u.afx.idx = f->u.afx.idx2 = armor_type;
f->ctl = stream_get_mode (s);
return 0;
}
/**
* cdk_stream_set_literal_flag:
* @s: the stream object
* @mode: the mode to use (binary, text, unicode)
* @fname: the file name to store in the packet.
*
* In read mode it kicks off the literal decoding routine to
* unwrap the data from the packet. The @mode parameter is ignored.
* In write mode the function can be used to wrap the stream data
* into a literal packet with the given mode and file name.
**/
cdk_error_t
cdk_stream_set_literal_flag (cdk_stream_t s, cdk_lit_format_t mode,
const char *fname)
{
struct stream_filter_s *f;
const char *orig_fname;
_cdk_log_debug ("stream: enable literal mode.\n");
if (!s)
return CDK_Inv_Value;
orig_fname = _cdk_stream_get_fname (s);
f = filter_add (s, _cdk_filter_literal, fLITERAL);
if (!f)
return CDK_Out_Of_Core;
f->u.pfx.mode = mode;
f->u.pfx.filename = fname ? cdk_strdup (fname) : NULL;
f->u.pfx.orig_filename = orig_fname ? cdk_strdup (orig_fname) : NULL;
f->ctl = stream_get_mode (s);
if (s->blkmode > 0)
{
f->u.pfx.blkmode.on = 1;
f->u.pfx.blkmode.size = s->blkmode;
}
return 0;
}
/**
* cdk_stream_set_cipher_flag:
* @s: the stream object
* @dek: the data encryption key
* @use_mdc: 1 means to use the MDC mode
*
* In read mode it kicks off the cipher filter to decrypt the data
* from the stream with the key given in @dek.
* In write mode the stream data will be encrypted with the DEK object
* and optionally, the @use_mdc parameter can be used to enable the MDC mode.
**/
cdk_error_t
cdk_stream_set_cipher_flag (cdk_stream_t s, cdk_dek_t dek, int use_mdc)
{
struct stream_filter_s *f;
_cdk_log_debug ("stream: enable cipher mode\n");
if (!s)
return CDK_Inv_Value;
f = filter_add (s, _cdk_filter_cipher, fCIPHER);
if (!f)
return CDK_Out_Of_Core;
dek->use_mdc = use_mdc;
f->ctl = stream_get_mode (s);
f->u.cfx.dek = dek;
f->u.cfx.mdc_method = use_mdc ? GCRY_MD_SHA1 : 0;
if (s->blkmode > 0)
{
f->u.cfx.blkmode.on = 1;
f->u.cfx.blkmode.size = s->blkmode;
}
return 0;
}
/**
* cdk_stream_set_compress_flag:
* @s: the stream object
* @algo: the compression algo
* @level: level of compression (0..9)
*
* In read mode it kicks off the decompression filter to retrieve
* the uncompressed data.
* In write mode the stream data will be compressed with the
* given algorithm at the given level.
**/
cdk_error_t
cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level)
{
struct stream_filter_s *f;
if (!s)
return CDK_Inv_Value;
f = filter_add (s, _cdk_filter_compress, fCOMPRESS);
if (!f)
return CDK_Out_Of_Core;
f->ctl = stream_get_mode (s);
f->u.zfx.algo = algo;
f->u.zfx.level = level;
return 0;
}
/**
* cdk_stream_set_text_flag:
* @s: the stream object
* @lf: line ending
*
* Pushes the text filter to store the stream data in cannoncial format.
**/
cdk_error_t
cdk_stream_set_text_flag (cdk_stream_t s, const char *lf)
{
struct stream_filter_s *f;
if (!s)
return CDK_Inv_Value;
f = filter_add (s, _cdk_filter_text, fTEXT);
if (!f)
return CDK_Out_Of_Core;
f->ctl = stream_get_mode (s);
f->u.tfx.lf = lf;
return 0;
}
/**
* cdk_stream_set_hash_flag:
* @s: the stream object
* @digest_algo: the digest algorithm to use
*
* This is for read-only streams. It pushes a digest filter to
* calculate the digest of the given stream data.
**/
cdk_error_t
cdk_stream_set_hash_flag (cdk_stream_t s, int digest_algo)
{
struct stream_filter_s *f;
if (!s)
return CDK_Inv_Value;
if (stream_get_mode (s))
return CDK_Inv_Mode;
f = filter_add (s, _cdk_filter_hash, fHASH);
if (!f)
return CDK_Out_Of_Core;
f->ctl = stream_get_mode (s);
f->u.mfx.digest_algo = digest_algo;
f->flags.rdonly = 1;
return 0;
}
/**
* cdk_stream_enable_cache:
* @s: the stream object
* @val: 1=on, 0=off
*
* Enable or disable the cache section of a stream object.
**/
cdk_error_t
cdk_stream_enable_cache (cdk_stream_t s, int val)
{
if (!s)
return CDK_Inv_Value;
if (!s->flags.write)
return CDK_Inv_Mode;
s->cache.on = val;
if (!s->cache.buf)
{
s->cache.buf = cdk_calloc (1, STREAM_BUFSIZE);
s->cache.alloced = STREAM_BUFSIZE;
_cdk_log_debug ("stream: allocate cache of %d octets\n",
STREAM_BUFSIZE);
}
return 0;
}
static int
stream_cache_flush (cdk_stream_t s, FILE * fp)
{
int nwritten;
assert (s);
/* FIXME: We should find a way to use cdk_stream_write here. */
if (s->cache.size > 0)
{
nwritten = fwrite (s->cache.buf, 1, s->cache.size, fp);
if (!nwritten)
return CDK_File_Error;
s->cache.size = 0;
s->cache.on = 0;
wipemem (s->cache.buf, s->cache.alloced);
}
return 0;
}
/**
* cdk_stream_kick_off:
* @inp: the input stream
* @out: the output stream.
*
* Passes the entire data from @inp into the output stream @out
* with all the activated filters.
*/
cdk_error_t
cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out)
{
byte buf[BUFSIZE];
int nread, nwritten;
cdk_error_t rc;
if (!inp || !out)
return CDK_Inv_Value;
rc = CDK_Success;
while (!cdk_stream_eof (inp))
{
nread = cdk_stream_read (inp, buf, DIM (buf));
if (!nread || nread == EOF)
break;
nwritten = cdk_stream_write (out, buf, nread);
if (!nwritten || nwritten == EOF)
{ /* In case of errors, we leave the loop. */
rc = inp->error;
break;
}
}
wipemem (buf, sizeof (buf));
return rc;
}
/**
* cdk_stream_mmap_part:
* @s: the stream
* @off: the offset where to start
* @len: how much bytes shall be mapped
* @ret_buf: the buffer to store the content
* @ret_buflen: length of the buffer
*
* Map the data of the given stream into a memory section. @ret_count
* contains the length of the buffer.
**/
cdk_error_t
cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len,
byte ** ret_buf, size_t * ret_buflen)
{
off_t oldpos;
int n;
cdk_error_t rc;
if (!s || !ret_buf || !ret_buflen)
return CDK_Inv_Value;
if (s->cbs_hd)
return CDK_Inv_Mode;
*ret_buflen = 0;
*ret_buf = NULL;
oldpos = cdk_stream_tell (s);
rc = cdk_stream_flush (s);
if (!rc)
rc = cdk_stream_seek (s, off);
if (rc)
return rc;
if (!len)
len = cdk_stream_get_length (s);
if (!len || len > MAX_MAP_SIZE)
return 0;
*ret_buf = cdk_calloc (1, len + 1);
*ret_buflen = len;
n = cdk_stream_read (s, *ret_buf, len);
if (n != len)
*ret_buflen = n;
rc = cdk_stream_seek (s, oldpos);
return rc;
}
cdk_error_t
cdk_stream_mmap (cdk_stream_t inp, byte ** buf, size_t * buflen)
{
off_t len;
/* We need to make sure all data is flushed before we retrieve the size. */
cdk_stream_flush (inp);
len = cdk_stream_get_length (inp);
return cdk_stream_mmap_part (inp, 0, len, buf, buflen);
}
/**
* cdk_stream_peek:
* @inp: the input stream handle
* @s: buffer
* @count: number of bytes to peek
*
* The function acts like cdk_stream_read with the difference that
* the file pointer is moved to the old position after the bytes were read.
**/
int
cdk_stream_peek (cdk_stream_t inp, byte * buf, size_t buflen)
{
off_t off;
int nbytes;
if (!inp || !buf)
return 0;
if (inp->cbs_hd)
return 0;
off = cdk_stream_tell (inp);
nbytes = cdk_stream_read (inp, buf, buflen);
if (nbytes == -1)
return 0;
if (cdk_stream_seek (inp, off))
return 0;
return nbytes;
}
/* Try to read a line from the given stream. */
int
_cdk_stream_gets (cdk_stream_t s, char *buf, size_t count)
{
int c, i;
assert (s);
i = 0;
while (!cdk_stream_eof (s) && count > 0)
{
c = cdk_stream_getc (s);
if (c == EOF || c == '\r' || c == '\n')
{
buf[i++] = '\0';
break;
}
buf[i++] = c;
count--;
}
return i;
}
/* Try to write string into the stream @s. */
int
_cdk_stream_puts (cdk_stream_t s, const char *buf)
{
return cdk_stream_write (s, buf, strlen (buf));
}
/* Activate the block mode for the given stream. */
cdk_error_t
_cdk_stream_set_blockmode (cdk_stream_t s, size_t nbytes)
{
assert (s);
_cdk_log_debug ("stream: activate block mode with blocksize %d\n", nbytes);
s->blkmode = nbytes;
return 0;
}
/* Return the block mode state of the given stream. */
int
_cdk_stream_get_blockmode (cdk_stream_t s)
{
return s ? s->blkmode : 0;
}
-88
View File
@@ -1,88 +0,0 @@
/* stream.h - internal definiton for the STREAM object
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef CDK_STREAM_H
#define CDK_STREAM_H
/* The default buffer size for the stream. */
#define STREAM_BUFSIZE 8192
enum {
fDUMMY = 0,
fARMOR = 1,
fCIPHER = 2,
fLITERAL = 3,
fCOMPRESS= 4,
fHASH = 5,
fTEXT = 6
};
/* Type definition for the filter function. */
typedef int (*filter_fnct_t) (void * opaque, int ctl, FILE * in, FILE * out);
/* The stream filter context structure. */
struct stream_filter_s
{
struct stream_filter_s *next;
filter_fnct_t fnct;
void *opaque;
FILE *tmp;
union {
armor_filter_t afx;
cipher_filter_t cfx;
literal_filter_t pfx;
compress_filter_t zfx;
text_filter_t tfx;
md_filter_t mfx;
} u;
struct {
unsigned enabled:1;
unsigned rdonly:1;
unsigned error:1;
} flags;
unsigned type;
unsigned ctl;
};
/* The stream context structure. */
struct cdk_stream_s {
struct stream_filter_s *filters;
int fmode;
int error;
size_t blkmode;
struct {
unsigned filtrated:1;
unsigned eof:1;
unsigned write:1;
unsigned temp:1;
unsigned reset:1;
unsigned no_filter:1;
unsigned compressed:3;
} flags;
struct {
unsigned char *buf;
unsigned on:1;
size_t size;
size_t alloced;
} cache;
char *fname;
FILE *fp;
unsigned int fp_ref:1;
struct cdk_stream_cbs_s cbs;
void *cbs_hd;
};
#endif /* CDK_STREAM_H */
-44
View File
@@ -1,44 +0,0 @@
/* types.h - Some type definitions
* Copyright (C) 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifndef CDK_TYPES_H
#define CDK_TYPES_H
#include <gcrypt.h>
#ifndef HAVE_BYTE_TYPEDEF
# undef byte
typedef unsigned char byte;
# define HAVE_BYTE_TYPEDEF
#endif
#ifndef HAVE_U16_TYPEDEF
# undef u16
typedef unsigned short u16;
# define HAVE_U16_TYPEDEF
#endif
#ifndef HAVE_U32_TYPEDEF
# undef u32
typedef unsigned int u32;
# define HAVE_U32_TYPEDEF
#endif
#ifndef DIM
# define DIM(v) (sizeof (v)/sizeof ((v)[0]))
# define DIMof(type, member) DIM(((type *)0)->member)
#endif
#endif /* CDK_TYPES_H */
-306
View File
@@ -1,306 +0,0 @@
/* verify.c - Verify signatures
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
#include "opencdk.h"
#include "main.h"
#include "filters.h"
#include "packet.h"
/* Table of all supported digest algorithms and their names. */
struct
{
const char *name;
int algo;
} digest_table[] =
{
{
"MD5", GCRY_MD_MD5},
{
"SHA1", GCRY_MD_SHA1},
{
"RIPEMD160", GCRY_MD_RMD160},
{
"SHA256", GCRY_MD_SHA256},
{
"SHA384", GCRY_MD_SHA384},
{
"SHA512", GCRY_MD_SHA512},
{
NULL, 0}
};
static int file_verify_clearsign (cdk_ctx_t, const char *, const char *);
/**
* cdk_stream_verify:
* @hd: session handle
* @inp: the input stream
* @data: for detached signatures, this is the data stream @inp is the sig
* @out: where the output shall be written.
*/
cdk_error_t
cdk_stream_verify (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t data,
cdk_stream_t out)
{
/* FIXME: out is not currently used. */
if (cdk_armor_filter_use (inp))
cdk_stream_set_armor_flag (inp, 0);
return _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL);
}
/**
* cdk_file_verify:
* @hd: the session handle
* @file: the input file
* @data_file: for detached signature this is the data file and @file is the sig.
* @output: the output file
*
* Verify a signature.
**/
cdk_error_t
cdk_file_verify (cdk_ctx_t hd, const char *file, const char *data_file,
const char *output)
{
struct stat stbuf;
cdk_stream_t inp, data;
char buf[4096];
int n;
cdk_error_t rc;
if (!hd || !file)
return CDK_Inv_Value;
if (output && !hd->opt.overwrite && !stat (output, &stbuf))
return CDK_Inv_Mode;
rc = cdk_stream_open (file, &inp);
if (rc)
return rc;
if (cdk_armor_filter_use (inp))
{
n = cdk_stream_peek (inp, (byte *) buf, DIM (buf) - 1);
if (!n || n == -1)
return CDK_EOF;
buf[n] = '\0';
if (strstr (buf, "BEGIN PGP SIGNED MESSAGE"))
{
cdk_stream_close (inp);
return file_verify_clearsign (hd, file, output);
}
cdk_stream_set_armor_flag (inp, 0);
}
if (data_file)
{
rc = cdk_stream_open (data_file, &data);
if (rc)
{
cdk_stream_close (inp);
return rc;
}
}
else
data = NULL;
rc = _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL);
if (data != NULL)
cdk_stream_close (data);
cdk_stream_close (inp);
return rc;
}
void
_cdk_result_verify_free (cdk_verify_result_t res)
{
if (!res)
return;
cdk_free (res->policy_url);
cdk_free (res->sig_data);
cdk_free (res);
}
cdk_verify_result_t
_cdk_result_verify_new (void)
{
cdk_verify_result_t res;
res = cdk_calloc (1, sizeof *res);
if (!res)
return NULL;
return res;
}
static cdk_error_t
file_verify_clearsign (cdk_ctx_t hd, const char *file, const char *output)
{
cdk_stream_t inp = NULL, out = NULL, tmp = NULL;
gcry_md_hd_t md = NULL;
char buf[512], chk[512];
const char *s;
int i, is_signed = 0, nbytes;
int digest_algo = 0;
gcry_error_t err;
cdk_error_t rc;
if (output)
{
rc = cdk_stream_create (output, &out);
if (rc)
return rc;
}
rc = cdk_stream_open (file, &inp);
if (rc)
{
if (output)
cdk_stream_close (out);
return rc;
}
s = "-----BEGIN PGP SIGNED MESSAGE-----";
while (!cdk_stream_eof (inp))
{
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
if (!nbytes || nbytes == -1)
break;
if (!strncmp (buf, s, strlen (s)))
{
is_signed = 1;
break;
}
}
if (cdk_stream_eof (inp) && !is_signed)
{
rc = CDK_Armor_Error;
goto leave;
}
while (!cdk_stream_eof (inp))
{
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
if (!nbytes || nbytes == -1)
break;
if (nbytes == 1) /* Empty line */
break;
else if (!strncmp (buf, "Hash: ", 6))
{
for (i = 0; digest_table[i].name; i++)
{
if (!strcmp (buf + 6, digest_table[i].name))
{
digest_algo = digest_table[i].algo;
break;
}
}
}
}
if (digest_algo && gcry_md_test_algo (digest_algo))
{
rc = CDK_Inv_Algo;
goto leave;
}
if (!digest_algo)
digest_algo = GCRY_MD_MD5;
err = gcry_md_open (&md, digest_algo, 0);
if (err)
{
rc = map_gcry_error (err);
goto leave;
}
s = "-----BEGIN PGP SIGNATURE-----";
while (!cdk_stream_eof (inp))
{
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
if (!nbytes || nbytes == -1)
break;
if (!strncmp (buf, s, strlen (s)))
break;
else
{
cdk_stream_peek (inp, (byte *) chk, DIM (chk) - 1);
i = strncmp (chk, s, strlen (s));
if (strlen (buf) == 0 && i == 0)
continue; /* skip last '\n' */
_cdk_trim_string (buf, i == 0 ? 0 : 1);
gcry_md_write (md, buf, strlen (buf));
}
if (!strncmp (buf, "- ", 2)) /* FIXME: handle it recursive. */
memmove (buf, buf + 2, nbytes - 2);
if (out)
{
if (strstr (buf, "\r\n"))
buf[strlen (buf) - 2] = '\0';
cdk_stream_write (out, buf, strlen (buf));
_cdk_stream_puts (out, _cdk_armor_get_lineend ());
}
}
/* We create a temporary stream object to store the
signature data in there. */
rc = cdk_stream_tmp_new (&tmp);
if (rc)
goto leave;
s = "-----BEGIN PGP SIGNATURE-----\n";
_cdk_stream_puts (tmp, s);
while (!cdk_stream_eof (inp))
{
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
if (!nbytes || nbytes == -1)
break;
if (nbytes < (DIM (buf) - 3))
{
buf[nbytes - 1] = '\n';
buf[nbytes] = '\0';
}
cdk_stream_write (tmp, buf, nbytes);
}
/* FIXME: This code is not very elegant. */
cdk_stream_tmp_set_mode (tmp, STREAMCTL_READ);
cdk_stream_seek (tmp, 0);
cdk_stream_set_armor_flag (tmp, 0);
cdk_stream_read (tmp, NULL, 0);
/* the digest handle will be closed there. */
rc = _cdk_proc_packets (hd, tmp, NULL, NULL, NULL, md);
leave:
gcry_md_close (md);
cdk_stream_close (out);
cdk_stream_close (tmp);
cdk_stream_close (inp);
return rc;
}
-947
View File
@@ -1,947 +0,0 @@
/* write-packet.c - Write OpenPGP packets
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
*
* This file is part of OpenCDK.
*
* OpenCDK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OpenCDK 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 General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "opencdk.h"
#include "main.h"
static int
stream_write (cdk_stream_t s, const void *buf, size_t buflen)
{
int nwritten;
nwritten = cdk_stream_write (s, buf, buflen);
if (nwritten == EOF)
return _cdk_stream_get_errno (s);
return 0;
}
static int
stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t * r_nread)
{
int nread;
assert (r_nread);
nread = cdk_stream_read (s, buf, buflen);
if (nread == EOF)
return _cdk_stream_get_errno (s);
*r_nread = nread;
return 0;
}
static int
stream_putc (cdk_stream_t s, int c)
{
int nwritten = cdk_stream_putc (s, c);
if (nwritten == EOF)
return _cdk_stream_get_errno (s);
return 0;
}
static int
write_32 (cdk_stream_t out, u32 u)
{
byte buf[4];
buf[0] = u >> 24;
buf[1] = u >> 16;
buf[2] = u >> 8;
buf[3] = u;
return stream_write (out, buf, 4);
}
static int
write_16 (cdk_stream_t out, u16 u)
{
byte buf[2];
buf[0] = u >> 8;
buf[1] = u;
return stream_write (out, buf, 2);
}
static size_t
calc_mpisize (gcry_mpi_t mpi[MAX_CDK_PK_PARTS], size_t ncount)
{
size_t size, i;
size = 0;
for (i = 0; i < ncount; i++)
size += (gcry_mpi_get_nbits (mpi[i]) + 7) / 8 + 2;
return size;
}
static int
write_mpi (cdk_stream_t out, gcry_mpi_t m)
{
byte buf[MAX_MPI_BYTES + 2];
size_t nbits, nread;
gcry_error_t err;
if (!out || !m)
return CDK_Inv_Value;
nbits = gcry_mpi_get_nbits (m);
if (nbits > MAX_MPI_BITS || nbits < 1)
return CDK_MPI_Error;
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buf, MAX_MPI_BYTES + 2, &nread, m);
if (err)
return map_gcry_error (err);
return stream_write (out, buf, nread);
}
static cdk_error_t
write_mpibuf (cdk_stream_t out, gcry_mpi_t mpi[MAX_CDK_PK_PARTS],
size_t count)
{
size_t i;
cdk_error_t rc;
for (i = 0; i < count; i++)
{
rc = write_mpi (out, mpi[i]);
if (rc)
return rc;
}
return 0;
}
static cdk_error_t
pkt_encode_len (cdk_stream_t out, size_t pktlen)
{
cdk_error_t rc;
assert (out);
rc = 0;
if (!pktlen)
{
/* Block mode, partial bodies, with 'DEF_BLOCKSIZE' from main.h */
rc = stream_putc (out, (0xE0 | DEF_BLOCKBITS));
}
else if (pktlen < 192)
rc = stream_putc (out, pktlen);
else if (pktlen < 8384)
{
pktlen -= 192;
rc = stream_putc (out, (pktlen / 256) + 192);
if (!rc)
rc = stream_putc (out, (pktlen % 256));
}
else
{
rc = stream_putc (out, 255);
if (!rc)
rc = write_32 (out, pktlen);
}
return rc;
}
static cdk_error_t
write_head_new (cdk_stream_t out, size_t size, int type)
{
cdk_error_t rc;
assert (out);
if (type < 0 || type > 63)
return CDK_Inv_Packet;
rc = stream_putc (out, (0xC0 | type));
if (!rc)
rc = pkt_encode_len (out, size);
return rc;
}
static cdk_error_t
write_head_old (cdk_stream_t out, size_t size, int type)
{
cdk_error_t rc;
int ctb;
assert (out);
if (type < 0 || type > 16)
return CDK_Inv_Packet;
ctb = 0x80 | (type << 2);
if (!size)
ctb |= 3;
else if (size < 256)
;
else if (size < 65536)
ctb |= 1;
else
ctb |= 2;
rc = stream_putc (out, ctb);
if (!size)
return rc;
if (!rc)
{
if (size < 256)
rc = stream_putc (out, size);
else if (size < 65536)
rc = write_16 (out, size);
else
rc = write_32 (out, size);
}
return rc;
}
/* Write special PGP2 packet header. PGP2 (wrongly) uses two byte header
length for signatures and keys even if the size is < 256. */
static cdk_error_t
pkt_write_head2 (cdk_stream_t out, size_t size, int type)
{
cdk_error_t rc;
rc = cdk_stream_putc (out, 0x80 | (type << 2) | 1);
if (!rc)
rc = cdk_stream_putc (out, size >> 8);
if (!rc)
rc = cdk_stream_putc (out, size & 0xff);
return rc;
}
static int
pkt_write_head (cdk_stream_t out, int old_ctb, size_t size, int type)
{
if (old_ctb)
return write_head_old (out, size, type);
return write_head_new (out, size, type);
}
static cdk_error_t
write_encrypted (cdk_stream_t out, cdk_pkt_encrypted_t enc, int old_ctb)
{
size_t nbytes;
cdk_error_t rc;
assert (out);
assert (enc);
if (DEBUG_PKT)
_cdk_log_debug ("write_encrypted: %lu bytes\n", enc->len);
nbytes = enc->len ? (enc->len + enc->extralen) : 0;
rc = pkt_write_head (out, old_ctb, nbytes, CDK_PKT_ENCRYPTED);
/* The rest of the packet is ciphertext */
return rc;
}
static int
write_encrypted_mdc (cdk_stream_t out, cdk_pkt_encrypted_t enc)
{
size_t nbytes;
cdk_error_t rc;
assert (out);
assert (enc);
if (!enc->mdc_method)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_encrypted_mdc: %lu bytes\n", enc->len);
nbytes = enc->len ? (enc->len + enc->extralen + 1) : 0;
rc = pkt_write_head (out, 0, nbytes, CDK_PKT_ENCRYPTED_MDC);
if (!rc)
rc = stream_putc (out, 1); /* version */
/* The rest of the packet is ciphertext */
return rc;
}
static cdk_error_t
write_symkey_enc (cdk_stream_t out, cdk_pkt_symkey_enc_t ske)
{
cdk_s2k_t s2k;
size_t size = 0, s2k_size = 0;
cdk_error_t rc;
assert (out);
assert (ske);
if (ske->version != 4)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_symkey_enc:\n");
s2k = ske->s2k;
if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
s2k_size = 8;
if (s2k->mode == CDK_S2K_ITERSALTED)
s2k_size++;
size = 4 + s2k_size + ske->seskeylen;
rc = pkt_write_head (out, 0, size, CDK_PKT_SYMKEY_ENC);
if (!rc)
rc = stream_putc (out, ske->version);
if (!rc)
rc = stream_putc (out, ske->cipher_algo);
if (!rc)
rc = stream_putc (out, s2k->mode);
if (!rc)
rc = stream_putc (out, s2k->hash_algo);
if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
{
rc = stream_write (out, s2k->salt, 8);
if (!rc)
{
if (s2k->mode == CDK_S2K_ITERSALTED)
rc = stream_putc (out, s2k->count);
}
}
return rc;
}
static int
write_pubkey_enc (cdk_stream_t out, cdk_pkt_pubkey_enc_t pke, int old_ctb)
{
size_t size;
int rc, nenc;
assert (out);
assert (pke);
if (pke->version < 2 || pke->version > 3)
return CDK_Inv_Packet;
if (!KEY_CAN_ENCRYPT (pke->pubkey_algo))
return CDK_Inv_Algo;
if (DEBUG_PKT)
_cdk_log_debug ("write_pubkey_enc:\n");
nenc = cdk_pk_get_nenc (pke->pubkey_algo);
size = 10 + calc_mpisize (pke->mpi, nenc);
rc = pkt_write_head (out, old_ctb, size, CDK_PKT_PUBKEY_ENC);
if (rc)
return rc;
rc = stream_putc (out, pke->version);
if (!rc)
rc = write_32 (out, pke->keyid[0]);
if (!rc)
rc = write_32 (out, pke->keyid[1]);
if (!rc)
rc = stream_putc (out, pke->pubkey_algo);
if (!rc)
rc = write_mpibuf (out, pke->mpi, nenc);
return rc;
}
static cdk_error_t
write_mdc (cdk_stream_t out, cdk_pkt_mdc_t mdc)
{
cdk_error_t rc;
assert (mdc);
assert (out);
if (DEBUG_PKT)
_cdk_log_debug ("write_mdc:\n");
/* This packet requires a fixed header encoding */
rc = stream_putc (out, 0xD3); /* packet ID and 1 byte length */
if (!rc)
rc = stream_putc (out, 0x14);
if (!rc)
rc = stream_write (out, mdc->hash, DIM (mdc->hash));
return rc;
}
static size_t
calc_subpktsize (cdk_subpkt_t s)
{
size_t nbytes;
/* In the count mode, no buffer is returned. */
_cdk_subpkt_get_array (s, 1, &nbytes);
return nbytes;
}
static cdk_error_t
write_v3_sig (cdk_stream_t out, cdk_pkt_signature_t sig, int nsig)
{
size_t size;
cdk_error_t rc;
size = 19 + calc_mpisize (sig->mpi, nsig);
if (is_RSA (sig->pubkey_algo))
rc = pkt_write_head2 (out, size, CDK_PKT_SIGNATURE);
else
rc = pkt_write_head (out, 1, size, CDK_PKT_SIGNATURE);
if (!rc)
rc = stream_putc (out, sig->version);
if (!rc)
rc = stream_putc (out, 5);
if (!rc)
rc = stream_putc (out, sig->sig_class);
if (!rc)
rc = write_32 (out, sig->timestamp);
if (!rc)
rc = write_32 (out, sig->keyid[0]);
if (!rc)
rc = write_32 (out, sig->keyid[1]);
if (!rc)
rc = stream_putc (out, sig->pubkey_algo);
if (!rc)
rc = stream_putc (out, sig->digest_algo);
if (!rc)
rc = stream_putc (out, sig->digest_start[0]);
if (!rc)
rc = stream_putc (out, sig->digest_start[1]);
if (!rc)
rc = write_mpibuf (out, sig->mpi, nsig);
return rc;
}
static cdk_error_t
write_signature (cdk_stream_t out, cdk_pkt_signature_t sig, int old_ctb)
{
byte *buf;
size_t nbytes, size, nsig;
cdk_error_t rc;
assert (out);
assert (sig);
if (!KEY_CAN_SIGN (sig->pubkey_algo))
return CDK_Inv_Algo;
if (sig->version < 2 || sig->version > 4)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_signature:\n");
nsig = cdk_pk_get_nsig (sig->pubkey_algo);
if (!nsig)
return CDK_Inv_Algo;
if (sig->version < 4)
return write_v3_sig (out, sig, nsig);
size = 10 + calc_subpktsize (sig->hashed)
+ calc_subpktsize (sig->unhashed) + calc_mpisize (sig->mpi, nsig);
rc = pkt_write_head (out, 0, size, CDK_PKT_SIGNATURE);
if (!rc)
rc = stream_putc (out, 4);
if (!rc)
rc = stream_putc (out, sig->sig_class);
if (!rc)
rc = stream_putc (out, sig->pubkey_algo);
if (!rc)
rc = stream_putc (out, sig->digest_algo);
if (!rc)
rc = write_16 (out, sig->hashed_size);
if (!rc)
{
buf = _cdk_subpkt_get_array (sig->hashed, 0, &nbytes);
if (!buf)
return CDK_Out_Of_Core;
rc = stream_write (out, buf, nbytes);
cdk_free (buf);
}
if (!rc)
rc = write_16 (out, sig->unhashed_size);
if (!rc)
{
buf = _cdk_subpkt_get_array (sig->unhashed, 0, &nbytes);
if (!buf)
return CDK_Out_Of_Core;
rc = stream_write (out, buf, nbytes);
cdk_free (buf);
}
if (!rc)
rc = stream_putc (out, sig->digest_start[0]);
if (!rc)
rc = stream_putc (out, sig->digest_start[1]);
if (!rc)
rc = write_mpibuf (out, sig->mpi, nsig);
return rc;
}
static cdk_error_t
write_public_key (cdk_stream_t out, cdk_pkt_pubkey_t pk,
int is_subkey, int old_ctb)
{
int pkttype, ndays = 0;
size_t npkey = 0, size = 6;
cdk_error_t rc;
assert (out);
assert (pk);
if (pk->version < 2 || pk->version > 4)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_public_key: subkey=%d\n", is_subkey);
pkttype = is_subkey ? CDK_PKT_PUBLIC_SUBKEY : CDK_PKT_PUBLIC_KEY;
npkey = cdk_pk_get_npkey (pk->pubkey_algo);
if (!npkey)
return CDK_Inv_Algo;
if (pk->version < 4)
size += 2; /* expire date */
if (is_subkey)
old_ctb = 0;
size += calc_mpisize (pk->mpi, npkey);
if (old_ctb)
rc = pkt_write_head2 (out, size, pkttype);
else
rc = pkt_write_head (out, old_ctb, size, pkttype);
if (!rc)
rc = stream_putc (out, pk->version);
if (!rc)
rc = write_32 (out, pk->timestamp);
if (!rc && pk->version < 4)
{
if (pk->expiredate)
ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
rc = write_16 (out, ndays);
}
if (!rc)
rc = stream_putc (out, pk->pubkey_algo);
if (!rc)
rc = write_mpibuf (out, pk->mpi, npkey);
return rc;
}
static int
calc_s2ksize (cdk_pkt_seckey_t sk)
{
size_t nbytes = 0;
if (!sk->is_protected)
return 0;
switch (sk->protect.s2k->mode)
{
case CDK_S2K_SIMPLE:
nbytes = 2;
break;
case CDK_S2K_SALTED:
nbytes = 10;
break;
case CDK_S2K_ITERSALTED:
nbytes = 11;
break;
}
nbytes += sk->protect.ivlen;
nbytes++; /* single cipher byte */
return nbytes;
}
static cdk_error_t
write_secret_key (cdk_stream_t out, cdk_pkt_seckey_t sk,
int is_subkey, int old_ctb)
{
cdk_pkt_pubkey_t pk = NULL;
size_t size = 6, npkey, nskey;
int pkttype, s2k_mode;
cdk_error_t rc;
assert (out);
assert (sk);
if (!sk->pk)
return CDK_Inv_Value;
pk = sk->pk;
if (pk->version < 2 || pk->version > 4)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_secret_key:\n");
npkey = cdk_pk_get_npkey (pk->pubkey_algo);
nskey = cdk_pk_get_nskey (pk->pubkey_algo);
if (!npkey || !nskey)
return CDK_Inv_Algo;
if (pk->version < 4)
size += 2;
/* If the key is unprotected, the 1 extra byte:
1 octet - cipher algorithm byte (0x00)
the other bytes depend on the mode:
a) simple checksum - 2 octets
b) sha-1 checksum - 20 octets */
size = !sk->is_protected ? size + 1 : size + 1 + calc_s2ksize (sk);
size += calc_mpisize (pk->mpi, npkey);
if (sk->version == 3 || !sk->is_protected)
{
if (sk->version == 3)
{
size += 2; /* force simple checksum */
sk->protect.sha1chk = 0;
}
else
size += sk->protect.sha1chk ? 20 : 2;
size += calc_mpisize (sk->mpi, nskey);
}
else /* We do not know anything about the encrypted mpi's so we
treat the data as opaque. */
size += sk->enclen;
pkttype = is_subkey ? CDK_PKT_SECRET_SUBKEY : CDK_PKT_SECRET_KEY;
rc = pkt_write_head (out, old_ctb, size, pkttype);
if (!rc)
rc = stream_putc (out, pk->version);
if (!rc)
rc = write_32 (out, pk->timestamp);
if (!rc && pk->version < 4)
{
u16 ndays = 0;
if (pk->expiredate)
ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
rc = write_16 (out, ndays);
}
if (!rc)
rc = stream_putc (out, pk->pubkey_algo);
if (!rc)
rc = write_mpibuf (out, pk->mpi, npkey);
if (sk->is_protected == 0)
rc = stream_putc (out, 0x00);
else
{
if (is_RSA (pk->pubkey_algo) && pk->version < 4)
stream_putc (out, sk->protect.algo);
else if (sk->protect.s2k)
{
s2k_mode = sk->protect.s2k->mode;
rc = stream_putc (out, sk->protect.sha1chk ? 0xFE : 0xFF);
if (!rc)
rc = stream_putc (out, sk->protect.algo);
if (!rc)
rc = stream_putc (out, sk->protect.s2k->mode);
if (!rc)
rc = stream_putc (out, sk->protect.s2k->hash_algo);
if (!rc && (s2k_mode == 1 || s2k_mode == 3))
{
rc = stream_write (out, sk->protect.s2k->salt, 8);
if (!rc && s2k_mode == 3)
rc = stream_putc (out, sk->protect.s2k->count);
}
}
else
return CDK_Inv_Value;
rc = stream_write (out, sk->protect.iv, sk->protect.ivlen);
}
if (!rc && sk->is_protected && pk->version == 4)
{
if (sk->encdata && sk->enclen)
rc = stream_write (out, sk->encdata, sk->enclen);
}
else
{
if (!rc)
rc = write_mpibuf (out, sk->mpi, nskey);
if (!rc)
{
if (!sk->csum)
sk->csum = _cdk_sk_get_csum (sk);
rc = write_16 (out, sk->csum);
}
}
return rc;
}
static cdk_error_t
write_compressed (cdk_stream_t out, cdk_pkt_compressed_t cd)
{
cdk_error_t rc;
assert (out);
assert (cd);
if (DEBUG_PKT)
_cdk_log_debug ("packet: write_compressed\n");
/* Use an old (RFC1991) header for this packet. */
rc = pkt_write_head (out, 1, 0, CDK_PKT_COMPRESSED);
if (!rc)
rc = stream_putc (out, cd->algorithm);
return rc;
}
static cdk_error_t
write_literal (cdk_stream_t out, cdk_pkt_literal_t pt, int old_ctb)
{
byte buf[BUFSIZE];
size_t size;
cdk_error_t rc;
assert (out);
assert (pt);
/* We consider a packet without a body as an invalid packet.
At least one octet must be present. */
if (!pt->len)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_literal:\n");
size = 6 + pt->namelen + pt->len;
rc = pkt_write_head (out, old_ctb, size, CDK_PKT_LITERAL);
if (rc)
return rc;
rc = stream_putc (out, pt->mode);
if (rc)
return rc;
rc = stream_putc (out, pt->namelen);
if (rc)
return rc;
if (pt->namelen > 0)
rc = stream_write (out, pt->name, pt->namelen);
if (!rc)
rc = write_32 (out, pt->timestamp);
if (rc)
return rc;
while (!cdk_stream_eof (pt->buf) && !rc)
{
rc = stream_read (pt->buf, buf, DIM (buf), &size);
if (!rc)
rc = stream_write (out, buf, size);
}
wipemem (buf, sizeof (buf));
return rc;
}
static cdk_error_t
write_onepass_sig (cdk_stream_t out, cdk_pkt_onepass_sig_t sig)
{
cdk_error_t rc;
assert (out);
assert (sig);
if (sig->version != 3)
return CDK_Inv_Packet;
if (DEBUG_PKT)
_cdk_log_debug ("write_onepass_sig:\n");
rc = pkt_write_head (out, 0, 13, CDK_PKT_ONEPASS_SIG);
if (!rc)
rc = stream_putc (out, sig->version);
if (!rc)
rc = stream_putc (out, sig->sig_class);
if (!rc)
rc = stream_putc (out, sig->digest_algo);
if (!rc)
rc = stream_putc (out, sig->pubkey_algo);
if (!rc)
rc = write_32 (out, sig->keyid[0]);
if (!rc)
rc = write_32 (out, sig->keyid[1]);
if (!rc)
rc = stream_putc (out, sig->last);
return rc;
}
static cdk_error_t
write_user_id (cdk_stream_t out, cdk_pkt_userid_t id, int old_ctb,
int pkttype)
{
cdk_error_t rc;
if (!out || !id)
return CDK_Inv_Value;
if (pkttype == CDK_PKT_ATTRIBUTE)
{
if (!id->attrib_img)
return CDK_Inv_Value;
rc =
pkt_write_head (out, old_ctb, id->attrib_len + 6, CDK_PKT_ATTRIBUTE);
if (rc)
return rc;
/* Write subpacket part. */
stream_putc (out, 255);
write_32 (out, id->attrib_len + 1);
stream_putc (out, 1);
rc = stream_write (out, id->attrib_img, id->attrib_len);
}
else
{
if (!id->name)
return CDK_Inv_Value;
rc = pkt_write_head (out, old_ctb, id->len, CDK_PKT_USER_ID);
if (!rc)
rc = stream_write (out, id->name, id->len);
}
return rc;
}
/**
* cdk_pkt_write:
* @out: the output stream handle
* @pkt: the packet itself
*
* Write the contents of @pkt into the @out stream.
* Return 0 on success.
**/
cdk_error_t
cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt)
{
cdk_error_t rc;
if (!out || !pkt)
return CDK_Inv_Value;
_cdk_log_debug ("write packet pkttype=%d\n", pkt->pkttype);
switch (pkt->pkttype)
{
case CDK_PKT_LITERAL:
rc = write_literal (out, pkt->pkt.literal, pkt->old_ctb);
break;
case CDK_PKT_ONEPASS_SIG:
rc = write_onepass_sig (out, pkt->pkt.onepass_sig);
break;
case CDK_PKT_MDC:
rc = write_mdc (out, pkt->pkt.mdc);
break;
case CDK_PKT_SYMKEY_ENC:
rc = write_symkey_enc (out, pkt->pkt.symkey_enc);
break;
case CDK_PKT_ENCRYPTED:
rc = write_encrypted (out, pkt->pkt.encrypted, pkt->old_ctb);
break;
case CDK_PKT_ENCRYPTED_MDC:
rc = write_encrypted_mdc (out, pkt->pkt.encrypted);
break;
case CDK_PKT_PUBKEY_ENC:
rc = write_pubkey_enc (out, pkt->pkt.pubkey_enc, pkt->old_ctb);
break;
case CDK_PKT_SIGNATURE:
rc = write_signature (out, pkt->pkt.signature, pkt->old_ctb);
break;
case CDK_PKT_PUBLIC_KEY:
rc = write_public_key (out, pkt->pkt.public_key, 0, pkt->old_ctb);
break;
case CDK_PKT_PUBLIC_SUBKEY:
rc = write_public_key (out, pkt->pkt.public_key, 1, pkt->old_ctb);
break;
case CDK_PKT_COMPRESSED:
rc = write_compressed (out, pkt->pkt.compressed);
break;
case CDK_PKT_SECRET_KEY:
rc = write_secret_key (out, pkt->pkt.secret_key, 0, pkt->old_ctb);
break;
case CDK_PKT_SECRET_SUBKEY:
rc = write_secret_key (out, pkt->pkt.secret_key, 1, pkt->old_ctb);
break;
case CDK_PKT_USER_ID:
case CDK_PKT_ATTRIBUTE:
rc = write_user_id (out, pkt->pkt.user_id, pkt->old_ctb, pkt->pkttype);
break;
default:
rc = CDK_Inv_Packet;
break;
}
if (DEBUG_PKT)
_cdk_log_debug ("write_packet rc=%d pkttype=%d\n", rc, pkt->pkttype);
return rc;
}
cdk_error_t
_cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx)
{
cdk_packet_t pkt;
cdk_error_t rc;
rc = cdk_pkt_new (&pkt);
if (rc)
return rc;
switch (pkttype)
{
case CDK_PKT_PUBLIC_KEY:
case CDK_PKT_PUBLIC_SUBKEY:
pkt->pkt.public_key = pktctx;
break;
case CDK_PKT_SIGNATURE:
pkt->pkt.signature = pktctx;
break;
case CDK_PKT_SECRET_KEY:
case CDK_PKT_SECRET_SUBKEY:
pkt->pkt.secret_key = pktctx;
break;
case CDK_PKT_USER_ID:
pkt->pkt.user_id = pktctx;
break;
}
pkt->pkttype = pkttype;
rc = cdk_pkt_write (out, pkt);
cdk_free (pkt);
return rc;
}
cdk_error_t
_cdk_pkt_write_fp (FILE * out, cdk_packet_t pkt)
{
cdk_stream_t so;
cdk_error_t rc;
rc = _cdk_stream_fpopen (out, 1, &so);
if (rc)
return rc;
rc = cdk_pkt_write (so, pkt);
cdk_stream_close (so);
return rc;
}
-28
View File
@@ -1,28 +0,0 @@
SUBDIRS = .
AM_CPPFLAGS = \
-I$(top_srcdir)/src/include \
-I$(top_srcdir)/src/daemon/https \
-I$(top_srcdir)/src/daemon/https/lgl \
-I$(top_srcdir)/src/daemon/https/x509 \
-I$(top_srcdir)/src/daemon/https/tls \
-I$(top_srcdir)/src/daemon/https/openpgp \
-I$(top_srcdir)/src/daemon/https/opencdk \
-I$(top_srcdir)/src/daemon/https/minitasn1
noinst_LTLIBRARIES = libopenpgp.la
# libopenpgp_la_LDFLAGS = -l$(top_srcdir)/src/daemon/https/libextra/.lib/libextra.la
libopenpgp_la_SOURCES = \
pgp_privkey.c \
compat.c \
pgp_verify.c \
extras.c \
pgp.c
# x libextra source list
libopenpgp_la_SOURCES += \
gnutls_openpgp.c \
gnutls_ia.c \
gnutls_extra.c
-252
View File
@@ -1,252 +0,0 @@
/*
* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation
*
* Author: Timo Schulz, Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Compatibility functions on OpenPGP key parsing.
*/
#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <gnutls_openpgp.h>
#include "openpgp.h"
/*-
* gnutls_openpgp_verify_key - Verify all signatures on the key
* @cert_list: the structure that holds the certificates.
* @cert_list_lenght: the items in the cert_list.
* @status: the output of the verification function
*
* Verify all signatures in the certificate list. When the key
* is not available, the signature is skipped.
*
* The return value is one of the CertificateStatus entries.
*
* NOTE: this function does not verify using any "web of trust". You
* may use GnuPG for that purpose, or any other external PGP application.
-*/
int
_gnutls_openpgp_verify_key (const mhd_gtls_cert_credentials_t cred,
const gnutls_datum_t * cert_list,
int cert_list_length, unsigned int *status)
{
int ret = 0;
gnutls_openpgp_crt_t key = NULL;
unsigned int verify = 0, verify_self = 0;
if (!cert_list || cert_list_length != 1)
{
gnutls_assert ();
return GNUTLS_E_NO_CERTIFICATE_FOUND;
}
ret = gnutls_openpgp_crt_init (&key);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret =
gnutls_openpgp_crt_import (key, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW);
if (ret < 0)
{
gnutls_assert ();
goto leave;
}
#ifndef KEYRING_HACK
if (cred->keyring != NULL)
{
ret = gnutls_openpgp_crt_verify_ring (key, cred->keyring, 0, &verify);
if (ret < 0)
{
gnutls_assert ();
goto leave;
}
}
#else
{
gnutls_openpgp_keyring_t kring;
ret = gnutls_openpgp_keyring_init (&kring);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret =
gnutls_openpgp_keyring_import (kring, &cred->keyring,
cred->keyring_format);
if (ret < 0)
{
gnutls_assert ();
gnutls_openpgp_keyring_deinit (kring);
return ret;
}
ret = gnutls_openpgp_crt_verify_ring (key, kring, 0, &verify);
if (ret < 0)
{
gnutls_assert ();
gnutls_openpgp_keyring_deinit (kring);
return ret;
}
gnutls_openpgp_keyring_deinit (kring);
}
#endif
/* Now try the self signature. */
ret = gnutls_openpgp_crt_verify_self (key, 0, &verify_self);
if (ret < 0)
{
gnutls_assert ();
goto leave;
}
*status = verify_self | verify;
#ifndef KEYRING_HACK
/* If we only checked the self signature. */
if (!cred->keyring)
#else
if (!cred->keyring.data || !cred->keyring.size)
#endif
*status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
ret = 0;
leave:
gnutls_openpgp_crt_deinit (key);
return ret;
}
/*-
* gnutls_openpgp_fingerprint - Gets the fingerprint
* @cert: the raw data that contains the OpenPGP public key.
* @fpr: the buffer to save the fingerprint.
* @fprlen: the integer to save the length of the fingerprint.
*
* Returns the fingerprint of the OpenPGP key. Depence on the algorithm,
* the fingerprint can be 16 or 20 bytes.
-*/
int
_gnutls_openpgp_fingerprint (const gnutls_datum_t * cert,
unsigned char *fpr, size_t * fprlen)
{
gnutls_openpgp_crt_t key;
int ret;
ret = gnutls_openpgp_crt_init (&key);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = gnutls_openpgp_crt_import (key, cert, GNUTLS_OPENPGP_FMT_RAW);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = gnutls_openpgp_crt_get_fingerprint (key, fpr, fprlen);
gnutls_openpgp_crt_deinit (key);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
return 0;
}
/*-
* gnutls_openpgp_get_raw_key_creation_time - Extract the timestamp
* @cert: the raw data that contains the OpenPGP public key.
*
* Returns the timestamp when the OpenPGP key was created.
-*/
time_t
_gnutls_openpgp_get_raw_key_creation_time (const gnutls_datum_t * cert)
{
gnutls_openpgp_crt_t key;
int ret;
time_t tim;
ret = gnutls_openpgp_crt_init (&key);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = gnutls_openpgp_crt_import (key, cert, GNUTLS_OPENPGP_FMT_RAW);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
tim = gnutls_openpgp_crt_get_creation_time (key);
gnutls_openpgp_crt_deinit (key);
return tim;
}
/*-
* gnutls_openpgp_get_raw_key_expiration_time - Extract the expire date
* @cert: the raw data that contains the OpenPGP public key.
*
* Returns the time when the OpenPGP key expires. A value of '0' means
* that the key doesn't expire at all.
-*/
time_t
_gnutls_openpgp_get_raw_key_expiration_time (const gnutls_datum_t * cert)
{
gnutls_openpgp_crt_t key;
int ret;
time_t tim;
ret = gnutls_openpgp_crt_init (&key);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = gnutls_openpgp_crt_import (key, cert, GNUTLS_OPENPGP_FMT_RAW);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
tim = gnutls_openpgp_crt_get_expiration_time (key);
gnutls_openpgp_crt_deinit (key);
return tim;
}
-170
View File
@@ -1,170 +0,0 @@
/*
* Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos, Timo Schulz
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Functions on OpenPGP keyring parsing
*/
#include <gnutls_int.h>
#include <gnutls_datum.h>
#include <gnutls_global.h>
#include <gnutls_errors.h>
#include <gnutls_openpgp.h>
#include <gnutls_num.h>
#include "openpgp.h"
/* Keyring stuff. */
/**
* gnutls_openpgp_keyring_init - This function initializes a gnutls_openpgp_keyring_t structure
* @keyring: The structure to be initialized
*-
* This function will initialize an OpenPGP keyring structure.
*
* Returns 0 on success.
*
**/
int
gnutls_openpgp_keyring_init (gnutls_openpgp_keyring_t * keyring)
{
*keyring = gnutls_calloc (1, sizeof (gnutls_openpgp_keyring_int));
if (*keyring)
return 0; /* success */
return GNUTLS_E_MEMORY_ERROR;
}
/**
* gnutls_openpgp_keyring_deinit - This function deinitializes memory used by a gnutls_openpgp_keyring_t structure
* @keyring: The structure to be initialized
*
* This function will deinitialize a keyring structure.
*
**/
void
gnutls_openpgp_keyring_deinit (gnutls_openpgp_keyring_t keyring)
{
if (!keyring)
return;
if (keyring->db)
{
cdk_keydb_free (keyring->db);
keyring->db = NULL;
}
/* In some cases the stream is also stored outside the keydb context
and we need to close it here then. */
if (keyring->db_stream)
{
cdk_stream_close (keyring->db_stream);
keyring->db_stream = NULL;
}
gnutls_free (keyring);
}
/**
* gnutls_openpgp_keyring_check_id - Check if a key id exists in the keyring
* @ring: holds the keyring to check against
* @keyid: will hold the keyid to check for.
* @flags: unused (should be 0)
*
* Check if a given key ID exists in the keyring.
*
* Returns 0 on success (if keyid exists) and a negative error code
* on failure.
**/
int
gnutls_openpgp_keyring_check_id (gnutls_openpgp_keyring_t ring,
const unsigned char keyid[8],
unsigned int flags)
{
cdk_pkt_pubkey_t pk;
uint32_t id[2];
id[0] = mhd_gtls_read_uint32 (keyid);
id[1] = mhd_gtls_read_uint32 (&keyid[4]);
if (!cdk_keydb_get_pk (ring->db, id, &pk))
{
cdk_pk_release (pk);
return 0;
}
_gnutls_debug_log ("PGP: key not found %08lX\n", (unsigned long) id[1]);
return GNUTLS_E_NO_CERTIFICATE_FOUND;
}
/**
* gnutls_openpgp_keyring_import - Import a raw- or Base64-encoded OpenPGP keyring
* @keyring: The structure to store the parsed key.
* @data: The RAW or BASE64 encoded keyring.
* @format: One of #gnutls_openpgp_keyring_fmt elements.
*
* This function will convert the given RAW or Base64 encoded keyring to the
* native #gnutls_openpgp_keyring_t format. The output will be stored in
* 'keyring'.
*
* Returns 0 on success.
*
**/
int
gnutls_openpgp_keyring_import (gnutls_openpgp_keyring_t keyring,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format)
{
cdk_error_t err;
cdk_stream_t input;
_gnutls_debug_log ("PGP: keyring import format '%s'\n",
format == GNUTLS_OPENPGP_FMT_RAW ? "raw" : "base64");
if (format == GNUTLS_OPENPGP_FMT_RAW)
{
err
=
cdk_keydb_new (&keyring->db, CDK_DBTYPE_DATA, data->data, data->size);
if (err)
gnutls_assert ();
return _gnutls_map_cdk_rc (err);
}
/* Create a new stream from the given data, which means to
allocate a new stream and to write the data in the stream.
Then push the armor filter to decode the data and to store
it in the raw format. */
err = cdk_stream_tmp_from_mem (data->data, data->size, &input);
if (!err)
err = cdk_stream_set_armor_flag (input, 0);
if (!err)
err = cdk_keydb_new_from_stream (&keyring->db, 0, input);
if (err)
{
cdk_stream_close (input);
gnutls_assert ();
}
else
/* The keydb function will not close the stream itself, so we need to
store it separately to close it later. */
keyring->db_stream = input;
return _gnutls_map_cdk_rc (err);
}
-103
View File
@@ -1,103 +0,0 @@
/*
* Copyright (C) 2001, 2004, 2005, 2007 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <gnutls_extensions.h>
#include <gnutls_openpgp.h>
#include <gnutls_extra.h>
#include <gnutls_extra_hooks.h>
#include <gnutls_algorithms.h>
/* the number of the compression algorithms available in the compression
* structure.
*/
extern int _gnutls_comp_algorithms_size;
/* Functions in gnutls that have not been initialized.
*/
static int _gnutls_init_extra = 0;
/**
* gnutls_global_init_extra - This function initializes the global state of gnutls-extra
*
* This function initializes the global state of gnutls-extra library
* to defaults. Returns zero on success.
*
* Note that MHD_gnutls_global_init() has to be called before this
* function. If this function is not called then the gnutls-extra
* library will not be usable.
*
**/
int
gnutls_global_init_extra (void)
{
/* If the version of libgnutls != version of
* libextra, then do not initialize the library.
* This is because it may break things.
*/
_gnutls_init_extra++;
if (_gnutls_init_extra != 1)
{
return 0;
}
/* Register the openpgp functions. This is because some
* of them are defined to be NULL in the main library.
*/
_gnutls_add_openpgp_functions (_gnutls_openpgp_verify_key,
_gnutls_openpgp_get_raw_key_creation_time,
_gnutls_openpgp_get_raw_key_expiration_time,
_gnutls_openpgp_fingerprint,
_gnutls_openpgp_request_key,
_gnutls_openpgp_raw_key_to_gcert,
_gnutls_openpgp_raw_privkey_to_gkey,
_gnutls_openpgp_crt_to_gcert,
_gnutls_openpgp_privkey_to_gkey,
gnutls_openpgp_crt_deinit,
gnutls_openpgp_keyring_deinit,
gnutls_openpgp_privkey_deinit);
return 0;
}
#include <strverscmp.h>
/**
* gnutls_extra_check_version - This function checks the library's version
* @req_version: the version to check
*
* Check that the version of the gnutls-extra library is at minimum
* the requested one and return the version string; return NULL if the
* condition is not satisfied. If a NULL is passed to this function,
* no check is done, but the version string is simply returned.
*
**/
const char *
gnutls_extra_check_version (const char *req_version)
{
if (!req_version || strverscmp (req_version, VERSION) <= 0)
return VERSION;
return NULL;
}
-50
View File
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* GNUTLS-EXTRA 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNUTLS-EXTRA; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#include <auth_cert.h>
typedef int (*OPENPGP_VERIFY_KEY_FUNC) (const
mhd_gtls_cert_credentials_t,
const gnutls_datum_t *, int,
unsigned int *);
typedef time_t (*OPENPGP_KEY_CREATION_TIME_FUNC) (const gnutls_datum_t *);
typedef time_t (*OPENPGP_KEY_EXPIRATION_TIME_FUNC) (const gnutls_datum_t *);
typedef int (*OPENPGP_KEY_REQUEST) (mhd_gtls_session_t, gnutls_datum_t *,
const mhd_gtls_cert_credentials_t,
opaque *, int);
typedef int (*OPENPGP_FINGERPRINT) (const gnutls_datum_t *,
unsigned char *, size_t *);
typedef int (*OPENPGP_RAW_KEY_TO_GCERT) (gnutls_cert *,
const gnutls_datum_t *);
typedef int (*OPENPGP_RAW_PRIVKEY_TO_GKEY) (gnutls_privkey *,
const gnutls_datum_t *);
typedef int (*OPENPGP_KEY_TO_GCERT) (gnutls_cert *, gnutls_openpgp_crt_t);
typedef int (*OPENPGP_PRIVKEY_TO_GKEY) (gnutls_privkey *,
gnutls_openpgp_privkey_t);
typedef void (*OPENPGP_KEY_DEINIT) (gnutls_openpgp_crt_t);
typedef void (*OPENPGP_PRIVKEY_DEINIT) (gnutls_openpgp_privkey_t);
-901
View File
@@ -1,901 +0,0 @@
/*
* Copyright (C) 2005, 2006 Free Software Foundation
*
* Author: Simon Josefsson
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gnutls_int.h"
#include "gnutls_record.h"
#include "gnutls_errors.h"
#include "gnutls_num.h"
#include "gnutls_state.h"
#define CHECKSUM_SIZE 12
struct gnutls_ia_client_credentials_st
{
gnutls_ia_avp_func avp_func;
void *avp_ptr;
};
struct gnutls_ia_server_credentials_st
{
gnutls_ia_avp_func avp_func;
void *avp_ptr;
};
static const char server_finished_label[] = "server phase finished";
static const char client_finished_label[] = "client phase finished";
static const char inner_permutation_label[] = "inner secret permutation";
static const char challenge_label[] = "inner application challenge";
/*
* The TLS/IA packet is the InnerApplication token, described as
* follows in draft-funk-tls-inner-application-extension-01.txt:
*
* enum {
* application_payload(0), intermediate_phase_finished(1),
* final_phase_finished(2), (255)
* } InnerApplicationType;
*
* struct {
* InnerApplicationType msg_type;
* uint24 length;
* select (InnerApplicationType) {
* case application_payload: ApplicationPayload;
* case intermediate_phase_finished: IntermediatePhaseFinished;
* case final_phase_finished: FinalPhaseFinished;
* } body;
* } InnerApplication;
*
*/
/* Send TLS/IA data. If data==NULL && sizeofdata==NULL, then the last
send was interrupted for some reason, and then we try to send it
again. Returns the number of bytes sent, or an error code. If
this return E_AGAIN and E_INTERRUPTED, call this function again
with data==NULL&&sizeofdata=0NULL until it returns successfully. */
static ssize_t
_gnutls_send_inner_application (mhd_gtls_session_t session,
gnutls_ia_apptype_t msg_type,
const char *data, size_t sizeofdata)
{
opaque *p = NULL;
size_t plen = 0;
ssize_t len;
if (data != NULL)
{
plen = sizeofdata + 4;
p = gnutls_malloc (plen);
if (!p)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
*(unsigned char *) p = (unsigned char) (msg_type & 0xFF);
mhd_gtls_write_uint24 (sizeofdata, p + 1);
memcpy (p + 4, data, sizeofdata);
}
len = mhd_gtls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);
if (p)
gnutls_free (p);
return len;
}
/* Receive TLS/IA data. Store received TLS/IA message type in
*MSG_TYPE, and the data in DATA of max SIZEOFDATA size. Return the
number of bytes read, or an error code. */
static ssize_t
_gnutls_recv_inner_application (mhd_gtls_session_t session,
gnutls_ia_apptype_t * msg_type,
opaque * data, size_t sizeofdata)
{
ssize_t len;
opaque pkt[4];
len = mhd_gtls_recv_int (session, GNUTLS_INNER_APPLICATION, -1, pkt, 4);
if (len != 4)
{
gnutls_assert ();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
*msg_type = pkt[0];
len = mhd_gtls_read_uint24 (&pkt[1]);
if (*msg_type != GNUTLS_IA_APPLICATION_PAYLOAD && len != CHECKSUM_SIZE)
{
gnutls_assert ();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
if (sizeofdata < len)
{
/* XXX push back pkt to IA buffer? */
gnutls_assert ();
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
if (len > 0)
{
int tmplen = len;
len = mhd_gtls_recv_int (session, GNUTLS_INNER_APPLICATION, -1,
data, tmplen);
if (len != tmplen)
{
gnutls_assert ();
/* XXX Correct? */
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
}
return len;
}
/* Apply the TLS PRF using the TLS/IA inner secret as keying material,
where the seed is the client random concatenated with the server
random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
respectively). LABEL and LABEL_SIZE is used as the label. The
result is placed in pre-allocated OUT of OUTSIZE length. */
static int
_gnutls_ia_prf (mhd_gtls_session_t session,
size_t label_size,
const char *label,
size_t extra_size,
const char *extra, size_t outsize, opaque * out)
{
int ret;
opaque *seed;
size_t seedsize = 2 * TLS_RANDOM_SIZE + extra_size;
seed = gnutls_malloc (seedsize);
if (!seed)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
memcpy (seed, session->security_parameters.server_random, TLS_RANDOM_SIZE);
memcpy (seed + TLS_RANDOM_SIZE, session->security_parameters.client_random,
TLS_RANDOM_SIZE);
memcpy (seed + 2 * TLS_RANDOM_SIZE, extra, extra_size);
ret = mhd_gtls_PRF (session, session->security_parameters.inner_secret,
TLS_MASTER_SIZE,
label, label_size, seed, seedsize, outsize, out);
gnutls_free (seed);
return ret;
}
/**
* gnutls_ia_permute_inner_secret:
* @session: is a #mhd_gtls_session_t structure.
* @session_keys_size: Size of generated session keys (0 if none).
* @session_keys: Generated session keys, used to permute inner secret
* (NULL if none).
*
* Permute the inner secret using the generated session keys.
*
* This can be called in the TLS/IA AVP callback to mix any generated
* session keys with the TLS/IA inner secret.
*
* Return value: Return zero on success, or a negative error code.
**/
int
gnutls_ia_permute_inner_secret (mhd_gtls_session_t session,
size_t session_keys_size,
const char *session_keys)
{
return _gnutls_ia_prf (session,
sizeof (inner_permutation_label) - 1,
inner_permutation_label,
session_keys_size,
session_keys,
TLS_RANDOM_SIZE,
session->security_parameters.inner_secret);
}
/**
* gnutls_ia_generate_challenge:
* @session: is a #mhd_gtls_session_t structure.
* @buffer_size: size of output buffer.
* @buffer: pre-allocated buffer to contain @buffer_size bytes of output.
*
* Generate an application challenge that the client cannot control or
* predict, based on the TLS/IA inner secret.
*
* Return value: Returns 0 on success, or an negative error code.
**/
int
gnutls_ia_generate_challenge (mhd_gtls_session_t session,
size_t buffer_size, char *buffer)
{
return _gnutls_ia_prf (session,
sizeof (challenge_label) - 1,
challenge_label, 0, NULL, buffer_size, buffer);
}
/**
* gnutls_ia_extract_inner_secret:
* @session: is a #mhd_gtls_session_t structure.
* @buffer: pre-allocated buffer to hold 48 bytes of inner secret.
*
* Copy the 48 bytes large inner secret into the specified buffer
*
* This function is typically used after the TLS/IA handshake has
* concluded. The TLS/IA inner secret can be used as input to a PRF
* to derive session keys. Do not use the inner secret directly as a
* session key, because for a resumed session that does not include an
* application phase, the inner secret will be identical to the inner
* secret in the original session. It is important to include, for
* example, the client and server randomness when deriving a sesssion
* key from the inner secret.
**/
void
gnutls_ia_extract_inner_secret (mhd_gtls_session_t session, char *buffer)
{
memcpy (buffer, session->security_parameters.inner_secret, TLS_MASTER_SIZE);
}
/**
* gnutls_ia_endphase_send:
* @session: is a #mhd_gtls_session_t structure.
* @final_p: Set iff this should signal the final phase.
*
* Send a TLS/IA end phase message.
*
* In the client, this should only be used to acknowledge an end phase
* message sent by the server.
*
* In the server, this can be called instead of gnutls_ia_send() if
* the server wishes to end an application phase.
*
* Return value: Return 0 on success, or an error code.
**/
int
gnutls_ia_endphase_send (mhd_gtls_session_t session, int final_p)
{
opaque local_checksum[CHECKSUM_SIZE];
int client = session->security_parameters.entity == GNUTLS_CLIENT;
const char *label = client ? client_finished_label : server_finished_label;
int size_of_label = client ? sizeof (client_finished_label) :
sizeof (server_finished_label);
ssize_t len;
int ret;
ret = mhd_gtls_PRF (session, session->security_parameters.inner_secret,
TLS_MASTER_SIZE, label, size_of_label - 1,
/* XXX specification unclear on seed. */
"", 0, CHECKSUM_SIZE, local_checksum);
if (ret < 0)
return ret;
len = _gnutls_send_inner_application
(session,
final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE);
/* XXX Instead of calling this function over and over...?
* while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
* len = mhd_gtls_io_write_flush(session);
*/
if (len < 0)
{
gnutls_assert ();
return len;
}
return 0;
}
/**
* gnutls_ia_verify_endphase:
* @session: is a #mhd_gtls_session_t structure.
* @checksum: 12-byte checksum data, received from gnutls_ia_recv().
*
* Verify TLS/IA end phase checksum data. If verification fails, the
* %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
* sie.
*
* This function is called when gnutls_ia_recv() return
* %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
* %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
*
* Return value: Return 0 on successful verification, or an error
* code. If the checksum verification of the end phase message fails,
* %GNUTLS_E_IA_VERIFY_FAILED is returned.
**/
int
gnutls_ia_verify_endphase (mhd_gtls_session_t session, const char *checksum)
{
char local_checksum[CHECKSUM_SIZE];
int client = session->security_parameters.entity == GNUTLS_CLIENT;
const char *label = client ? server_finished_label : client_finished_label;
int size_of_label = client ? sizeof (server_finished_label) :
sizeof (client_finished_label);
int ret;
ret = mhd_gtls_PRF (session, session->security_parameters.inner_secret,
TLS_MASTER_SIZE,
label, size_of_label - 1,
"", 0, CHECKSUM_SIZE, local_checksum);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
{
ret = MHD_gnutls_alert_send (session, GNUTLS_AL_FATAL,
GNUTLS_A_INNER_APPLICATION_VERIFICATION);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
return GNUTLS_E_IA_VERIFY_FAILED;
}
return 0;
}
/**
* gnutls_ia_send: Send peer the specified TLS/IA data.
* @session: is a #mhd_gtls_session_t structure.
* @data: contains the data to send
* @sizeofdata: is the length of the data
*
* Send TLS/IA application payload data. This function has the
* similar semantics with send(). The only difference is that is
* accepts a GNUTLS session, and uses different error codes.
*
* The TLS/IA protocol is synchronous, so you cannot send more than
* one packet at a time. The client always send the first packet.
*
* To finish an application phase in the server, use
* gnutls_ia_endphase_send(). The client cannot end an application
* phase unilaterally; rather, a client is required to respond with an
* endphase of its own if gnutls_ia_recv indicates that the server has
* sent one.
*
* If the EINTR is returned by the internal push function (the default
* is send()} then %GNUTLS_E_INTERRUPTED will be returned. If
* %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must call
* this function again, with the same parameters; alternatively you
* could provide a %NULL pointer for data, and 0 for size.
*
* Returns the number of bytes sent, or a negative error code.
**/
ssize_t
gnutls_ia_send (mhd_gtls_session_t session, const char *data, size_t sizeofdata)
{
ssize_t len;
len = _gnutls_send_inner_application (session,
GNUTLS_IA_APPLICATION_PAYLOAD,
data, sizeofdata);
return len;
}
/**
* gnutls_ia_recv - read data from the TLS/IA protocol
* @session: is a #mhd_gtls_session_t structure.
* @data: the buffer that the data will be read into, must hold >= 12 bytes.
* @sizeofdata: the number of requested bytes, must be >= 12.
*
* Receive TLS/IA data. This function has the similar semantics with
* recv(). The only difference is that is accepts a GNUTLS session,
* and uses different error codes.
*
* If the server attempt to finish an application phase, this function
* will return %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
* %GNUTLS_E_WARNING_IA_FPHF_RECEIVED. The caller should then invoke
* gnutls_ia_verify_endphase(), and if it runs the client side, also
* send an endphase message of its own using gnutls_ia_endphase_send.
*
* If EINTR is returned by the internal push function (the default is
* @code{recv()}) then GNUTLS_E_INTERRUPTED will be returned. If
* GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN is returned, you must call
* this function again, with the same parameters; alternatively you
* could provide a NULL pointer for data, and 0 for size.
*
* Returns the number of bytes received. A negative error code is
* returned in case of an error. The
* %GNUTLS_E_WARNING_IA_IPHF_RECEIVED and
* %GNUTLS_E_WARNING_IA_FPHF_RECEIVED errors are returned when an
* application phase finished message has been sent by the server.
**/
ssize_t
gnutls_ia_recv (mhd_gtls_session_t session, char *data, size_t sizeofdata)
{
gnutls_ia_apptype_t msg_type;
ssize_t len;
len = _gnutls_recv_inner_application (session, &msg_type, data, sizeofdata);
if (msg_type == GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED)
return GNUTLS_E_WARNING_IA_IPHF_RECEIVED;
else if (msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED)
return GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
return len;
}
int
_gnutls_ia_client_handshake (mhd_gtls_session_t session)
{
char *buf = NULL;
size_t buflen = 0;
char tmp[1024]; /* XXX */
ssize_t len;
int ret;
const struct gnutls_ia_client_credentials_st *cred =
mhd_gtls_get_cred (session->key, MHD_GNUTLS_CRD_IA, NULL);
if (cred == NULL)
return GNUTLS_E_INTERNAL_ERROR;
while (1)
{
char *avp;
size_t avplen;
ret = cred->avp_func (session, cred->avp_ptr,
buf, buflen, &avp, &avplen);
if (ret)
{
int tmpret;
tmpret = MHD_gnutls_alert_send (session, GNUTLS_AL_FATAL,
GNUTLS_A_INNER_APPLICATION_FAILURE);
if (tmpret < 0)
gnutls_assert ();
return ret;
}
len = gnutls_ia_send (session, avp, avplen);
gnutls_free (avp);
if (len < 0)
return len;
len = gnutls_ia_recv (session, tmp, sizeof (tmp));
if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
{
ret = gnutls_ia_verify_endphase (session, tmp);
if (ret < 0)
return ret;
ret = gnutls_ia_endphase_send
(session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED);
if (ret < 0)
return ret;
}
if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
{
buf = NULL;
buflen = 0;
continue;
}
else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
break;
if (len < 0)
return len;
buflen = len;
buf = tmp;
}
return 0;
}
int
_gnutls_ia_server_handshake (mhd_gtls_session_t session)
{
gnutls_ia_apptype_t msg_type;
ssize_t len;
char buf[1024];
int ret;
const struct gnutls_ia_server_credentials_st *cred =
mhd_gtls_get_cred (session->key, MHD_GNUTLS_CRD_IA, NULL);
if (cred == NULL)
return GNUTLS_E_INTERNAL_ERROR;
do
{
char *avp;
size_t avplen;
len = gnutls_ia_recv (session, buf, sizeof (buf));
if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
{
ret = gnutls_ia_verify_endphase (session, buf);
if (ret < 0)
return ret;
}
if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
continue;
else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
break;
if (len < 0)
return len;
avp = NULL;
avplen = 0;
ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen);
if (ret < 0)
{
int tmpret;
tmpret = MHD_gnutls_alert_send (session, GNUTLS_AL_FATAL,
GNUTLS_A_INNER_APPLICATION_FAILURE);
if (tmpret < 0)
gnutls_assert ();
return ret;
}
msg_type = ret;
if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD)
{
ret = gnutls_ia_endphase_send (session, msg_type ==
GNUTLS_IA_FINAL_PHASE_FINISHED);
if (ret < 0)
return ret;
}
else
{
len = gnutls_ia_send (session, avp, avplen);
gnutls_free (avp);
if (len < 0)
return len;
}
}
while (1);
return 0;
}
/**
* gnutls_ia_handshake_p:
* @session: is a #mhd_gtls_session_t structure.
*
* Predicate to be used after MHD_gnutls_handshake() to decide whether to
* invoke gnutls_ia_handshake(). Usable by both clients and servers.
*
* Return value: non-zero if TLS/IA handshake is expected, zero
* otherwise.
**/
int
gnutls_ia_handshake_p (mhd_gtls_session_t session)
{
mhd_gtls_ext_st *ext = &session->security_parameters.extensions;
/* Either local side or peer doesn't do TLS/IA: don't do IA */
if (!ext->gnutls_ia_enable || !ext->gnutls_ia_peer_enable)
return 0;
/* Not resuming or we don't allow skipping on resumption locally: do IA */
if (!ext->gnutls_ia_allowskip || !MHD_gtls_session_is_resumed (session))
return 1;
/* If we're resuming and we and the peer both allow skipping on resumption:
* don't do IA */
return !ext->gnutls_ia_peer_allowskip;
}
/**
* gnutls_ia_handshake:
* @session: is a #mhd_gtls_session_t structure.
*
* Perform a TLS/IA handshake. This should be called after
* MHD_gnutls_handshake() iff gnutls_ia_handshake_p().
*
* Return 0 on success, or an error code.
**/
int
gnutls_ia_handshake (mhd_gtls_session_t session)
{
int ret;
if (session->security_parameters.entity == GNUTLS_CLIENT)
ret = _gnutls_ia_client_handshake (session);
else
ret = _gnutls_ia_server_handshake (session);
return ret;
}
/**
* gnutls_ia_allocate_client_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
* @sc: is a pointer to an #gnutls_ia_server_credentials_t structure.
*
* This structure is complex enough to manipulate directly thus this
* helper function is provided in order to allocate it.
*
* Adding this credential to a session will enable TLS/IA, and will
* require an Application Phase after the TLS handshake (if the server
* support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
* TLS/IA mode.
*
* Returns 0 on success.
**/
int
gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t * sc)
{
*sc = gnutls_calloc (1, sizeof (**sc));
if (*sc == NULL)
return GNUTLS_E_MEMORY_ERROR;
return 0;
}
/**
* gnutls_ia_free_client_credentials - Used to free an allocated #gnutls_ia_client_credentials_t structure
* @sc: is an #gnutls_ia_client_credentials_t structure.
*
* This structure is complex enough to manipulate directly thus this
* helper function is provided in order to free (deallocate) it.
*
**/
void
gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc)
{
gnutls_free (sc);
}
/**
* gnutls_ia_set_client_avp_function - Used to set a AVP callback
* @cred: is a #gnutls_ia_client_credentials_t structure.
* @avp_func: is the callback function
*
* Set the TLS/IA AVP callback handler used for the session.
*
* The AVP callback is called to process AVPs received from the
* server, and to get a new AVP to send to the server.
*
* The callback's function form is:
* int (*avp_func) (mhd_gtls_session_t session, void *ptr,
* const char *last, size_t lastlen,
* char **next, size_t *nextlen);
*
* The @session parameter is the #mhd_gtls_session_t structure
* corresponding to the current session. The @ptr parameter is the
* application hook pointer, set through
* gnutls_ia_set_client_avp_ptr(). The AVP received from the server
* is present in @last of @lastlen size, which will be %NULL on the
* first invocation. The newly allocated output AVP to send to the
* server should be placed in *@next of *@nextlen size.
*
* The callback may invoke gnutls_ia_permute_inner_secret() to mix any
* generated session keys with the TLS/IA inner secret.
*
* Return 0 (%GNUTLS_IA_APPLICATION_PAYLOAD) on success, or a negative
* error code to abort the TLS/IA handshake.
*
* Note that the callback must use allocate the @next parameter using
* gnutls_malloc(), because it is released via gnutls_free() by the
* TLS/IA handshake function.
*
**/
void
gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
gnutls_ia_avp_func avp_func)
{
cred->avp_func = avp_func;
}
/**
* gnutls_ia_set_client_avp_ptr - Sets a pointer to be sent to TLS/IA callback
* @cred: is a #gnutls_ia_client_credentials_t structure.
* @ptr: is the pointer
*
* Sets the pointer that will be provided to the TLS/IA callback
* function as the first argument.
*
**/
void
gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred, void *ptr)
{
cred->avp_ptr = ptr;
}
/**
* gnutls_ia_get_client_avp_ptr - Returns the pointer which is sent to TLS/IA callback
* @cred: is a #gnutls_ia_client_credentials_t structure.
*
* Returns the pointer that will be provided to the TLS/IA callback
* function as the first argument.
*
**/
void *
gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred)
{
return cred->avp_ptr;
}
/**
* gnutls_ia_allocate_server_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
* @sc: is a pointer to an #gnutls_ia_server_credentials_t structure.
*
* This structure is complex enough to manipulate directly thus this
* helper function is provided in order to allocate it.
*
* Adding this credential to a session will enable TLS/IA, and will
* require an Application Phase after the TLS handshake (if the client
* support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
* TLS/IA mode.
*
* Returns 0 on success.
**/
int
gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t * sc)
{
*sc = gnutls_calloc (1, sizeof (**sc));
if (*sc == NULL)
return GNUTLS_E_MEMORY_ERROR;
return 0;
}
/**
* gnutls_ia_free_server_credentials - Used to free an allocated #gnutls_ia_server_credentials_t structure
* @sc: is an #gnutls_ia_server_credentials_t structure.
*
* This structure is complex enough to manipulate directly thus this
* helper function is provided in order to free (deallocate) it.
*
**/
void
gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc)
{
gnutls_free (sc);
}
/**
* gnutls_ia_set_server_credentials_function - Used to set a AVP callback
* @cred: is a #gnutls_ia_server_credentials_t structure.
* @func: is the callback function
*
* Set the TLS/IA AVP callback handler used for the session.
*
* The callback's function form is:
* int (*avp_func) (mhd_gtls_session_t session, void *ptr,
* const char *last, size_t lastlen,
* char **next, size_t *nextlen);
*
* The @session parameter is the #mhd_gtls_session_t structure
* corresponding to the current session. The @ptr parameter is the
* application hook pointer, set through
* gnutls_ia_set_server_avp_ptr(). The AVP received from the client
* is present in @last of @lastlen size. The newly allocated output
* AVP to send to the client should be placed in *@next of *@nextlen
* size.
*
* The AVP callback is called to process incoming AVPs from the
* client, and to get a new AVP to send to the client. It can also be
* used to instruct the TLS/IA handshake to do go into the
* Intermediate or Final phases. It return a negative error code, or
* an #gnutls_ia_apptype_t message type.
*
* The callback may invoke gnutls_ia_permute_inner_secret() to mix any
* generated session keys with the TLS/IA inner secret.
*
* Specifically, return %GNUTLS_IA_APPLICATION_PAYLOAD (0) to send
* another AVP to the client, return
* %GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED (1) to indicate that an
* IntermediatePhaseFinished message should be sent, and return
* %GNUTLS_IA_FINAL_PHASE_FINISHED (2) to indicate that an
* FinalPhaseFinished message should be sent. In the last two cases,
* the contents of the @next and @nextlen parameter is not used.
*
* Note that the callback must use allocate the @next parameter using
* gnutls_malloc(), because it is released via gnutls_free() by the
* TLS/IA handshake function.
**/
void
gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
gnutls_ia_avp_func avp_func)
{
cred->avp_func = avp_func;
}
/**
* gnutls_ia_set_server_avp_ptr - Sets a pointer to be sent to TLS/IA callback
* @cred: is a #gnutls_ia_client_credentials_t structure.
* @ptr: is the pointer
*
* Sets the pointer that will be provided to the TLS/IA callback
* function as the first argument.
*
**/
void
gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred, void *ptr)
{
cred->avp_ptr = ptr;
}
/**
* gnutls_ia_get_server_avp_ptr - Returns the pointer which is sent to TLS/IA callback
* @cred: is a #gnutls_ia_client_credentials_t structure.
*
* Returns the pointer that will be provided to the TLS/IA callback
* function as the first argument.
*
**/
void *
gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred)
{
return cred->avp_ptr;
}
/**
* gnutls_ia_enable - Indicate willingness for TLS/IA application phases
* @session: is a #mhd_gtls_session_t structure.
* @allow_skip_on_resume: non-zero if local party allows to skip the
* TLS/IA application phases for a resumed session.
*
* Specify whether we must advertise support for the TLS/IA extension
* during the handshake.
*
* At the client side, we always advertise TLS/IA if gnutls_ia_enable
* was called before the handshake; at the server side, we also
* require that the client has advertised that it wants to run TLS/IA
* before including the advertisement, as required by the protocol.
*
* Similarly, at the client side we always advertise that we allow
* TLS/IA to be skipped for resumed sessions if @allow_skip_on_resume
* is non-zero; at the server side, we also require that the session
* is indeed resumable and that the client has also advertised that it
* allows TLS/IA to be skipped for resumed sessions.
*
* After the TLS handshake, call gnutls_ia_handshake_p() to find out
* whether both parties agreed to do a TLS/IA handshake, before
* calling gnutls_ia_handshake() or one of the lower level gnutls_ia_*
* functions.
**/
void
gnutls_ia_enable (mhd_gtls_session_t session, int allow_skip_on_resume)
{
session->security_parameters.extensions.gnutls_ia_enable = 1;
session->security_parameters.extensions.gnutls_ia_allowskip =
allow_skip_on_resume;
}
-966
View File
@@ -1,966 +0,0 @@
/*
* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
*
* Author: Timo Schulz
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gnutls_int.h"
#include "gnutls_errors.h"
#include "gnutls_mpi.h"
#include "gnutls_cert.h"
#include "gnutls_datum.h"
#include "gnutls_global.h"
#include "gnutls_openpgp.h"
#include "read-file.h"
#include <gnutls_str.h>
#include <gnutls_sig.h>
#include <stdio.h>
#include <gcrypt.h>
#include <time.h>
#include <sys/stat.h>
#define OPENPGP_NAME_SIZE 256
#define datum_append(x, y, z) mhd_gtls_datum_append_m (x, y, z, gnutls_realloc)
static void
release_mpi_array (mpi_t * arr, size_t n)
{
mpi_t x;
while (arr && n--)
{
x = *arr;
mhd_gtls_mpi_release (&x);
*arr = NULL;
arr++;
}
}
/* Map an OpenCDK error type to a GnuTLS error type. */
int
_gnutls_map_cdk_rc (int rc)
{
switch (rc)
{
case CDK_Success:
return 0;
case CDK_Too_Short:
return GNUTLS_E_SHORT_MEMORY_BUFFER;
case CDK_General_Error:
return GNUTLS_E_INTERNAL_ERROR;
case CDK_File_Error:
return GNUTLS_E_FILE_ERROR;
case CDK_MPI_Error:
return GNUTLS_E_MPI_SCAN_FAILED;
case CDK_Error_No_Key:
return GNUTLS_E_OPENPGP_GETKEY_FAILED;
case CDK_Armor_Error:
return GNUTLS_E_BASE64_DECODING_ERROR;
case CDK_Inv_Value:
return GNUTLS_E_INVALID_REQUEST;
default:
return GNUTLS_E_INTERNAL_ERROR;
}
}
static unsigned long
buftou32 (const uint8_t * buf)
{
unsigned a;
a = buf[0] << 24;
a |= buf[1] << 16;
a |= buf[2] << 8;
a |= buf[3];
return a;
}
static int
openpgp_pk_to_gnutls_cert (gnutls_cert * cert, cdk_pkt_pubkey_t pk)
{
uint8_t buf[512 + 2];
size_t nbytes;
int algo, i;
int rc = 0;
if (!cert || !pk)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
/* GnuTLS OpenPGP does not support ELG keys */
if (is_ELG (pk->pubkey_algo))
{
gnutls_assert ();
return GNUTLS_E_UNWANTED_ALGORITHM;
}
algo = MHD_GNUTLS_PK_RSA;
cert->subject_pk_algorithm = algo;
cert->version = pk->version;
cert->cert_type = MHD_GNUTLS_CRT_OPENPGP;
cert->key_usage = 0;
if (pk->pubkey_usage & CDK_KEY_USG_SIGN)
cert->key_usage = KEY_DIGITAL_SIGNATURE;
if (pk->pubkey_usage & CDK_KEY_USG_ENCR)
cert->key_usage = KEY_KEY_ENCIPHERMENT;
if (!cert->key_usage) /* Fallback code. */
{
if (pk->pubkey_algo == GCRY_PK_DSA || pk->pubkey_algo == GCRY_PK_RSA_S)
cert->key_usage = KEY_DIGITAL_SIGNATURE;
else if (pk->pubkey_algo == GCRY_PK_RSA_E)
cert->key_usage = KEY_KEY_ENCIPHERMENT;
else if (pk->pubkey_algo == GCRY_PK_RSA)
cert->key_usage = KEY_DIGITAL_SIGNATURE | KEY_KEY_ENCIPHERMENT;
}
cert->params_size = cdk_pk_get_npkey (pk->pubkey_algo);
for (i = 0; i < cert->params_size; i++)
{
nbytes = sizeof (buf) / sizeof (buf[0]);
cdk_pk_get_mpi (pk, i, buf, nbytes, &nbytes, NULL);
rc = mhd_gtls_mpi_scan_pgp (&cert->params[i], buf, &nbytes);
if (rc)
{
rc = GNUTLS_E_MPI_SCAN_FAILED;
break;
}
}
if (rc)
release_mpi_array (cert->params, i - 1);
return rc;
}
/*-
* _gnutls_openpgp_raw_privkey_to_gkey - Converts an OpenPGP secret key to GnuTLS
* @pkey: the GnuTLS private key context to store the key.
* @raw_key: the raw data which contains the whole key packets.
* @format: the format of the key packets.
*
* The RFC2440 (OpenPGP Message Format) data is converted into the
* GnuTLS specific data which is need to perform secret key operations.
*
* This function can read both BASE64 and RAW keys.
-*/
int
_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey * pkey,
const gnutls_datum_t * raw_key,
gnutls_openpgp_crt_fmt_t format)
{
cdk_kbnode_t snode = NULL;
cdk_packet_t pkt;
cdk_stream_t out;
cdk_pkt_seckey_t sk = NULL;
int pke_algo, i, j;
size_t nbytes = 0;
uint8_t buf[512];
int rc = 0;
if (!pkey || raw_key->size <= 0)
{
gnutls_assert ();
return GNUTLS_E_CERTIFICATE_ERROR;
}
rc = cdk_stream_tmp_new (&out);
if (rc)
return GNUTLS_E_CERTIFICATE_ERROR;
if (format == GNUTLS_OPENPGP_FMT_BASE64)
{
rc = cdk_stream_set_armor_flag (out, 0);
if (rc)
{
cdk_stream_close (out);
rc = _gnutls_map_cdk_rc (rc);
gnutls_assert ();
goto leave;
}
}
cdk_stream_write (out, raw_key->data, raw_key->size);
cdk_stream_seek (out, 0);
rc = cdk_keydb_get_keyblock (out, &snode);
cdk_stream_close (out);
if (rc)
{
rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
goto leave;
}
pkt = cdk_kbnode_find_packet (snode, CDK_PKT_SECRET_KEY);
if (!pkt)
{
rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
goto leave;
}
sk = pkt->pkt.secret_key;
pke_algo = sk->pk->pubkey_algo;
pkey->params_size = cdk_pk_get_npkey (pke_algo);
for (i = 0; i < pkey->params_size; i++)
{
nbytes = sizeof (buf) / sizeof (buf[0]);
cdk_pk_get_mpi (sk->pk, i, buf, nbytes, &nbytes, NULL);
rc = mhd_gtls_mpi_scan_pgp (&pkey->params[i], buf, &nbytes);
if (rc)
{
rc = GNUTLS_E_MPI_SCAN_FAILED;
release_mpi_array (pkey->params, i - 1);
goto leave;
}
}
pkey->params_size += cdk_pk_get_nskey (pke_algo);
for (j = 0; j < cdk_pk_get_nskey (pke_algo); j++, i++)
{
nbytes = sizeof (buf) / sizeof (buf[0]);
cdk_sk_get_mpi (sk, j, buf, nbytes, &nbytes, NULL);
rc = mhd_gtls_mpi_scan_pgp (&pkey->params[i], buf, &nbytes);
if (rc)
{
rc = GNUTLS_E_MPI_SCAN_FAILED;
release_mpi_array (pkey->params, i - 1);
goto leave;
}
}
if (is_ELG (pke_algo))
return GNUTLS_E_UNWANTED_ALGORITHM;
else if (is_RSA (pke_algo))
pkey->pk_algorithm = MHD_GNUTLS_PK_RSA;
leave:
cdk_kbnode_release (snode);
return rc;
}
/*-
* _gnutls_openpgp_raw_key_to_gcert - Converts raw OpenPGP data to GnuTLS certs
* @cert: the certificate to store the data.
* @raw: the buffer which contains the whole OpenPGP key packets.
*
* The RFC2440 (OpenPGP Message Format) data is converted to a GnuTLS
* specific certificate.
-*/
int
_gnutls_openpgp_raw_key_to_gcert (gnutls_cert * cert,
const gnutls_datum_t * raw)
{
cdk_kbnode_t knode = NULL;
cdk_packet_t pkt = NULL;
int rc;
if (!cert)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
memset (cert, 0, sizeof *cert);
rc = cdk_kbnode_read_from_mem (&knode, raw->data, raw->size);
if (!(rc = _gnutls_map_cdk_rc (rc)))
{
pkt = cdk_kbnode_find_packet (knode, CDK_PKT_PUBLIC_KEY);
}
if (!pkt)
{
gnutls_assert ();
rc = _gnutls_map_cdk_rc (rc);
}
if (!rc)
rc = _gnutls_set_datum (&cert->raw, raw->data, raw->size);
if (!rc)
rc = openpgp_pk_to_gnutls_cert (cert, pkt->pkt.public_key);
cdk_kbnode_release (knode);
return rc;
}
/**
* gnutls_certificate_set_openpgp_key - Used to set keys in a mhd_gtls_cert_credentials_t structure
* @res: is an #mhd_gtls_cert_credentials_t structure.
* @key: contains an openpgp public key
* @pkey: is an openpgp private key
*
* This function sets a certificate/private key pair in the
* mhd_gtls_cert_credentials_t structure. This function may be called
* more than once (in case multiple keys/certificates exist for the
* server).
*
**/
int
gnutls_certificate_set_openpgp_key (mhd_gtls_cert_credentials_t
res, gnutls_openpgp_crt_t crt,
gnutls_openpgp_privkey_t pkey)
{
int ret;
/* this should be first */
res->pkey = mhd_gtls_realloc_fast (res->pkey,
(res->ncerts + 1) *
sizeof (gnutls_privkey));
if (res->pkey == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
ret = _gnutls_openpgp_privkey_to_gkey (&res->pkey[res->ncerts], pkey);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
res->cert_list = mhd_gtls_realloc_fast (res->cert_list,
(1 +
res->ncerts) *
sizeof (gnutls_cert *));
if (res->cert_list == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
res->cert_list_length = mhd_gtls_realloc_fast (res->cert_list_length,
(1 +
res->ncerts) * sizeof (int));
if (res->cert_list_length == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
res->cert_list[res->ncerts] = gnutls_calloc (1, sizeof (gnutls_cert));
if (res->cert_list[res->ncerts] == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
res->cert_list_length[res->ncerts] = 1;
ret = _gnutls_openpgp_crt_to_gcert (res->cert_list[res->ncerts], crt);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
res->ncerts++;
/* FIXME: Check if the keys match. */
return 0;
}
/*-
* gnutls_openpgp_get_key - Retrieve a key from the keyring.
* @key: the destination context to save the key.
* @keyring: the datum struct that contains all keyring information.
* @attr: The attribute (keyid, fingerprint, ...).
* @by: What attribute is used.
*
* This function can be used to retrieve keys by different pattern
* from a binary or a file keyring.
-*/
int
gnutls_openpgp_get_key (gnutls_datum_t * key,
gnutls_openpgp_keyring_t keyring, key_attr_t by,
opaque * pattern)
{
cdk_kbnode_t knode = NULL;
unsigned long keyid[2];
unsigned char *buf;
void *desc;
size_t len;
int rc = 0;
if (!key || !keyring || by == KEY_ATTR_NONE)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
memset (key, 0, sizeof *key);
if (by == KEY_ATTR_SHORT_KEYID)
{
keyid[0] = buftou32 (pattern);
desc = keyid;
}
else if (by == KEY_ATTR_KEYID)
{
keyid[0] = buftou32 (pattern);
keyid[1] = buftou32 (pattern + 4);
desc = keyid;
}
else
desc = pattern;
rc = cdk_keydb_search_start (keyring->db, by, desc);
if (!rc)
rc = cdk_keydb_search (keyring->db, &knode);
if (rc)
{
rc = _gnutls_map_cdk_rc (rc);
goto leave;
}
if (!cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY))
{
rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
goto leave;
}
/* We let the function allocate the buffer to avoid
to call the function twice. */
rc = cdk_kbnode_write_to_mem_alloc (knode, &buf, &len);
if (!rc)
datum_append (key, buf, len);
cdk_free (buf);
leave:
cdk_kbnode_release (knode);
return rc;
}
/* Convert the stream to a datum. In this case we use the mmap
function to map the entire stream to a buffer. */
static int
stream_to_datum (cdk_stream_t inp, gnutls_datum_t * raw)
{
uint8_t *buf;
size_t buflen;
if (!inp || !raw)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
cdk_stream_mmap (inp, &buf, &buflen);
datum_append (raw, buf, buflen);
cdk_free (buf);
if (!buflen)
{
gnutls_assert ();
return GNUTLS_E_INTERNAL_ERROR;
}
return 0;
}
/**
* gnutls_certificate_set_openpgp_key_mem - Used to set OpenPGP keys
* @res: the destination context to save the data.
* @cert: the datum that contains the public key.
* @key: the datum that contains the secret key.
*
* This funtion is used to load OpenPGP keys into the GnuTLS credential
* structure.
* It doesn't matter whether the keys are armored or not, but the files
* should only contain one key which should not be encrypted.
**/
int
gnutls_certificate_set_openpgp_key_mem (mhd_gtls_cert_credentials_t
res, const gnutls_datum_t * icert,
const gnutls_datum_t * ikey,
gnutls_openpgp_crt_fmt_t format)
{
gnutls_openpgp_privkey_t key;
gnutls_openpgp_crt_t cert;
int ret;
ret = gnutls_openpgp_privkey_init (&key);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = gnutls_openpgp_privkey_import (key, ikey, format, NULL, 0);
if (ret < 0)
{
gnutls_assert ();
gnutls_openpgp_privkey_deinit (key);
return ret;
}
ret = gnutls_openpgp_crt_init (&cert);
if (ret < 0)
{
gnutls_assert ();
gnutls_openpgp_privkey_deinit (key);
return ret;
}
ret = gnutls_openpgp_crt_import (cert, icert, format);
if (ret < 0)
{
gnutls_assert ();
gnutls_openpgp_privkey_deinit (key);
gnutls_openpgp_crt_deinit (cert);
return ret;
}
ret = gnutls_certificate_set_openpgp_key (res, cert, key);
gnutls_openpgp_privkey_deinit (key);
gnutls_openpgp_crt_deinit (cert);
return ret;
}
/**
* gnutls_certificate_set_openpgp_key_file - Used to set OpenPGP keys
* @res: the destination context to save the data.
* @certfile: the file that contains the public key.
* @keyfile: the file that contains the secret key.
*
* This funtion is used to load OpenPGP keys into the GnuTLS credentials structure.
* It doesn't matter whether the keys are armored or not, but the files
* should only contain one key which should not be encrypted.
**/
int
gnutls_certificate_set_openpgp_key_file (mhd_gtls_cert_credentials_t
res, const char *certfile,
const char *keyfile,
gnutls_openpgp_crt_fmt_t format)
{
struct stat statbuf;
gnutls_datum_t key, cert;
int rc;
size_t size;
if (!res || !keyfile || !certfile)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (stat (certfile, &statbuf) || stat (keyfile, &statbuf))
{
gnutls_assert ();
return GNUTLS_E_FILE_ERROR;
}
cert.data = read_binary_file (certfile, &size);
cert.size = (unsigned int) size;
if (cert.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_FILE_ERROR;
}
key.data = read_binary_file (keyfile, &size);
key.size = (unsigned int) size;
if (key.data == NULL)
{
gnutls_assert ();
free (cert.data);
return GNUTLS_E_FILE_ERROR;
}
rc = gnutls_certificate_set_openpgp_key_mem (res, &cert, &key, format);
free (cert.data);
free (key.data);
if (rc < 0)
{
gnutls_assert ();
return rc;
}
return 0;
}
int
gnutls_openpgp_count_key_names (const gnutls_datum_t * cert)
{
cdk_kbnode_t knode, p, ctx;
cdk_packet_t pkt;
int nuids;
if (cert == NULL)
{
gnutls_assert ();
return 0;
}
if (cdk_kbnode_read_from_mem (&knode, cert->data, cert->size))
{
gnutls_assert ();
return 0;
}
ctx = NULL;
for (nuids = 0;;)
{
p = cdk_kbnode_walk (knode, &ctx, 0);
if (!p)
break;
pkt = cdk_kbnode_get_packet (p);
if (pkt->pkttype == CDK_PKT_USER_ID)
nuids++;
}
cdk_kbnode_release (knode);
return nuids;
}
/**
* gnutls_certificate_set_openpgp_keyring_file - Sets a keyring file for OpenPGP
* @c: A certificate credentials structure
* @file: filename of the keyring.
*
* The function is used to set keyrings that will be used internally
* by various OpenPGP functions. For example to find a key when it
* is needed for an operations. The keyring will also be used at the
* verification functions.
*
**/
int
gnutls_certificate_set_openpgp_keyring_file (mhd_gtls_cert_credentials_t
c, const char *file,
gnutls_openpgp_crt_fmt_t format)
{
gnutls_datum_t ring;
size_t size;
int rc;
if (!c || !file)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ring.data = read_binary_file (file, &size);
ring.size = (unsigned int) size;
if (ring.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_FILE_ERROR;
}
rc =
gnutls_certificate_set_openpgp_keyring_mem (c, ring.data, ring.size,
format);
free (ring.data);
return rc;
}
/**
* gnutls_certificate_set_openpgp_keyring_mem - Add keyring data for OpenPGP
* @c: A certificate credentials structure
* @data: buffer with keyring data.
* @dlen: length of data buffer.
*
* The function is used to set keyrings that will be used internally
* by various OpenPGP functions. For example to find a key when it
* is needed for an operations. The keyring will also be used at the
* verification functions.
*
**/
int
gnutls_certificate_set_openpgp_keyring_mem (mhd_gtls_cert_credentials_t
c, const opaque * data,
size_t dlen,
gnutls_openpgp_crt_fmt_t format)
{
#ifndef KEYRING_HACK
cdk_stream_t inp;
size_t count;
uint8_t *buf;
gnutls_datum ddata;
int rc;
ddata.data = (void *) data;
ddata.size = dlen;
if (!c || !data || !dlen)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
rc = gnutls_openpgp_keyring_init (&c->keyring);
if (rc < 0)
{
gnutls_assert ();
return rc;
}
rc = gnutls_openpgp_keyring_import (c->keyring, &ddata, format);
if (rc < 0)
{
gnutls_assert ();
gnutls_openpgp_keyring_deinit (c->keyring);
return rc;
}
#else
c->keyring_format = format;
c->keyring.data = gnutls_malloc (dlen + 1);
if (c->keyring.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
memcpy (c->keyring.data, data, dlen);
c->keyring.data[dlen] = 0;
c->keyring.size = dlen;
#endif
return 0;
}
/*-
* _gnutls_openpgp_request_key - Receives a key from a database, key server etc
* @ret - a pointer to gnutls_datum_t structure.
* @cred - a mhd_gtls_cert_credentials_t structure.
* @key_fingerprint - The keyFingerprint
* @key_fingerprint_size - the size of the fingerprint
*
* Retrieves a key from a local database, keyring, or a key server. The
* return value is locally allocated.
*
-*/
int
_gnutls_openpgp_request_key (mhd_gtls_session_t session, gnutls_datum_t * ret,
const mhd_gtls_cert_credentials_t cred,
opaque * key_fpr, int key_fpr_size)
{
int rc = 0;
#ifdef KEYRING_HACK
gnutls_openpgp_keyring_t kring;
#endif
if (!ret || !cred || !key_fpr)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (key_fpr_size != 16 && key_fpr_size != 20)
return GNUTLS_E_HASH_FAILED; /* only MD5 and SHA1 are supported */
#ifndef KEYRING_HACK
rc = gnutls_openpgp_get_key (ret, cred->keyring, KEY_ATTR_FPR, key_fpr);
#else
rc = gnutls_openpgp_keyring_init (&kring);
if (rc < 0)
{
gnutls_assert ();
return rc;
}
rc =
gnutls_openpgp_keyring_import (kring, &cred->keyring,
cred->keyring_format);
if (rc < 0)
{
gnutls_assert ();
gnutls_openpgp_keyring_deinit (kring);
return rc;
}
#endif
if (rc >= 0) /* key was found */
{
rc = 0;
goto error;
}
else
rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
/* If the callback function was set, then try this one. */
if (session->internals.openpgp_recv_key_func != NULL)
{
rc = session->internals.openpgp_recv_key_func (session,
key_fpr,
key_fpr_size, ret);
if (rc < 0)
{
gnutls_assert ();
rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
goto error;
}
}
error:
#ifdef KEYRING_HACK
gnutls_openpgp_keyring_deinit (kring);
#endif
return rc;
}
/**
* gnutls_openpgp_set_recv_key_function - Used to set a key retrieval callback for PGP keys
* @session: a TLS session
* @func: the callback
*
* This funtion will set a key retrieval function for OpenPGP keys. This
* callback is only useful in server side, and will be used if the peer
* sent a key fingerprint instead of a full key.
*
**/
void
gnutls_openpgp_set_recv_key_function (mhd_gtls_session_t session,
mhd_gtls_openpgp_recv_key_func func)
{
session->internals.openpgp_recv_key_func = func;
}
/* Copies a gnutls_openpgp_privkey_t to a gnutls_privkey structure. */
int
_gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
gnutls_openpgp_privkey_t src)
{
int i, ret;
memset (dest, 0, sizeof (gnutls_privkey));
for (i = 0; i < src->pkey.params_size; i++)
{
dest->params[i] = _gnutls_mpi_copy (src->pkey.params[i]);
if (dest->params[i] == NULL)
{
gnutls_assert ();
ret = GNUTLS_E_MEMORY_ERROR;
goto cleanup;
}
}
dest->pk_algorithm = src->pkey.pk_algorithm;
dest->params_size = src->pkey.params_size;
return 0;
cleanup:
for (i = 0; i < src->pkey.params_size; i++)
mhd_gtls_mpi_release (&dest->params[i]);
return ret;
}
/* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure.
*/
int
_gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, gnutls_openpgp_crt_t cert)
{
opaque *der;
size_t der_size = 0;
gnutls_datum_t raw;
int ret;
memset (gcert, 0, sizeof (gnutls_cert));
gcert->cert_type = MHD_GNUTLS_CRT_OPENPGP;
ret = gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW,
NULL, &der_size);
if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
gnutls_assert ();
return ret;
}
der = gnutls_malloc (der_size);
if (der == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
ret = gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW,
der, &der_size);
if (ret < 0)
{
gnutls_assert ();
gnutls_free (der);
return ret;
}
raw.data = der;
raw.size = der_size;
ret = _gnutls_openpgp_raw_key_to_gcert (gcert, &raw);
if (ret < 0)
{
gnutls_assert ();
gnutls_free (der);
return ret;
}
gnutls_free (der);
return 0;
}
/**
* gnutls_openpgp_privkey_sign_hash - This function will sign the given data using the private key params
* @key: Holds the key
* @hash: holds the data to be signed
* @signature: will contain newly allocated signature
*
* This function will sign the given hash using the private key.
*
* Return value: In case of failure a negative value will be returned,
* and 0 on success.
**/
int
gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key,
const gnutls_datum_t * hash,
gnutls_datum_t * signature)
{
int result;
if (key == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
result = mhd_gtls_sign (key->pkey.pk_algorithm, key->pkey.params,
key->pkey.params_size, hash, signature);
if (result < 0)
{
gnutls_assert ();
return result;
}
return 0;
}
-98
View File
@@ -1,98 +0,0 @@
#include <config.h>
#if ENABLE_OPENPGP
#ifndef GNUTLS_OPENPGP_H
#define GNUTLS_OPENPGP_H
#include <auth_cert.h>
#include <opencdk.h>
typedef struct
{
int type;
size_t size;
uint8_t *data;
}keybox_blob;
typedef enum
{
KBX_BLOB_FILE = 0x00,
KBX_BLOB_DATA = 0x01
}keyring_blob_types;
/* OpenCDK compatible */
typedef enum
{
KEY_ATTR_NONE = 0,
KEY_ATTR_SHORT_KEYID = 3,
KEY_ATTR_KEYID = 4,
KEY_ATTR_FPR = 5
}key_attr_t;
int
gnutls_certificate_set_openpgp_key_file (mhd_gtls_cert_credentials_t
res, const char *CERTFILE,
const char *KEYFILE, gnutls_openpgp_crt_fmt_t);
int gnutls_openpgp_count_key_names (const gnutls_datum_t * cert);
int gnutls_certificate_set_openpgp_keyring_file
(mhd_gtls_cert_credentials_t c, const char *file, gnutls_openpgp_crt_fmt_t);
int
gnutls_certificate_set_openpgp_keyring_mem (mhd_gtls_cert_credentials_t
c, const opaque * data,
size_t dlen, gnutls_openpgp_crt_fmt_t);
int gnutls_openpgp_get_key (gnutls_datum_t * key,
gnutls_openpgp_keyring_t keyring,
key_attr_t by, opaque * pattern);
int gnutls_openpgp_recv_key (const char *host,
short port, uint32_t keyid,
gnutls_datum_t * key);
/* internal */
int _gnutls_openpgp_raw_key_to_gcert (gnutls_cert * cert,
const gnutls_datum_t * raw);
extern int
_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey * pkey,
const gnutls_datum_t * raw_key,
gnutls_openpgp_crt_fmt_t format);
int
_gnutls_openpgp_request_key (mhd_gtls_session_t,
gnutls_datum_t * ret,
const mhd_gtls_cert_credentials_t cred,
opaque * key_fpr, int key_fpr_size);
int _gnutls_openpgp_verify_key (const mhd_gtls_cert_credentials_t,
const gnutls_datum_t * cert_list,
int cert_list_length, unsigned int *status);
int _gnutls_openpgp_fingerprint (const gnutls_datum_t * cert,
unsigned char *fpr, size_t * fprlen);
time_t _gnutls_openpgp_get_raw_key_creation_time (const gnutls_datum_t *
cert);
time_t _gnutls_openpgp_get_raw_key_expiration_time (const gnutls_datum_t *
cert);
int
gnutls_openpgp_privkey_init (gnutls_openpgp_privkey_t * key);
int
gnutls_openpgp_privkey_init (gnutls_openpgp_privkey_t * key);
void
gnutls_openpgp_privkey_deinit (gnutls_openpgp_privkey_t key);
int
gnutls_openpgp_privkey_import (gnutls_openpgp_privkey_t key,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format,
const char *pass, unsigned int flags);
#endif /*GNUTLS_OPENPGP_H */
#endif /*ENABLE_OPENPGP */
-182
View File
@@ -1,182 +0,0 @@
#ifndef OPENPGP_H
#define OPENPGP_H
#include "config.h"
#if ENABLE_OPENPGP
#ifdef __cplusplus
extern "C"
{
#endif
#include <gnutls.h>
#include "opencdk.h"
#include <gnutls_cert.h>
/* Internal context to store the OpenPGP key. */
typedef struct gnutls_openpgp_crt_int
{
cdk_kbnode_t knode;
} gnutls_openpgp_crt_int;
/* Internal context to store the private OpenPGP key. */
typedef struct gnutls_openpgp_privkey_int
{
gnutls_privkey pkey;
} gnutls_openpgp_privkey_int;
typedef struct gnutls_openpgp_keyring_int
{
cdk_keydb_hd_t db;
cdk_stream_t db_stream;
} gnutls_openpgp_keyring_int;
typedef struct gnutls_openpgp_keyring_int * gnutls_openpgp_keyring_t;
/* gnutls_openpgp_cert_t should be defined in gnutls.h */
/* initializes the memory for gnutls_openpgp_crt_t struct */
int gnutls_openpgp_crt_init(gnutls_openpgp_crt_t * key);
/* frees all memory */
void gnutls_openpgp_crt_deinit(gnutls_openpgp_crt_t key);
int gnutls_openpgp_crt_import(gnutls_openpgp_crt_t key,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format);
int gnutls_openpgp_crt_export(gnutls_openpgp_crt_t key,
gnutls_openpgp_crt_fmt_t format,
void *output_data,
size_t * output_data_size);
/* The key_usage flags are defined in gnutls.h. They are
* the GNUTLS_KEY_* definitions.
*/
int gnutls_openpgp_crt_get_key_usage(gnutls_openpgp_crt_t cert,
unsigned int *key_usage);
int gnutls_openpgp_crt_get_fingerprint(gnutls_openpgp_crt_t key,
void *fpr,
size_t * fprlen);
int gnutls_openpgp_crt_get_name(gnutls_openpgp_crt_t key,
int idx,
char *buf,
size_t * sizeof_buf);
gnutls_pk_algorithm_t
gnutls_openpgp_crt_get_pk_algorithm(gnutls_openpgp_crt_t key,
unsigned int *bits);
int gnutls_openpgp_crt_get_version(gnutls_openpgp_crt_t key);
time_t gnutls_openpgp_crt_get_creation_time(gnutls_openpgp_crt_t key);
time_t gnutls_openpgp_crt_get_expiration_time(gnutls_openpgp_crt_t key);
int gnutls_openpgp_crt_get_id(gnutls_openpgp_crt_t key,
unsigned char keyid[8]);
int gnutls_openpgp_crt_check_hostname(gnutls_openpgp_crt_t key,
const char *hostname);
/* privkey stuff. */
int gnutls_openpgp_privkey_init(gnutls_openpgp_privkey_t * key);
void gnutls_openpgp_privkey_deinit(gnutls_openpgp_privkey_t key);
gnutls_pk_algorithm_t
gnutls_openpgp_privkey_get_pk_algorithm(gnutls_openpgp_privkey_t key,
unsigned int *bits);
int gnutls_openpgp_privkey_import(gnutls_openpgp_privkey_t key,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format,
const char *pass,
unsigned int flags);
int gnutls_openpgp_privkey_sign_hash(gnutls_openpgp_privkey_t key,
const gnutls_datum_t * hash,
gnutls_datum_t * signature);
/* Keyring stuff. */
int gnutls_openpgp_keyring_init(gnutls_openpgp_keyring_t * keyring);
void gnutls_openpgp_keyring_deinit(gnutls_openpgp_keyring_t keyring);
int gnutls_openpgp_keyring_import(gnutls_openpgp_keyring_t keyring,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format);
int gnutls_openpgp_keyring_check_id(gnutls_openpgp_keyring_t ring,
const unsigned char keyid[8],
unsigned int flags);
int gnutls_openpgp_crt_verify_ring(gnutls_openpgp_crt_t key,
gnutls_openpgp_keyring_t keyring,
unsigned int flags,
unsigned int *verify
/* the output of the verification */);
int gnutls_openpgp_crt_verify_self(gnutls_openpgp_crt_t key,
unsigned int flags,
unsigned int *verify);
/* certificate authentication stuff.
*/
int gnutls_certificate_set_openpgp_key(mhd_gtls_cert_credentials_t
res,
gnutls_openpgp_crt_t key,
gnutls_openpgp_privkey_t pkey);
#ifdef __cplusplus
}
#endif
int _gnutls_map_cdk_rc(int rc);
int gnutls_openpgp_crt_get_name(gnutls_openpgp_crt_t key,
int idx,
char *buf,
size_t * sizeof_buf);
int gnutls_openpgp_crt_get_fingerprint(gnutls_openpgp_crt_t key,
void *fpr,
size_t * fprlen);
gnutls_pk_algorithm_t
gnutls_openpgp_crt_get_pk_algorithm(gnutls_openpgp_crt_t key,
unsigned int *bits);
int gnutls_openpgp_crt_get_version(gnutls_openpgp_crt_t key);
time_t gnutls_openpgp_crt_get_creation_time(gnutls_openpgp_crt_t key);
time_t gnutls_openpgp_crt_get_expiration_time(gnutls_openpgp_crt_t key);
int gnutls_openpgp_crt_get_id(gnutls_openpgp_crt_t key,
unsigned char keyid[8]);
int gnutls_openpgp_crt_init(gnutls_openpgp_crt_t * key);
void gnutls_openpgp_crt_deinit(gnutls_openpgp_crt_t key);
int gnutls_openpgp_crt_import(gnutls_openpgp_crt_t key,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format);
int gnutls_openpgp_crt_export(gnutls_openpgp_crt_t key,
gnutls_openpgp_crt_fmt_t format,
void *output_data,
size_t * output_data_size);
void gnutls_openpgp_keyring_deinit(gnutls_openpgp_keyring_t keyring);
int gnutls_openpgp_keyring_init(gnutls_openpgp_keyring_t * keyring);
int gnutls_openpgp_keyring_import(gnutls_openpgp_keyring_t keyring,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format);
int gnutls_openpgp_keyring_check_id(gnutls_openpgp_keyring_t ring,
const unsigned char keyid[8],
unsigned int flags);
int gnutls_openpgp_crt_verify_ring(gnutls_openpgp_crt_t key,
gnutls_openpgp_keyring_t keyring,
unsigned int flags,
unsigned int *verify);
int gnutls_openpgp_crt_verify_self(gnutls_openpgp_crt_t key,
unsigned int flags,
unsigned int *verify);
int _gnutls_openpgp_crt_to_gcert(gnutls_cert * gcert,
gnutls_openpgp_crt_t cert);
int _gnutls_openpgp_privkey_to_gkey(gnutls_privkey * dest,
gnutls_openpgp_privkey_t src);
void gnutls_openpgp_privkey_deinit(gnutls_openpgp_privkey_t key);
#endif /* ENABLE_OPENPGP */
#endif /* OPENPGP_H */
-543
View File
@@ -1,543 +0,0 @@
/*
* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation
*
* Author: Timo Schulz, Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Functions on OpenPGP key parsing
*/
#include <gnutls_int.h>
#include <gnutls_datum.h>
#include <gnutls_global.h>
#include <gnutls_errors.h>
#include "openpgp.h"
/* x509 */
#include <rfc2818.h>
/**
* gnutls_openpgp_crt_init - This function initializes a gnutls_openpgp_crt_t structure
* @key: The structure to be initialized
*
* This function will initialize an OpenPGP key structure.
*
* Returns 0 on success.
*
**/
int
gnutls_openpgp_crt_init (gnutls_openpgp_crt_t * key)
{
*key = gnutls_calloc (1, sizeof (gnutls_openpgp_crt_int));
if (*key)
return 0; /* success */
return GNUTLS_E_MEMORY_ERROR;
}
/**
* gnutls_openpgp_crt_deinit - This function deinitializes memory used by a gnutls_openpgp_crt_t structure
* @key: The structure to be initialized
*
* This function will deinitialize a key structure.
**/
void
gnutls_openpgp_crt_deinit (gnutls_openpgp_crt_t key)
{
if (!key)
return;
if (key->knode)
{
cdk_kbnode_release (key->knode);
key->knode = NULL;
}
gnutls_free (key);
}
/**
* gnutls_openpgp_crt_import - This function will import a RAW or BASE64 encoded key
* @key: The structure to store the parsed key.
* @data: The RAW or BASE64 encoded key.
* @format: One of gnutls_openpgp_crt_fmt_t elements.
*
* This function will convert the given RAW or Base64 encoded key
* to the native gnutls_openpgp_crt_t format. The output will be stored in 'key'.
*
* Returns 0 on success.
**/
int
gnutls_openpgp_crt_import (gnutls_openpgp_crt_t key,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format)
{
cdk_stream_t inp;
int rc;
if (format == GNUTLS_OPENPGP_FMT_RAW)
rc = cdk_kbnode_read_from_mem (&key->knode, data->data, data->size);
else
{
rc = cdk_stream_tmp_from_mem (data->data, data->size, &inp);
if (rc)
{
rc = _gnutls_map_cdk_rc (rc);
gnutls_assert ();
return rc;
}
if (cdk_armor_filter_use (inp))
rc = cdk_stream_set_armor_flag (inp, 0);
if (!rc)
rc = cdk_keydb_get_keyblock (inp, &key->knode);
cdk_stream_close (inp);
if (rc)
{
rc = _gnutls_map_cdk_rc (rc);
gnutls_assert ();
return rc;
}
}
return 0;
}
/**
* gnutls_openpgp_crt_export - This function will export a RAW or BASE64 encoded key
* @key: Holds the key.
* @format: One of gnutls_openpgp_crt_fmt_t elements.
* @output_data: will contain the key base64 encoded or raw
* @output_data_size: holds the size of output_data (and will be replaced by the actual size of parameters)
*
* This function will convert the given key to RAW or Base64 format.
* If the buffer provided is not long enough to hold the output, then
* GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
*
* Returns 0 on success.
*
**/
int
gnutls_openpgp_crt_export (gnutls_openpgp_crt_t key,
gnutls_openpgp_crt_fmt_t format,
void *output_data, size_t * output_data_size)
{
size_t input_data_size = *output_data_size;
size_t calc_size;
int rc;
rc = cdk_kbnode_write_to_mem (key->knode, output_data, output_data_size);
if (rc)
{
rc = _gnutls_map_cdk_rc (rc);
gnutls_assert ();
return rc;
}
/* FIXME: The first call of this function is with output_data == NULL
to figure out the size and the caller expects this error here. */
if (!output_data)
return GNUTLS_E_SHORT_MEMORY_BUFFER;
if (format == GNUTLS_OPENPGP_FMT_BASE64)
{
unsigned char *in = cdk_calloc (1, *output_data_size);
memcpy (in, output_data, *output_data_size);
/* Calculate the size of the encoded data and check if the provided
buffer is large enough. */
rc = cdk_armor_encode_buffer (in, input_data_size,
NULL, 0, &calc_size, CDK_ARMOR_PUBKEY);
if (rc || calc_size > input_data_size)
{
cdk_free (in);
*output_data_size = calc_size;
rc = _gnutls_map_cdk_rc (CDK_Too_Short);
gnutls_assert ();
return rc;
}
rc = cdk_armor_encode_buffer (in, input_data_size, output_data,
input_data_size, &calc_size,
CDK_ARMOR_PUBKEY);
cdk_free (in);
*output_data_size = calc_size;
}
return 0;
}
/**
* gnutls_openpgp_crt_get_fingerprint - Gets the fingerprint
* @key: the raw data that contains the OpenPGP public key.
* @fpr: the buffer to save the fingerprint, must hold at least 20 bytes.
* @fprlen: the integer to save the length of the fingerprint.
*
* Returns the fingerprint of the OpenPGP key. Depends on the algorithm,
* the fingerprint can be 16 or 20 bytes.
**/
int
gnutls_openpgp_crt_get_fingerprint (gnutls_openpgp_crt_t key,
void *fpr, size_t * fprlen)
{
cdk_packet_t pkt;
cdk_pkt_pubkey_t pk = NULL;
if (!fpr || !fprlen)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
*fprlen = 0;
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (!pkt)
return GNUTLS_E_OPENPGP_GETKEY_FAILED;
pk = pkt->pkt.public_key;
*fprlen = 20;
/* FIXME: Check if the draft allows old PGP keys. */
if (is_RSA (pk->pubkey_algo) && pk->version < 4)
*fprlen = 16;
cdk_pk_get_fingerprint (pk, fpr);
return 0;
}
int
_gnutls_openpgp_count_key_names (gnutls_openpgp_crt_t key)
{
cdk_kbnode_t p, ctx;
cdk_packet_t pkt;
int nuids;
if (key == NULL)
{
gnutls_assert ();
return 0;
}
ctx = NULL;
nuids = 0;
while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
{
pkt = cdk_kbnode_get_packet (p);
if (pkt->pkttype == CDK_PKT_USER_ID)
nuids++;
}
return nuids;
}
/**
* gnutls_openpgp_crt_get_name - Extracts the userID
* @key: the structure that contains the OpenPGP public key.
* @idx: the index of the ID to extract
* @buf: a pointer to a structure to hold the name
* @sizeof_buf: holds the maximum size of @buf, on return hold the
* actual/required size of @buf.
*
* Extracts the userID from the parsed OpenPGP key.
*
* Returns 0 on success, and GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
* if the index of the ID does not exist.
*
**/
int
gnutls_openpgp_crt_get_name (gnutls_openpgp_crt_t key,
int idx, char *buf, size_t * sizeof_buf)
{
cdk_kbnode_t ctx = NULL, p;
cdk_packet_t pkt = NULL;
cdk_pkt_userid_t uid = NULL;
int pos = 0;
if (!key || !buf)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (idx < 0 || idx > _gnutls_openpgp_count_key_names (key))
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
if (!idx)
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_USER_ID);
else
{
pos = 0;
while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
{
pkt = cdk_kbnode_get_packet (p);
if (pkt->pkttype == CDK_PKT_USER_ID && ++pos == idx)
break;
}
}
if (!pkt)
{
gnutls_assert ();
return GNUTLS_E_INTERNAL_ERROR;
}
uid = pkt->pkt.user_id;
if (uid->len >= *sizeof_buf)
{
gnutls_assert ();
*sizeof_buf = uid->len + 1;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
memcpy (buf, uid->name, uid->len);
buf[uid->len] = '\0'; /* make sure it's a string */
*sizeof_buf = uid->len + 1;
if (uid->is_revoked)
return GNUTLS_E_OPENPGP_UID_REVOKED;
return 0;
}
/**
* gnutls_openpgp_crt_get_pk_algorithm - This function returns the key's PublicKey algorithm
* @key: is an OpenPGP key
* @bits: if bits is non null it will hold the size of the parameters' in bits
*
* This function will return the public key algorithm of an OpenPGP
* certificate.
*
* If bits is non null, it should have enough size to hold the parameters
* size in bits. For RSA the bits returned is the modulus.
* For DSA the bits returned are of the public exponent.
*
* Returns a member of the GNUTLS_PKAlgorithm enumeration on success,
* or a negative value on error.
*
**/
gnutls_pk_algorithm_t
gnutls_openpgp_crt_get_pk_algorithm (gnutls_openpgp_crt_t key,
unsigned int *bits)
{
cdk_packet_t pkt;
int algo;
if (!key)
return MHD_GNUTLS_PK_UNKNOWN;
algo = 0;
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (pkt && pkt->pkttype == CDK_PKT_PUBLIC_KEY)
{
if (bits)
*bits = cdk_pk_get_nbits (pkt->pkt.public_key);
algo = pkt->pkt.public_key->pubkey_algo;
if (is_RSA (algo))
algo = MHD_GNUTLS_PK_RSA;
else
algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
return algo;
}
/**
* gnutls_openpgp_crt_get_version - Extracts the version of the key.
* @key: the structure that contains the OpenPGP public key.
*
* Extract the version of the OpenPGP key.
**/
int
gnutls_openpgp_crt_get_version (gnutls_openpgp_crt_t key)
{
cdk_packet_t pkt;
int version;
if (!key)
return -1;
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (pkt)
version = pkt->pkt.public_key->version;
else
version = 0;
return version;
}
/**
* gnutls_openpgp_crt_get_creation_time - Extract the timestamp
* @key: the structure that contains the OpenPGP public key.
*
* Returns the timestamp when the OpenPGP key was created.
**/
time_t
gnutls_openpgp_crt_get_creation_time (gnutls_openpgp_crt_t key)
{
cdk_packet_t pkt;
time_t timestamp;
if (!key)
return (time_t) - 1;
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (pkt)
timestamp = pkt->pkt.public_key->timestamp;
else
timestamp = 0;
return timestamp;
}
/**
* gnutls_openpgp_crt_get_expiration_time - Extract the expire date
* @key: the structure that contains the OpenPGP public key.
*
* Returns the time when the OpenPGP key expires. A value of '0' means
* that the key doesn't expire at all.
**/
time_t
gnutls_openpgp_crt_get_expiration_time (gnutls_openpgp_crt_t key)
{
cdk_packet_t pkt;
time_t expiredate;
if (!key)
return (time_t) - 1;
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (pkt)
expiredate = pkt->pkt.public_key->expiredate;
else
expiredate = 0;
return expiredate;
}
/**
* gnutls_openpgp_crt_get_id - Gets the keyID
* @key: the structure that contains the OpenPGP public key.
* @keyid: the buffer to save the keyid.
*
* Returns the 64-bit keyID of the OpenPGP key.
**/
int
gnutls_openpgp_crt_get_id (gnutls_openpgp_crt_t key, unsigned char keyid[8])
{
cdk_packet_t pkt;
uint32_t kid[2];
if (!key || !keyid)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (!pkt)
return GNUTLS_E_OPENPGP_GETKEY_FAILED;
cdk_pk_get_keyid (pkt->pkt.public_key, kid);
keyid[0] = kid[0] >> 24;
keyid[1] = kid[0] >> 16;
keyid[2] = kid[0] >> 8;
keyid[3] = kid[0];
keyid[4] = kid[1] >> 24;
keyid[5] = kid[1] >> 16;
keyid[6] = kid[1] >> 8;
keyid[7] = kid[1];
return 0;
}
/**
* gnutls_openpgp_crt_check_hostname - This function compares the given hostname with the hostname in the key
* @key: should contain an gnutls_openpgp_crt_t structure
* @hostname: A null terminated string that contains a DNS name
*
* This function will check if the given key's owner matches
* the given hostname. This is a basic implementation of the matching
* described in RFC2818 (HTTPS), which takes into account wildcards.
*
* Returns non zero on success, and zero on failure.
*
**/
int
gnutls_openpgp_crt_check_hostname (gnutls_openpgp_crt_t key,
const char *hostname)
{
char dnsname[MAX_CN];
size_t dnsnamesize;
int ret;
int i;
/* Check through all included names. */
for (i = 0; !(ret < 0); i++)
{
dnsnamesize = sizeof (dnsname);
ret = gnutls_openpgp_crt_get_name (key, i, dnsname, &dnsnamesize);
/* FIXME: ret is not used */
if (_gnutls_hostname_compare (dnsname, hostname))
return 1;
}
/* not found a matching name */
return 0;
}
/**
* gnutls_openpgp_crt_get_key_usage - This function returns the key's usage
* @key: should contain a gnutls_openpgp_crt_t structure
* @key_usage: where the key usage bits will be stored
*
* This function will return certificate's key usage, by checking the
* key algorithm. The key usage value will ORed values of the:
* GNUTLS_KEY_DIGITAL_SIGNATURE, GNUTLS_KEY_KEY_ENCIPHERMENT.
*
* A negative value may be returned in case of parsing error.
*
*/
int
gnutls_openpgp_crt_get_key_usage (gnutls_openpgp_crt_t key,
unsigned int *key_usage)
{
cdk_packet_t pkt;
int algo = 0;
if (!key)
return GNUTLS_E_INVALID_REQUEST;
*key_usage = 0;
pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
if (pkt && pkt->pkttype == CDK_PKT_PUBLIC_KEY)
{
algo = pkt->pkt.public_key->pubkey_algo;
/* FIXME: We need to take a look at the key flags because
RSA-E and RSA-S are obsolete. Only RSA is used
and the flags are used to set the capabilities. */
if (is_DSA (algo) || algo == GCRY_PK_RSA_S)
*key_usage |= KEY_DIGITAL_SIGNATURE;
else if (algo == GCRY_PK_RSA_E)
*key_usage |= KEY_KEY_ENCIPHERMENT;
else if (algo == GCRY_PK_RSA)
*key_usage |= KEY_DIGITAL_SIGNATURE | KEY_KEY_ENCIPHERMENT;
}
return 0;
}
-134
View File
@@ -1,134 +0,0 @@
/*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Functions on OpenPGP privkey parsing
*/
#include <gnutls_int.h>
#include <gnutls_datum.h>
#include <gnutls_global.h>
#include <gnutls_errors.h>
#include "openpgp.h"
#include <gnutls_openpgp.h>
#include <gnutls_cert.h>
/* x509 */
#include <rfc2818.h>
/**
* gnutls_openpgp_privkey_init - This function initializes a gnutls_openpgp_privkey_t structure
* @key: The structure to be initialized
*
* This function will initialize an OpenPGP key structure.
*
* Returns 0 on success.
*
**/
int
gnutls_openpgp_privkey_init (gnutls_openpgp_privkey_t * key)
{
*key = gnutls_calloc (1, sizeof (gnutls_openpgp_privkey_int));
if (*key)
return 0; /* success */
return GNUTLS_E_MEMORY_ERROR;
}
/**
* gnutls_openpgp_privkey_deinit - This function deinitializes memory used by a gnutls_openpgp_privkey_t structure
* @key: The structure to be initialized
*
* This function will deinitialize a key structure.
*
**/
void
gnutls_openpgp_privkey_deinit (gnutls_openpgp_privkey_t key)
{
if (!key)
return;
mhd_gtls_gkey_deinit (&key->pkey);
gnutls_free (key);
}
/**
* gnutls_openpgp_privkey_import - This function will import a RAW or BASE64 encoded key
* @key: The structure to store the parsed key.
* @data: The RAW or BASE64 encoded key.
* @format: One of gnutls_openpgp_crt_fmt_t elements.
* @pass: Unused for now
* @flags: should be zero
*
* This function will convert the given RAW or Base64 encoded key
* to the native gnutls_openpgp_privkey_t format. The output will be stored in 'key'.
*
* Returns 0 on success.
*
**/
int
gnutls_openpgp_privkey_import (gnutls_openpgp_privkey_t key,
const gnutls_datum_t * data,
gnutls_openpgp_crt_fmt_t format,
const char *pass, unsigned int flags)
{
int rc;
rc = _gnutls_openpgp_raw_privkey_to_gkey (&key->pkey, data, format);
if (rc)
{
gnutls_assert ();
return rc;
}
return 0;
}
/**
* gnutls_openpgp_privkey_get_pk_algorithm - This function returns the key's PublicKey algorithm
* @key: is an OpenPGP key
* @bits: if bits is non null it will hold the size of the parameters' in bits
*
* This function will return the public key algorithm of an OpenPGP
* certificate.
*
* If bits is non null, it should have enough size to hold the parameters
* size in bits. For RSA the bits returned is the modulus.
* For DSA the bits returned are of the public exponent.
*
* Returns a member of the GNUTLS_PKAlgorithm enumeration on success,
* or a negative value on error.
*
**/
gnutls_pk_algorithm_t
gnutls_openpgp_privkey_get_pk_algorithm (gnutls_openpgp_privkey_t key,
unsigned int *bits)
{
int pk = key->pkey.pk_algorithm;
if (bits)
{
*bits = 0;
if (pk == MHD_GNUTLS_PK_RSA)
*bits = _gnutls_mpi_get_nbits (key->pkey.params[0]);
}
return pk;
}
-144
View File
@@ -1,144 +0,0 @@
/*
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation
*
* Author: Timo Schulz, Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS-EXTRA.
*
* GNUTLS-EXTRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNUTLS-EXTRA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Functions on OpenPGP key parsing
*/
#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <gnutls_openpgp.h>
#include <gnutls_num.h>
#include "openpgp.h"
/* x509 */
#include <verify.h> /* lib/x509/verify.h */
/**
* gnutls_openpgp_crt_verify_ring - Verify all signatures in the key
* @key: the structure that holds the key.
* @keyring: holds the keyring to check against
* @flags: unused (should be 0)
* @verify: will hold the certificate verification output.
*
* Verify all signatures in the key, using the given set of keys (keyring).
*
* The key verification output will be put in @verify and will be
* one or more of the gnutls_certificate_status_t enumerated elements bitwise or'd.
*
* GNUTLS_CERT_INVALID: A signature on the key is invalid.
*
* GNUTLS_CERT_REVOKED: The key has been revoked.
*
* Note that this function does not verify using any "web of
* trust". You may use GnuPG for that purpose, or any other external
* PGP application.
*
* Returns 0 on success.
**/
int
gnutls_openpgp_crt_verify_ring (gnutls_openpgp_crt_t key,
gnutls_openpgp_keyring_t keyring,
unsigned int flags, unsigned int *verify)
{
opaque id[8];
cdk_error_t rc;
int status;
if (!key || !keyring)
{
gnutls_assert ();
return GNUTLS_E_NO_CERTIFICATE_FOUND;
}
*verify = 0;
rc = cdk_pk_check_sigs (key->knode, keyring->db, &status);
if (rc == CDK_Error_No_Key)
{
rc = GNUTLS_E_NO_CERTIFICATE_FOUND;
gnutls_assert ();
return rc;
}
else if (rc != CDK_Success)
{
_gnutls_x509_log ("cdk_pk_check_sigs: error %d\n", rc);
rc = _gnutls_map_cdk_rc (rc);
gnutls_assert ();
return rc;
}
_gnutls_x509_log ("status: %x\n", status);
if (status & CDK_KEY_INVALID)
*verify |= GNUTLS_CERT_INVALID;
if (status & CDK_KEY_REVOKED)
*verify |= GNUTLS_CERT_REVOKED;
if (status & CDK_KEY_NOSIGNER)
*verify |= GNUTLS_CERT_SIGNER_NOT_FOUND;
/* Check if the key is included in the ring. */
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
{
rc = gnutls_openpgp_crt_get_id (key, id);
if (rc < 0)
{
gnutls_assert ();
return rc;
}
rc = gnutls_openpgp_keyring_check_id (keyring, id, 0);
/* If it exists in the keyring don't treat it as unknown. */
if (rc == 0 && *verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
*verify ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
}
return 0;
}
/**
* gnutls_openpgp_crt_verify_self - Verify the self signature on the key
* @key: the structure that holds the key.
* @flags: unused (should be 0)
* @verify: will hold the key verification output.
*
* Verifies the self signature in the key.
* The key verification output will be put in @verify and will be
* one or more of the gnutls_certificate_status_t enumerated elements bitwise or'd.
*
* GNUTLS_CERT_INVALID: The self signature on the key is invalid.
*
* Returns 0 on success.
**/
int
gnutls_openpgp_crt_verify_self (gnutls_openpgp_crt_t key,
unsigned int flags, unsigned int *verify)
{
int status;
cdk_error_t rc;
rc = cdk_pk_check_self_sig (key->knode, &status);
if (rc || status != CDK_KEY_VALID)
*verify |= GNUTLS_CERT_INVALID;
else
*verify = 0;
return 0;
}