summaryrefslogtreecommitdiff
path: root/libextra
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-10-03 09:00:03 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-10-03 09:00:03 +0000
commit91a1dc4084213200c2618dde1225746f2c8619a5 (patch)
tree77e2b8493490479b8b49b9c2dfb7f136bafa704c /libextra
parentf8619134f13cc2f0aca9f4e7eecc9871a8b4fab2 (diff)
downloadgnutls-91a1dc4084213200c2618dde1225746f2c8619a5.tar.gz
started some rewrite of the openpgp stuff.
Diffstat (limited to 'libextra')
-rw-r--r--libextra/Makefile.am8
-rw-r--r--libextra/gnutls_openpgp.c32
-rw-r--r--libextra/openpgp/Makefile.am17
-rw-r--r--libextra/openpgp/gnutls_openpgp.c2107
-rw-r--r--libextra/openpgp/openpgp.c414
-rw-r--r--libextra/openpgp/openpgp.h16
6 files changed, 2576 insertions, 18 deletions
diff --git a/libextra/Makefile.am b/libextra/Makefile.am
index 6eb9dd662e..50f132acf8 100644
--- a/libextra/Makefile.am
+++ b/libextra/Makefile.am
@@ -1,5 +1,7 @@
INCLUDES = -I../lib -I../includes -I../lib/minitasn1/
bin_SCRIPTS = libgnutls-extra-config
+DIST_SUBDIRS = openpgp
+SUBDIRS = openpgp
m4datadir = $(datadir)/aclocal
m4data_DATA = libgnutls-extra.m4
@@ -11,7 +13,7 @@ else
endif
EXTRA_DIST = ext_srp.h gnutls_srp.h libgnutls-extra.vers \
- auth_srp.h auth_srp_passwd.h gnutls_openpgp.h \
+ auth_srp.h auth_srp_passwd.h \
gnutls-extra-api.tex gnutls_extra.h libgnutls-extra-config.in \
libgnutls-extra.m4 lzoconf.h minilzo.h
@@ -20,7 +22,7 @@ lib_LTLIBRARIES = libgnutls-extra.la
COBJECTS_EXTRA = ext_srp.c \
gnutls_srp.c auth_srp.c auth_srp_passwd.c auth_srp_sb64.c \
- gnutls_openpgp.c gnutls_extra.c gnutls_openssl.c \
+ gnutls_extra.c gnutls_openssl.c \
auth_srp_rsa.c
libgnutls_extra_la_LDFLAGS = $(libgnutls_extra_version_script_cmd) \
@@ -31,6 +33,8 @@ libgnutls_extra_la_DEPENDENCIES = $(LZO_OBJECTS)
libgnutls_extra_la_SOURCES = $(COBJECTS_EXTRA)
+libgnutls_extra_la_LIBADD = openpgp/openpgp.lo openpgp/xml.lo openpgp/gnutls_openpgp.lo
+
EXTRA_libgnutls_extra_la_SOURCES = minilzo.c
gnutls-extra-api.tex: $(COBJECTS_EXTRA)
diff --git a/libextra/gnutls_openpgp.c b/libextra/gnutls_openpgp.c
index 8bf630477d..824fd99375 100644
--- a/libextra/gnutls_openpgp.c
+++ b/libextra/gnutls_openpgp.c
@@ -71,8 +71,8 @@ release_mpi_array( GNUTLS_MPI *arr, size_t n )
}
-static int
-map_cdk_rc( int rc )
+int
+_gnutls_map_cdk_rc( int rc )
{
switch( rc ) {
case CDK_Success: return 0;
@@ -431,7 +431,7 @@ _gnutls_openpgp_cert2gnutls_cert( gnutls_cert *cert, const gnutls_datum *raw )
memset( cert, 0, sizeof *cert );
rc = cdk_kbnode_read_from_mem( &knode, raw->data, raw->size );
- if( !(rc = map_cdk_rc( rc )) )
+ if( !(rc = _gnutls_map_cdk_rc( rc )) )
pkt = cdk_kbnode_find_packet( knode, CDK_PKT_PUBLIC_KEY );
if( !pkt )
rc = GNUTLS_E_INTERNAL_ERROR;
@@ -493,13 +493,13 @@ gnutls_openpgp_get_key( gnutls_datum *key, const gnutls_datum *keyring,
desc = pattern;
rc = cdk_keydb_search_new( &ks, by, desc );
if( rc ) {
- rc = map_cdk_rc( rc );
+ rc = _gnutls_map_cdk_rc( rc );
goto leave;
}
rc = cdk_keydb_search( hd, ks, &knode );
if( rc ) {
- rc = map_cdk_rc( rc );
+ rc = _gnutls_map_cdk_rc( rc );
goto leave;
}
@@ -541,7 +541,7 @@ gnutls_certificate_set_openpgp_key_mem( gnutls_certificate_credentials res,
}
rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
- if( (rc = map_cdk_rc( rc )) )
+ if( (rc = _gnutls_map_cdk_rc( rc )) )
goto leave;
/* fixme: too much duplicated code from (set_openpgp_key_file) */
@@ -643,7 +643,7 @@ gnutls_certificate_set_openpgp_key_file( gnutls_certificate_credentials res,
rc = cdk_stream_open( CERTFILE, &inp );
if( rc ) {
gnutls_assert();
- return map_cdk_rc( rc );
+ return _gnutls_map_cdk_rc( rc );
}
if( cdk_armor_filter_use( inp ) )
@@ -693,7 +693,7 @@ gnutls_certificate_set_openpgp_key_file( gnutls_certificate_credentials res,
cdk_kbnode_release( knode );
gnutls_assert();
- rc = map_cdk_rc( rc );
+ rc = _gnutls_map_cdk_rc( rc );
goto leave;
}
cdk_kbnode_release( knode );
@@ -701,7 +701,7 @@ gnutls_certificate_set_openpgp_key_file( gnutls_certificate_credentials res,
rc = cdk_stream_open( KEYFILE, &inp );
if( rc ) {
gnutls_assert();
- return map_cdk_rc( rc );
+ return _gnutls_map_cdk_rc( rc );
}
if( cdk_armor_filter_use( inp ) )
cdk_stream_set_armor_flag( inp, 0 );
@@ -784,7 +784,7 @@ gnutls_openpgp_extract_key_name( const gnutls_datum *cert,
memset( dn, 0, sizeof *dn );
rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
- if( (rc = map_cdk_rc( rc )) ) {
+ if( (rc = _gnutls_map_cdk_rc( rc )) ) {
gnutls_assert( );
return rc;
}
@@ -865,7 +865,7 @@ gnutls_openpgp_extract_key_name_string( const gnutls_datum *cert,
}
rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
- if( (rc = map_cdk_rc( rc )) ) {
+ if( (rc = _gnutls_map_cdk_rc( rc )) ) {
gnutls_assert( );
return rc;
}
@@ -1045,7 +1045,7 @@ _gnutls_openpgp_get_key_trust( const char *trustdb,
*r_trustval = 0;
rc = cdk_kbnode_read_from_mem( &knode, key->data, key->size );
- if( (rc = map_cdk_rc( rc )) )
+ if( (rc = _gnutls_map_cdk_rc( rc )) )
return rc;
pkt = cdk_kbnode_find_packet( knode, CDK_PKT_PUBLIC_KEY );
@@ -1057,7 +1057,7 @@ _gnutls_openpgp_get_key_trust( const char *trustdb,
rc = cdk_stream_open( trustdb, &inp );
if( rc ) {
- rc = map_cdk_rc( rc );
+ rc = _gnutls_map_cdk_rc( rc );
goto leave;
}
@@ -1161,7 +1161,7 @@ gnutls_openpgp_verify_key( const char *trustdb,
}
rc = cdk_kbnode_read_from_mem( &knode, cert_list->data, cert_list->size );
- if( (rc = map_cdk_rc( rc )) ) {
+ if( (rc = _gnutls_map_cdk_rc( rc )) ) {
goto leave;
return GNUTLS_CERT_INVALID | GNUTLS_CERT_NOT_TRUSTED;
}
@@ -1294,7 +1294,7 @@ gnutls_openpgp_add_keyring_file(gnutls_datum *keyring, const char *name)
rc = cdk_stream_open( name, &inp );
if( rc )
- return map_cdk_rc( rc );
+ return _gnutls_map_cdk_rc( rc );
enc = cdk_armor_filter_use( inp );
cdk_stream_close( inp );
@@ -1839,7 +1839,7 @@ gnutls_openpgp_key_to_xml( const gnutls_datum *cert,
}
rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
- if( (rc = map_cdk_rc( rc )) )
+ if( (rc = _gnutls_map_cdk_rc( rc )) )
return rc;
_gnutls_string_init( &string_xml_key, malloc, realloc, free );
diff --git a/libextra/openpgp/Makefile.am b/libextra/openpgp/Makefile.am
new file mode 100644
index 0000000000..b3ce014e5f
--- /dev/null
+++ b/libextra/openpgp/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = -I../ -I../../includes/
+EXTRA_DIST = openpgp.h
+
+noinst_LTLIBRARIES = libpgp.la
+
+COBJECTS = openpgp.c xml.c gnutls_openpgp.c
+
+libx509_la_SOURCES = $(COBJECTS)
+
+pgp-api.tex: $(COBJECTS)
+ @echo "" > pgp-api.tex
+ @for i in $(COBJECTS); \
+ do echo -n "Creating documentation for file $$i... " && ../../doc/scripts/gdoc -tex $$i >> pgp-api.tex \
+ && echo "ok"; \
+ done
+
+dist-hook: pgp-api.tex
diff --git a/libextra/openpgp/gnutls_openpgp.c b/libextra/openpgp/gnutls_openpgp.c
new file mode 100644
index 0000000000..824fd99375
--- /dev/null
+++ b/libextra/openpgp/gnutls_openpgp.c
@@ -0,0 +1,2107 @@
+/*
+ * Copyright (C) 2002 Timo Schulz <twoaday@freakmail.de>
+ *
+ * This file is part of GNUTLS.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#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 "auth_cert.h"
+#include "gnutls_openpgp.h"
+
+#ifdef HAVE_LIBOPENCDK
+#include <gnutls/compat8.h>
+#include <gnutls_str.h>
+#include <stdio.h>
+#include <gcrypt.h>
+#include <opencdk.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <assert.h>
+
+#define OPENPGP_NAME_SIZE 256
+
+#define datum_append(x, y, z) _gnutls_datum_append_m( x, y, z, gnutls_realloc )
+
+typedef struct {
+ int type;
+ int armored;
+ size_t size;
+ uint8 *data;
+} keybox_blob;
+
+typedef enum {
+ KBX_BLOB_FILE = 0x00,
+ KBX_BLOB_DATA = 0x01
+} keyring_blob_types;
+
+
+static void
+release_mpi_array( GNUTLS_MPI *arr, size_t n )
+{
+ GNUTLS_MPI x;
+
+ while( arr && n-- ) {
+ x = *arr;
+ _gnutls_mpi_release( &x );
+ *arr = NULL; arr++;
+ }
+}
+
+
+int
+_gnutls_map_cdk_rc( int rc )
+{
+ switch( rc ) {
+ case CDK_Success: return 0;
+ 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_Wrong_Format: return GNUTLS_E_OPENPGP_TRUSTDB_VERSION_UNSUPPORTED;
+ 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;
+ }
+ return rc;
+}
+
+
+static unsigned long
+buftou32( const uint8 *buf )
+{
+ unsigned a;
+ a = buf[0] << 24;
+ a |= buf[1] << 16;
+ a |= buf[2] << 8;
+ a |= buf[3];
+ return a;
+}
+
+
+static int
+kbx_blob_new( keybox_blob **r_ctx )
+{
+ keybox_blob *c;
+
+ if( !r_ctx ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ c = cdk_calloc( 1, sizeof * c );
+ if( !c ) {
+ gnutls_assert( );
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ *r_ctx = c;
+
+ return 0;
+}
+
+
+static void
+kbx_blob_release( keybox_blob *ctx )
+{
+ if( ctx ) {
+ cdk_free( ctx->data );
+ cdk_free( ctx );
+ }
+}
+
+
+static CDK_KEYDB_HD
+kbx_to_keydb( keybox_blob *blob )
+{
+ CDK_KEYDB_HD hd;
+ int rc;
+
+ if( !blob ) {
+ gnutls_assert( );
+ return NULL;
+ }
+
+ switch( blob->type ) {
+ case KBX_BLOB_FILE:
+ rc = cdk_keydb_new( &hd, blob->armored? CDK_DBTYPE_ARMORED:
+ CDK_DBTYPE_KEYRING, blob->data, blob->size );
+ break;
+
+ case KBX_BLOB_DATA:
+ rc = cdk_keydb_new( &hd, CDK_DBTYPE_DATA, blob->data, blob->size );
+ break;
+
+ default:
+ rc = GNUTLS_E_INTERNAL_ERROR;
+ gnutls_assert( );
+ break;
+ }
+ if( rc )
+ hd = NULL;
+ return hd;
+}
+
+
+/* Extract a keybox blob from the given position. */
+static keybox_blob*
+kbx_read_blob( const gnutls_datum* keyring, size_t pos )
+{
+ keybox_blob *blob = NULL;
+ int rc;
+
+ if( !keyring || !keyring->data || pos > keyring->size ) {
+ gnutls_assert( );
+ return NULL;
+ }
+
+ rc = kbx_blob_new( &blob );
+ if( rc )
+ return NULL;
+
+ blob->type = keyring->data[pos];
+ if( blob->type != KBX_BLOB_FILE && blob->type != KBX_BLOB_DATA ) {
+ kbx_blob_release( blob );
+ return NULL;
+ }
+ blob->armored = keyring->data[pos + 1];
+ blob->size = buftou32( keyring->data + pos + 2 );
+ if( !blob->size ) {
+ kbx_blob_release( blob );
+ return NULL;
+ }
+ blob->data = cdk_calloc( 1, blob->size + 1 );
+ if( !blob->data )
+ return NULL;
+ memcpy( blob->data, keyring->data + (pos + 6), blob->size );
+ blob->data[blob->size] = '\0';
+
+ return blob;
+}
+
+
+/* Creates a keyring blob from raw data
+ *
+ * Format:
+ * 1 octet type
+ * 1 octet armored
+ * 4 octet size of blob
+ * n octets data
+ */
+static uint8*
+kbx_data_to_keyring( int type, int enc, const char *data,
+ size_t size, size_t *r_size )
+{
+ uint8 *p = NULL;
+
+ if( !data )
+ return NULL;
+
+ p = gnutls_malloc( 1+4+size );
+ if( !p )
+ return NULL;
+ p[0] = type; /* type: {keyring,name} */
+ p[1] = enc; /* encoded: {plain, armored} */
+ p[2] = size >> 24;
+ p[3] = size >> 16;
+ p[4] = size >> 8;
+ p[5] = size ;
+ memcpy( p + 6, data, size );
+ if( r_size )
+ *r_size = 6 + size;
+ return p;
+}
+
+
+CDK_PACKET*
+search_packet( const gnutls_datum *buf, int pkttype )
+{
+ static CDK_KBNODE knode = NULL;
+ CDK_PACKET *pkt;
+
+ if( !buf && !pkttype ) {
+ cdk_kbnode_release( knode );
+ knode = NULL;
+ return NULL;
+ }
+ if( cdk_kbnode_read_from_mem( &knode, buf->data, buf->size ) )
+ return NULL;
+ pkt = cdk_kbnode_find_packet( knode, pkttype );
+
+ return pkt;
+}
+
+
+static int
+stream_to_datum( CDK_STREAM inp, gnutls_datum *raw )
+{
+ uint8 buf[4096];
+ int rc = 0, nread, nbytes = 0;
+
+ if( !buf || !raw ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ cdk_stream_seek( inp, 0 );
+ while( !cdk_stream_eof( inp ) ) {
+ nread = cdk_stream_read( inp, buf, sizeof buf-1 );
+ if( nread == EOF )
+ break;
+ datum_append( raw, buf, nread );
+ nbytes += nread;
+ }
+ cdk_stream_seek( inp, 0 );
+ if( !nbytes )
+ rc = GNUTLS_E_INTERNAL_ERROR;
+
+ return rc;
+}
+
+
+static int
+openpgp_pk_to_gnutls_cert( gnutls_cert *cert, cdkPKT_public_key *pk )
+{
+ uint8 buf[512];
+ size_t nbytes = 0;
+ int algo, i;
+ int rc = 0;
+
+ if( !cert || !pk ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* GnuTLS OpenPGP doesn't support ELG keys */
+ if( is_ELG(pk->pubkey_algo) )
+ return GNUTLS_E_UNWANTED_ALGORITHM;
+
+ algo = is_DSA( pk->pubkey_algo )? GNUTLS_PK_DSA : GNUTLS_PK_RSA;
+ cert->subject_pk_algorithm = algo;
+ cert->version = pk->version;
+ cert->cert_type = GNUTLS_CRT_OPENPGP;
+
+ if( is_DSA(pk->pubkey_algo) || pk->pubkey_algo == GCRY_PK_RSA_S )
+ cert->keyUsage = KEY_DIGITAL_SIGNATURE;
+ else if( pk->pubkey_algo == GCRY_PK_RSA_E )
+ cert->keyUsage = KEY_ENCIPHER_ONLY;
+ else if( pk->pubkey_algo == GCRY_PK_RSA )
+ cert->keyUsage = KEY_DIGITAL_SIGNATURE
+ | KEY_ENCIPHER_ONLY;
+
+ cert->params_size = cdk_pk_get_npkey( pk->pubkey_algo );
+ for( i = 0; i < cert->params_size; i++ ) {
+ nbytes = sizeof buf-1;
+ cdk_pk_get_mpi( pk, i, buf, &nbytes, NULL );
+ rc = _gnutls_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_key2gnutls_key - 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.
+ *
+ * The RFC2440 (OpenPGP Message Format) data is converted into the
+ * GnuTLS specific data which is need to perform secret key operations.
+ -*/
+int
+_gnutls_openpgp_key2gnutls_key( gnutls_privkey *pkey,
+ gnutls_datum *raw_key )
+{
+ CDK_KBNODE snode;
+ CDK_PACKET *pkt;
+ CDK_STREAM out;
+ cdkPKT_secret_key *sk = NULL;
+ int pke_algo, i, j;
+ size_t nbytes = 0;
+ uint8 buf[512];
+ int rc = 0;
+
+ if( !pkey || raw_key->size <= 0 ) {
+ gnutls_assert( );
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ out = cdk_stream_tmp( );
+ if( !out )
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ cdk_stream_write( out, raw_key->data, raw_key->size );
+ cdk_stream_seek( out, 0 );
+
+ cdk_keydb_get_keyblock( out, &snode );
+ if( !snode ) {
+ 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 -1;
+ cdk_pk_get_mpi( sk->pk, i, buf, &nbytes, NULL );
+ rc = _gnutls_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-1;
+ cdk_sk_get_mpi( sk, j, buf, &nbytes, NULL );
+ rc = _gnutls_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_DSA(pke_algo) )
+ pkey->pk_algorithm = GNUTLS_PK_DSA;
+ else if( is_RSA(pke_algo) )
+ pkey->pk_algorithm = GNUTLS_PK_RSA;
+
+leave:
+ cdk_stream_close( out );
+ cdk_kbnode_release( snode );
+ return rc;
+}
+
+
+/*-
+ * _gnutls_openpgp_cert2gnutls_cert - 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_cert2gnutls_cert( gnutls_cert *cert, const gnutls_datum *raw )
+{
+ CDK_KBNODE knode = NULL;
+ CDK_PACKET *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 )
+ rc = GNUTLS_E_INTERNAL_ERROR;
+ 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_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 *key, const gnutls_datum *keyring,
+ key_attr_t by, opaque *pattern )
+{
+ keybox_blob *blob = NULL;
+ CDK_KEYDB_HD hd = NULL;
+ CDK_KBNODE knode = NULL;
+ CDK_DBSEARCH ks = 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 );
+ blob = kbx_read_blob( keyring, 0 );
+ if( !blob )
+ return GNUTLS_E_MEMORY_ERROR;
+ hd = kbx_to_keydb( blob );
+
+ 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_new( &ks, by, desc );
+ if( rc ) {
+ rc = _gnutls_map_cdk_rc( rc );
+ goto leave;
+ }
+
+ rc = cdk_keydb_search( hd, ks, &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;
+ }
+
+ len = 20000;
+ buf = cdk_calloc (1, len + 1);
+ rc = cdk_kbnode_write_to_mem( knode, buf, &len );
+ if( !rc )
+ datum_append( key, buf, len );
+ cdk_free( buf );
+
+leave:
+ cdk_free( hd );
+ cdk_kbnode_release( knode );
+ cdk_keydb_search_free( ks );
+ kbx_blob_release( blob );
+ return rc;
+}
+
+
+int
+gnutls_certificate_set_openpgp_key_mem( gnutls_certificate_credentials res,
+ gnutls_datum *cert,
+ gnutls_datum *key )
+{
+ gnutls_datum raw;
+ CDK_KBNODE knode = NULL, ctx = NULL, p;
+ CDK_PACKET *pkt;
+ int i = 0;
+ int rc = 0;
+
+ if ( !res || !key || !cert ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
+ if( (rc = _gnutls_map_cdk_rc( rc )) )
+ goto leave;
+
+ /* fixme: too much duplicated code from (set_openpgp_key_file) */
+ res->cert_list = gnutls_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 = gnutls_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;
+ }
+
+ i = 1;
+ while( (p = cdk_kbnode_walk( knode, &ctx, 0 )) ) {
+ pkt = cdk_kbnode_get_packet( p );
+ if( i > MAX_PUBLIC_PARAMS_SIZE )
+ break;
+ if( pkt->pkttype == CDK_PKT_PUBLIC_KEY ) {
+ int n = res->ncerts;
+ cdkPKT_public_key *pk = pkt->pkt.public_key;
+ res->cert_list_length[n] = 1;
+ if (_gnutls_set_datum( &res->cert_list[n][0].raw,
+ cert->data, cert->size ) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ openpgp_pk_to_gnutls_cert( &res->cert_list[n][0], pk );
+ i++;
+ }
+ }
+
+ res->ncerts++;
+ res->pkey = gnutls_realloc_fast(res->pkey,
+ (res->ncerts)*sizeof(gnutls_privkey));
+ if( !res->pkey ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ /* ncerts has been incremented before */
+ rc = _gnutls_set_datum( &raw, key->data, key->size );
+ if (rc < 0) {
+ gnutls_assert();
+ return rc;
+ }
+ rc = _gnutls_openpgp_key2gnutls_key( &res->pkey[res->ncerts-1], &raw );
+ _gnutls_free_datum(&raw);
+
+leave:
+ cdk_kbnode_release( knode );
+
+ return rc;
+}
+
+
+/**
+ * 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 structure.
+ * It doesn't matter whether the keys are armored or but, but the files
+ * should only contain one key which should not be encrypted.
+ **/
+int
+gnutls_certificate_set_openpgp_key_file( gnutls_certificate_credentials res,
+ char* CERTFILE,
+ char* KEYFILE )
+{
+ struct stat statbuf;
+ CDK_STREAM inp = NULL;
+ CDK_KBNODE knode = NULL, ctx = NULL, p;
+ CDK_PACKET *pkt = NULL;
+ gnutls_datum raw;
+ int i = 0, n;
+ int rc = 0;
+
+ 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;
+ }
+
+ rc = cdk_stream_open( CERTFILE, &inp );
+ if( rc ) {
+ gnutls_assert();
+ return _gnutls_map_cdk_rc( rc );
+ }
+
+ if( cdk_armor_filter_use( inp ) )
+ cdk_stream_set_armor_flag( inp, 0 );
+
+ n = (1 + res->ncerts) * sizeof (gnutls_cert*);
+ res->cert_list = gnutls_realloc_fast( res->cert_list, n );
+ if( !res->cert_list ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ n = (1 + res->ncerts) * sizeof (int);
+ res->cert_list_length = gnutls_realloc_fast( res->cert_list_length, n );
+ if( !res->cert_list_length ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ res->cert_list[res->ncerts] = gnutls_calloc( 1, sizeof(gnutls_cert) );
+ if( !res->cert_list[res->ncerts] ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ while( !rc ) {
+ i = 1;
+ rc = cdk_keydb_get_keyblock( inp, &knode );
+ while( knode && (p = cdk_kbnode_walk( knode, &ctx, 0 )) ) {
+ if( i > MAX_PUBLIC_PARAMS_SIZE )
+ break;
+ pkt = cdk_kbnode_get_packet( p );
+ if( pkt->pkttype == CDK_PKT_PUBLIC_KEY ) {
+ int n = res->ncerts;
+ cdkPKT_public_key *pk = pkt->pkt.public_key;
+ res->cert_list_length[n] = 1;
+ stream_to_datum( inp, &res->cert_list[n][0].raw );
+ openpgp_pk_to_gnutls_cert( &res->cert_list[n][0], pk );
+ i++;
+ }
+ }
+ }
+ if( rc == CDK_EOF && i > 1 )
+ rc = 0;
+ cdk_stream_close( inp );
+ if( rc ) {
+ cdk_kbnode_release( knode );
+
+ gnutls_assert();
+ rc = _gnutls_map_cdk_rc( rc );
+ goto leave;
+ }
+ cdk_kbnode_release( knode );
+
+ rc = cdk_stream_open( KEYFILE, &inp );
+ if( rc ) {
+ gnutls_assert();
+ return _gnutls_map_cdk_rc( rc );
+ }
+ if( cdk_armor_filter_use( inp ) )
+ cdk_stream_set_armor_flag( inp, 0 );
+
+ memset( &raw, 0, sizeof raw );
+ stream_to_datum( inp, &raw );
+ cdk_stream_close( inp );
+
+ n = (res->ncerts + 1) * sizeof (gnutls_privkey);
+ res->pkey = gnutls_realloc_fast( res->pkey, n );
+ if( !res->pkey ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ res->ncerts++;
+ /* ncerts has been incremented before */
+ rc = _gnutls_openpgp_key2gnutls_key( &res->pkey[res->ncerts-1], &raw );
+
+ leave:
+ return rc;
+}
+
+
+int
+gnutls_openpgp_count_key_names( const gnutls_datum *cert )
+{
+ CDK_KBNODE knode, p, ctx = NULL;
+ CDK_PACKET *pkt;
+ int nuids = 0;
+
+ if( cert == NULL ) {
+ gnutls_assert();
+ return 0;
+ }
+ if( cdk_kbnode_read_from_mem( &knode, cert->data, cert->size ) ) {
+ gnutls_assert();
+ return 0;
+ }
+ while( (p = cdk_kbnode_walk( knode, &ctx, 0 )) ) {
+ pkt = cdk_kbnode_get_packet( p );
+ if( pkt->pkttype == CDK_PKT_USER_ID )
+ nuids++;
+ }
+
+ return nuids;
+}
+
+
+/**
+ * gnutls_openpgp_extract_key_name - Extracts the userID
+ * @cert: the raw data that contains the OpenPGP public key.
+ * @idx: the index of the ID to extract
+ * @dn: the structure to store the userID specific data in.
+ *
+ * Extracts the userID from the raw OpenPGP key.
+ **/
+int
+gnutls_openpgp_extract_key_name( const gnutls_datum *cert,
+ int idx,
+ gnutls_openpgp_name *dn )
+{
+ CDK_KBNODE knode = NULL, ctx = NULL, p;
+ CDK_PACKET *pkt = NULL;
+ cdkPKT_user_id *uid = NULL;
+ char *email;
+ int pos = 0, pos1 = 0, pos2 = 0;
+ size_t size = 0;
+ int rc = 0;
+
+ if( !cert || !dn ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if( idx < 0 || idx > gnutls_openpgp_count_key_names( cert ) ) {
+ gnutls_assert( );
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ memset( dn, 0, sizeof *dn );
+ rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
+ if( (rc = _gnutls_map_cdk_rc( rc )) ) {
+ gnutls_assert( );
+ return rc;
+ }
+ if( !idx )
+ pkt = cdk_kbnode_find_packet( knode, CDK_PKT_USER_ID );
+ else {
+ pos = 0;
+ while( (p = cdk_kbnode_walk( knode, &ctx, 0 )) ) {
+ pkt = cdk_kbnode_get_packet( p );
+ if( pkt->pkttype == CDK_PKT_USER_ID && ++pos == idx )
+ break;
+ }
+ }
+
+ if( !pkt ) {
+ rc = GNUTLS_E_INTERNAL_ERROR;
+ goto leave;
+ }
+
+ uid = pkt->pkt.user_id;
+ size = uid->len < OPENPGP_NAME_SIZE? uid->len : OPENPGP_NAME_SIZE-1;
+ memcpy( dn->name, uid->name, size );
+ dn->name[size] = '\0'; /* make sure it's a string */
+
+ /* Extract the email address from the userID string and save
+ it to the email field. */
+ email = strchr( uid->name, '<' );
+ if( email )
+ pos1 = email-uid->name + 1;
+ email = strchr( uid->name, '>' );
+ if( email )
+ pos2 = email-uid->name + 1;
+ if( pos1 && pos2 ) {
+ pos2 -= pos1;
+ size = pos2 < OPENPGP_NAME_SIZE? pos2 : OPENPGP_NAME_SIZE-1;
+ memcpy( dn->email, uid->name+pos1, size );
+ dn->email[size-1] = '\0'; /* make sure it's a string */
+ }
+ if( uid->is_revoked ) {
+ rc = GNUTLS_E_OPENPGP_UID_REVOKED;
+ goto leave;
+ }
+
+leave:
+ cdk_kbnode_release( knode );
+ return rc;
+}
+
+/**
+ * gnutls_openpgp_extract_key_name_string - Extracts the userID
+ * @cert: the raw data that contains the OpenPGP public key.
+ * @idx: the index of the ID to extract
+ * @buf: a pointer to a structure to hold the peer's name
+ * @sizeof_buf: holds the size of 'buf'
+ *
+ * Extracts the userID from the raw OpenPGP key.
+ **/
+int
+gnutls_openpgp_extract_key_name_string( const gnutls_datum *cert,
+ int idx,
+ char *buf, unsigned int sizeof_buf)
+{
+ CDK_KBNODE knode = NULL, ctx = NULL, p;
+ CDK_PACKET *pkt = NULL;
+ cdkPKT_user_id *uid = NULL;
+ int pos = 0;
+ size_t size = 0;
+ int rc = 0;
+
+ if( !cert || !buf ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if( idx < 0 || idx > gnutls_openpgp_count_key_names( cert ) ) {
+ gnutls_assert( );
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
+ if( (rc = _gnutls_map_cdk_rc( rc )) ) {
+ gnutls_assert( );
+ return rc;
+ }
+ if( !idx )
+ pkt = cdk_kbnode_find_packet( knode, CDK_PKT_USER_ID );
+ else {
+ pos = 0;
+ while( (p = cdk_kbnode_walk( knode, &ctx, 0 )) ) {
+ pkt = cdk_kbnode_get_packet( p );
+ if( pkt->pkttype == CDK_PKT_USER_ID && ++pos == idx )
+ break;
+ }
+ }
+
+ if( !pkt ) {
+ rc = GNUTLS_E_INTERNAL_ERROR;
+ goto leave;
+ }
+
+ uid = pkt->pkt.user_id;
+
+ if (uid->len >= sizeof_buf) {
+ gnutls_assert();
+ rc = GNUTLS_E_SHORT_MEMORY_BUFFER;
+ goto leave;
+ }
+
+ size = uid->len < sizeof_buf? uid->len : sizeof_buf-1;
+ memcpy( buf, uid->name, size);
+
+ buf[size] = '\0'; /* make sure it's a string */
+
+ if( uid->is_revoked ) {
+ rc = GNUTLS_E_OPENPGP_UID_REVOKED;
+ goto leave;
+ }
+
+leave:
+ cdk_kbnode_release( knode );
+ return rc;
+}
+
+
+/**
+ * gnutls_openpgp_extract_key_pk_algorithm - This function returns the
+ * key's PublicKey algorithm
+ * @cert: 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.
+ *
+ **/
+int
+gnutls_openpgp_extract_key_pk_algorithm( const gnutls_datum *cert, int *r_bits)
+{
+ CDK_PACKET *pkt;
+ int algo = 0;
+
+ if( !cert )
+ return GNUTLS_E_INVALID_REQUEST;
+
+ pkt = search_packet( cert, CDK_PKT_PUBLIC_KEY );
+ if( pkt && pkt->pkttype == CDK_PKT_PUBLIC_KEY ) {
+ if( r_bits )
+ *r_bits = cdk_pk_get_nbits( pkt->pkt.public_key );
+ algo = pkt->pkt.public_key->pubkey_algo;
+ if( is_RSA( algo ) )
+ algo = GNUTLS_PK_RSA;
+ else if( is_DSA( algo ) )
+ algo = GNUTLS_PK_DSA;
+ else
+ algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+ }
+ search_packet( NULL, 0 );
+ return algo;
+}
+
+
+/**
+ * gnutls_openpgp_extract_key_version - Extracts the version of the key.
+ * @cert: the raw data that contains the OpenPGP public key.
+ *
+ * Extract the version of the OpenPGP key.
+ **/
+int
+gnutls_openpgp_extract_key_version( const gnutls_datum *cert )
+{
+ CDK_PACKET *pkt;
+ int version = 0;
+
+ if( !cert )
+ return -1;
+
+ pkt = search_packet( cert, CDK_PKT_PUBLIC_KEY );
+ if( pkt )
+ version = pkt->pkt.public_key->version;
+ search_packet( NULL, 0 );
+
+ return version;
+}
+
+
+/**
+ * gnutls_openpgp_extract_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_extract_key_creation_time( const gnutls_datum *cert )
+{
+ CDK_PACKET *pkt;
+ time_t timestamp = 0;
+
+ if( !cert )
+ return (time_t)-1;
+
+ pkt = search_packet( cert, CDK_PKT_PUBLIC_KEY );
+ if( pkt )
+ timestamp = pkt->pkt.public_key->timestamp;
+ search_packet( NULL, 0 );
+
+ return timestamp;
+}
+
+
+/**
+ * gnutls_openpgp_extract_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_extract_key_expiration_time( const gnutls_datum *cert )
+{
+ CDK_PACKET *pkt;
+ time_t expiredate = 0;
+
+ if( !cert )
+ return (time_t)-1;
+
+ pkt = search_packet( cert, CDK_PKT_PUBLIC_KEY );
+ if( pkt )
+ expiredate = pkt->pkt.public_key->expiredate;
+ search_packet( NULL, 0 );
+
+ return expiredate;
+}
+
+
+int
+_gnutls_openpgp_get_key_trust( const char *trustdb,
+ const gnutls_datum *key,
+ int *r_trustval )
+{
+ CDK_KBNODE knode = NULL;
+ CDK_STREAM inp;
+ CDK_PACKET *pkt;
+ cdkPKT_public_key *pk = NULL;
+ int flags = 0, ot = 0;
+ int rc = 0;
+
+ if( !trustdb || !key || !r_trustval ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ *r_trustval = 0;
+
+ rc = cdk_kbnode_read_from_mem( &knode, key->data, key->size );
+ if( (rc = _gnutls_map_cdk_rc( rc )) )
+ return rc;
+
+ pkt = cdk_kbnode_find_packet( knode, CDK_PKT_PUBLIC_KEY );
+ if( !pkt ) {
+ rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
+ goto leave;
+ }
+ pk = pkt->pkt.public_key;
+
+ rc = cdk_stream_open( trustdb, &inp );
+ if( rc ) {
+ rc = _gnutls_map_cdk_rc( rc );
+ goto leave;
+ }
+
+ rc = cdk_trustdb_get_ownertrust( inp, pk, &ot, &flags );
+ cdk_stream_close( inp );
+ if ( rc ) { /* no ownertrust record was found */
+ rc = 0;
+ *r_trustval = 0;
+ goto leave;
+ }
+
+ if( flags & CDK_TFLAG_DISABLED ) {
+ *r_trustval |= GNUTLS_CERT_NOT_TRUSTED;
+ *r_trustval |= GNUTLS_CERT_INVALID;
+ goto leave;
+ }
+
+ if( flags & CDK_TFLAG_REVOKED ) {
+ *r_trustval |= GNUTLS_CERT_NOT_TRUSTED;
+ *r_trustval |= GNUTLS_CERT_REVOKED;
+ }
+
+ switch( ot ) {
+ case CDK_TRUST_NEVER:
+ *r_trustval |= GNUTLS_CERT_NOT_TRUSTED;
+ break;
+ case CDK_TRUST_UNKNOWN:
+ case CDK_TRUST_UNDEFINED:
+ case CDK_TRUST_MARGINAL:
+ case CDK_TRUST_FULLY:
+ case CDK_TRUST_ULTIMATE:
+ *r_trustval |= 1; /* means okay */
+ rc = 0;
+ break;
+ }
+
+leave:
+ if( rc )
+ *r_trustval |= GNUTLS_CERT_NOT_TRUSTED;
+ cdk_kbnode_release( knode );
+ return rc;
+}
+
+
+/**
+ * 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.
+ *
+ * Verify all signatures in the certificate list. When the key
+ * is not available, the signature is skipped.
+ *
+ * When the trustdb parameter is used, the function checks the
+ * ownertrust of the key before the signatures are checked. It
+ * is possible that the key was disabled or the owner is not trusted
+ * at all. Then we don't check the signatures because it makes no sense.
+ *
+ * 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 char *trustdb,
+ const gnutls_datum* keyring,
+ const gnutls_datum* cert_list,
+ int cert_list_length )
+{
+ CDK_KBNODE knode = NULL;
+ CDK_KEYDB_HD hd = NULL;
+ keybox_blob *blob = NULL;
+ int rc = 0;
+ int status = 0;
+
+ if( !cert_list || cert_list_length != 1 || !keyring ) {
+ gnutls_assert();
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+ }
+
+ if( !keyring->size && !trustdb ) {
+ gnutls_assert( );
+ return GNUTLS_CERT_INVALID | GNUTLS_CERT_NOT_TRUSTED;
+ }
+
+ blob = kbx_read_blob( keyring, 0 );
+ if( !blob ) {
+ gnutls_assert();
+ return GNUTLS_CERT_INVALID | GNUTLS_CERT_NOT_TRUSTED;
+ }
+ hd = kbx_to_keydb( blob );
+ if( !hd ) {
+ rc = GNUTLS_CERT_INVALID | GNUTLS_CERT_NOT_TRUSTED;
+ goto leave;
+ }
+
+ if( trustdb ) {
+ int ktrust;
+ rc = _gnutls_openpgp_get_key_trust( trustdb, cert_list, &ktrust );
+ if( rc || !ktrust )
+ goto leave;
+ }
+
+ rc = cdk_kbnode_read_from_mem( &knode, cert_list->data, cert_list->size );
+ if( (rc = _gnutls_map_cdk_rc( rc )) ) {
+ goto leave;
+ return GNUTLS_CERT_INVALID | GNUTLS_CERT_NOT_TRUSTED;
+ }
+
+ rc = cdk_key_check_sigs( knode, hd, &status );
+ if( rc == CDK_Error_No_Key )
+ rc = 0; /* fixme */
+
+ switch( status ) {
+ case CDK_KEY_INVALID:
+ rc = GNUTLS_CERT_INVALID | GNUTLS_CERT_NOT_TRUSTED;
+ break;
+
+ case CDK_KEY_REVOKED:
+ rc = GNUTLS_CERT_REVOKED | GNUTLS_CERT_NOT_TRUSTED;
+ break;
+ }
+
+leave:
+ kbx_blob_release( blob );
+ cdk_free( hd );
+ cdk_kbnode_release( knode );
+ if( rc ) {
+ gnutls_assert();
+ }
+ return rc;
+}
+
+
+/**
+ * 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 *cert,
+ unsigned char *fpr, size_t *fprlen )
+{
+ CDK_PACKET *pkt;
+ cdkPKT_public_key *pk = NULL;
+
+ if( !cert || !fpr || !fprlen ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ *fprlen = 0;
+
+ pkt = search_packet( cert, CDK_PKT_PUBLIC_KEY );
+ if( !pkt )
+ return GNUTLS_E_OPENPGP_GETKEY_FAILED;
+
+ pk = pkt->pkt.public_key;
+ *fprlen = 20;
+ if ( is_RSA(pk->pubkey_algo) && pk->version < 4 )
+ *fprlen = 16;
+ cdk_pk_get_fingerprint( pk, fpr );
+ search_packet( NULL, 0 );
+
+ return 0;
+}
+
+
+/**
+ * gnutls_openpgp_extract_key_id - Gets the keyID
+ * @cert: the raw data 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_extract_key_id( const gnutls_datum *cert,
+ unsigned char keyid[8] )
+{
+ CDK_PACKET *pkt;
+ cdkPKT_public_key *pk = NULL;
+ unsigned long kid[2];
+
+ if( !cert || !keyid ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ pkt = search_packet( cert, CDK_PKT_PUBLIC_KEY );
+ if( !pkt )
+ return GNUTLS_E_OPENPGP_GETKEY_FAILED;
+
+ pk = pkt->pkt.public_key;
+ cdk_pk_get_keyid( pk, 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];
+ search_packet( NULL, 0 );
+
+ return 0;
+}
+
+
+/*-
+ * gnutls_openpgp_add_keyring_file - Adds a keyring file for OpenPGP
+ * @keyring: data buffer to store the file.
+ * @name: filename of the keyring.
+ *
+ * The function is used to set keyrings that will be used internally
+ * by various OpenCDK functions. For example to find a key when it
+ * is needed for an operations.
+ -*/
+int
+gnutls_openpgp_add_keyring_file(gnutls_datum *keyring, const char *name)
+{
+ CDK_STREAM inp = NULL;
+ uint8 *blob;
+ size_t nbytes;
+ int enc = 0;
+ int rc = 0;
+
+ if( !keyring || !name ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ rc = cdk_stream_open( name, &inp );
+ if( rc )
+ return _gnutls_map_cdk_rc( rc );
+ enc = cdk_armor_filter_use( inp );
+ cdk_stream_close( inp );
+
+ blob = kbx_data_to_keyring( KBX_BLOB_FILE, enc, name,
+ strlen( name ), &nbytes);
+ if( blob && nbytes ) {
+ if ( datum_append( keyring, blob, nbytes ) < 0 ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ gnutls_free( blob );
+ }
+ return 0;
+}
+
+
+/*-
+ * gnutls_openpgp_add_keyring_mem - Adds keyring data for OpenPGP
+ * @keyring: data buffer to store the file.
+ * @data: the binary data of the keyring.
+ * @len: the size of the binary buffer.
+ *
+ * Same as gnutls_openpgp_add_keyring_mem but now we store the
+ * data instead of the filename.
+ -*/
+int
+gnutls_openpgp_add_keyring_mem(gnutls_datum *keyring,
+ const opaque *data, size_t len)
+{
+ uint8 *blob;
+ size_t nbytes = 0;
+
+ if( !keyring || !data || !len ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ blob = kbx_data_to_keyring( KBX_BLOB_DATA, 0, data, len, &nbytes );
+ if( blob && nbytes ) {
+ if ( datum_append( keyring, blob, nbytes ) < 0 ) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ gnutls_free( blob );
+ }
+
+ return 0;
+}
+
+
+/**
+ * gnutls_certificate_set_openpgp_keyring_file - Adds 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( gnutls_certificate_credentials c,
+ const char *file )
+{
+ struct stat statbuf;
+
+ if( !c || !file ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if( stat( file, &statbuf ) )
+ return GNUTLS_E_FILE_ERROR;
+
+ return gnutls_openpgp_add_keyring_file( &c->keyring, file );
+}
+
+
+int
+gnutls_certificate_set_openpgp_keyring_mem( gnutls_certificate_credentials c,
+ const opaque *data, size_t dlen )
+{
+ CDK_STREAM inp;
+ size_t count;
+ uint8 *buf;
+ int rc = 0;
+
+ if( !c || !data || !dlen ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ inp = cdk_stream_tmp_from_mem( data, dlen );
+ if( !inp )
+ return GNUTLS_E_FILE_ERROR;
+
+ /* Maybe it's a little confusing that we check the output..
+ but it's possible, that the data we want to add, is armored
+ and we only want to store plaintext keyring data. */
+ if( cdk_armor_filter_use( inp ) )
+ cdk_stream_set_armor_flag( inp, 0 );
+
+ /* fixme: this is possible the armored length. */
+ count = cdk_stream_get_length( inp );
+ buf = gnutls_malloc( count + 1 );
+ if( !buf ) {
+ gnutls_assert();
+ cdk_stream_close( inp );
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ count = cdk_stream_read( inp, buf, count );
+ buf[count] = '\0';
+ rc = gnutls_openpgp_add_keyring_mem( &c->keyring, buf, count );
+ cdk_stream_close( inp );
+
+ return rc;
+}
+
+/*-
+ * _gnutls_openpgp_request_key - Receives a key from a database, key server etc
+ * @ret - a pointer to gnutls_datum structure.
+ * @cred - a gnutls_certificate_credentials 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( gnutls_session session, gnutls_datum* ret,
+ const gnutls_certificate_credentials cred,
+ opaque* key_fpr,
+ int key_fpr_size)
+{
+ int rc = 0;
+
+ 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 */
+
+ rc = gnutls_openpgp_get_key( ret, &cred->keyring, KEY_ATTR_FPR, key_fpr );
+ if( rc >= 0 ) /* key was found */
+ return rc;
+ 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();
+ return GNUTLS_E_OPENPGP_GETKEY_FAILED;
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * gnutls_certificate_set_openpgp_keyserver - Used to set an OpenPGP key server
+ * @res: the destination context to save the data.
+ * @server: is the key server address
+ * @port: is the key server port to connect to
+ *
+ * This funtion will set a key server for use with openpgp keys. This
+ * key server will only be used if the peer sends a key fingerprint instead
+ * of a key in the handshake. Using a key server may delay the handshake
+ * process.
+ *
+ **/
+int
+gnutls_certificate_set_openpgp_keyserver(gnutls_certificate_credentials res,
+ char* keyserver,
+ int port)
+{
+ if( !res || !keyserver ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if( !port )
+ port = 11371;
+
+ gnutls_free( res->pgp_key_server);
+ res->pgp_key_server = gnutls_strdup( keyserver );
+ if( !res->pgp_key_server )
+ return GNUTLS_E_MEMORY_ERROR;
+ res->pgp_key_server_port = port;
+
+ return 0;
+}
+
+
+static int
+xml_add_tag( gnutls_string *xmlkey, const char *tag, const char *val )
+{
+ if( !xmlkey || !tag || !val ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ _gnutls_string_append_str( xmlkey, " <" );
+ _gnutls_string_append_str( xmlkey, tag );
+ _gnutls_string_append_str( xmlkey, ">" );
+ _gnutls_string_append_str( xmlkey, val );
+ _gnutls_string_append_str( xmlkey, "</" );
+ _gnutls_string_append_str( xmlkey, tag );
+ _gnutls_string_append_str( xmlkey, ">\n" );
+
+ return 0;
+}
+
+
+static int
+xml_add_mpi2( gnutls_string *xmlkey, const uint8 *data, size_t count,
+ const char *tag )
+{
+ char *p = NULL;
+ size_t i;
+ int rc = 0;
+
+ if( !xmlkey || !data || !tag ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ p = gnutls_calloc( 1, 2 * ( count + 3 ) );
+ if( !p ) {
+ gnutls_assert( );
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ for( i = 0; i < count; i++ )
+ sprintf( p + 2 * i, "%02X", data[i] );
+ p[2 * count] = '\0';
+
+ rc = xml_add_tag( xmlkey, tag, p );
+ gnutls_free( p );
+
+ return rc;
+}
+
+
+static int
+xml_add_mpi( gnutls_string *xmlkey, cdkPKT_public_key *pk, int idx,
+ const char *tag )
+{
+ uint8 buf[4096];
+ size_t nbytes;
+
+ nbytes = sizeof buf-1;
+ cdk_pk_get_mpi( pk, idx, buf, &nbytes, NULL );
+ return xml_add_mpi2( xmlkey, buf, nbytes, tag );
+}
+
+
+
+static int
+xml_add_key_mpi( gnutls_string *xmlkey, cdkPKT_public_key *pk )
+{
+ const char *s = " <KEY ENCODING=\"HEX\"/>\n";
+ int rc = 0;
+
+ if( !xmlkey || !pk ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ _gnutls_string_append_str( xmlkey, s );
+
+ if( is_RSA( pk->pubkey_algo ) ) {
+ rc = xml_add_mpi( xmlkey, pk, 0, "RSA-N" );
+ if( !rc )
+ rc = xml_add_mpi( xmlkey, pk, 1, "RSA-E" );
+ }
+ else if( is_DSA( pk->pubkey_algo ) ) {
+ rc = xml_add_mpi( xmlkey, pk, 0, "DSA-P" );
+ if( !rc )
+ rc = xml_add_mpi( xmlkey, pk, 1, "DSA-Q" );
+ if( !rc )
+ rc = xml_add_mpi( xmlkey, pk, 2, "DSA-G" );
+ if( !rc )
+ rc = xml_add_mpi( xmlkey, pk, 3, "DSA-Y" );
+ }
+ else if( is_ELG( pk->pubkey_algo ) ) {
+ rc = xml_add_mpi( xmlkey, pk, 0, "ELG-P" );
+ if( !rc )
+ rc = xml_add_mpi( xmlkey, pk, 1, "ELG-G" );
+ if( !rc )
+ rc = xml_add_mpi( xmlkey, pk, 2, "ELG-Y" );
+ }
+ else
+ return GNUTLS_E_UNWANTED_ALGORITHM;
+
+ return 0;
+}
+
+
+static int
+xml_add_key( gnutls_string *xmlkey, int ext, cdkPKT_public_key *pk, int sub )
+{
+ const char *algo, *s;
+ char keyid[16], fpr[41], tmp[32];
+ uint8 fingerpr[20];
+ unsigned long kid[2];
+ int i = 0, rc = 0;
+
+ if( !xmlkey || !pk ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ s = sub? " <SUBKEY>\n" : " <MAINKEY>\n";
+ _gnutls_string_append_str( xmlkey, s );
+
+ cdk_pk_get_keyid( pk, kid );
+ snprintf( keyid, 16, "%08lX%08lX", kid[0], kid[1] );
+ rc = xml_add_tag( xmlkey, "KEYID", keyid );
+ if( rc )
+ return rc;
+
+ cdk_pk_get_fingerprint( pk, fingerpr );
+ for ( i = 0; i < 20; i++ )
+ sprintf( fpr + 2 * i, "%02X", fingerpr[i] );
+ fpr[40] = '\0';
+ rc = xml_add_tag( xmlkey, "FINGERPRINT", fpr );
+ if( rc )
+ return rc;
+
+ if( is_DSA( pk->pubkey_algo ) )
+ algo = "DSA";
+ else if( is_RSA( pk->pubkey_algo ) )
+ algo = "RSA";
+ else if( is_ELG( pk->pubkey_algo ) )
+ algo = "ELG";
+ else algo = "???";
+ rc = xml_add_tag( xmlkey, "PKALGO", algo );
+ if( rc )
+ return rc;
+
+ sprintf( tmp, "%d", cdk_pk_get_nbits( pk ) );
+ rc = xml_add_tag( xmlkey, "KEYLEN", tmp );
+ if( rc )
+ return rc;
+
+ sprintf( tmp, "%lu", pk->timestamp );
+ rc = xml_add_tag( xmlkey, "CREATED", tmp );
+ if( rc )
+ return rc;
+
+ if( pk->expiredate > 0 ) {
+ sprintf( tmp, "%lu", (unsigned long)pk->expiredate );
+ rc = xml_add_tag( xmlkey, "EXPIREDATE", tmp );
+ if( rc )
+ return rc;
+ }
+
+ sprintf( tmp, "%d", pk->is_revoked );
+ rc = xml_add_tag( xmlkey, "REVOKED", tmp );
+ if( rc )
+ return rc;
+
+ if( ext ) {
+ rc = xml_add_key_mpi( xmlkey, pk );
+ if( rc )
+ return rc;
+ }
+
+ s = sub? " </SUBKEY>\n" : " </MAINKEY>\n";
+ _gnutls_string_append_str( xmlkey, s );
+
+ return 0;
+}
+
+
+static int
+xml_add_userid( gnutls_string *xmlkey, int ext,
+ gnutls_openpgp_name *dn, cdkPKT_user_id *id )
+{
+ const char *s;
+ char *p, *name, tmp[32];
+ int rc = 0;
+
+ if( !xmlkey || !dn || !id ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ s = " <USERID>\n";
+ _gnutls_string_append_str( xmlkey, s );
+
+ p = strchr( dn->name, '<' );
+ if ( p ) {
+ int len = (p - dn->name - 1);
+ name = gnutls_calloc( 1, len );
+ if( !name ) {
+ gnutls_assert( );
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ memcpy( name, dn->name, len );
+ rc = xml_add_tag( xmlkey, "NAME", name );
+ gnutls_free( name );
+ if( rc )
+ return rc;
+ }
+ else {
+ rc = xml_add_tag( xmlkey, "NAME", dn->name );
+ if( rc )
+ return rc;
+ }
+
+ rc = xml_add_tag( xmlkey, "EMAIL", dn->email );
+ if( rc )
+ return rc;
+
+ if ( ext ) {
+ sprintf( tmp, "%d", id->is_primary );
+ rc = xml_add_tag( xmlkey, "PRIMARY", tmp );
+ if( rc )
+ return rc;
+ sprintf( tmp, "%d", id->is_revoked );
+ rc = xml_add_tag( xmlkey, "REVOKED", tmp );
+ if( rc )
+ return rc;
+ }
+
+ s = " </USERID>\n";
+ _gnutls_string_append_str( xmlkey, s );
+
+ return 0;
+}
+
+
+static int
+xml_add_sig( gnutls_string *xmlkey, int ext, cdkPKT_signature *sig )
+{
+ const char *algo, *s;
+ char tmp[32], keyid[16];
+ unsigned long kid[2];
+ int rc = 0;
+
+ if( !xmlkey || !sig ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ s = " <SIGNATURE>\n";
+ _gnutls_string_append_str( xmlkey, s );
+
+ sprintf( tmp, "%d", sig->version );
+ rc = xml_add_tag( xmlkey, "VERSION", tmp );
+ if( rc )
+ return rc;
+
+ if( ext ) {
+ sprintf( tmp, "%d", sig->sig_class );
+ rc = xml_add_tag( xmlkey, "SIGCLASS", tmp );
+ if( rc )
+ return rc;
+ }
+
+ sprintf( tmp, "%d", sig->flags.expired );
+ rc = xml_add_tag( xmlkey, "EXPIRED", tmp );
+ if( rc )
+ return rc;
+
+ if ( ext ) {
+ switch( sig->pubkey_algo ) {
+ case GCRY_PK_DSA : algo = "DSA"; break;
+ case GCRY_PK_ELG :
+ case GCRY_PK_ELG_E: algo = "ELG"; break;
+ case GCRY_PK_RSA :
+ case GCRY_PK_RSA_E:
+ case GCRY_PK_RSA_S: algo = "RSA"; break;
+ default : algo = "???"; /* unknown algorithm */
+ }
+ rc = xml_add_tag( xmlkey, "PKALGO", algo );
+ if( rc )
+ return rc;
+
+ switch( sig->digest_algo ) {
+ case GCRY_MD_SHA1 : algo = "SHA1"; break;
+ case GCRY_MD_RMD160: algo = "RMD160"; break;
+ case GCRY_MD_MD5 : algo = "MD5"; break;
+ default : algo = "???";
+ }
+ rc = xml_add_tag( xmlkey, "MDALGO", algo );
+ if( rc )
+ return rc;
+ }
+
+ sprintf( tmp, "%lu", sig->timestamp );
+ rc = xml_add_tag( xmlkey, "CREATED", tmp );
+ if( rc )
+ return rc;
+
+ cdk_sig_get_keyid( sig, kid );
+ snprintf( keyid, 16, "%08lX%08lX", kid[0], kid[1] );
+ rc = xml_add_tag( xmlkey, "KEYID", keyid );
+ if( rc )
+ return rc;
+
+ s = " </SIGNATURE>\n";
+ _gnutls_string_append_str( xmlkey, s );
+
+ return 0;
+}
+
+
+/**
+ * gnutls_openpgp_key_to_xml - Return a certificate as a XML fragment
+ * @cert: the certificate which holds the whole OpenPGP key.
+ * @xmlkey: he datum struct to store the XML result.
+ * @ext: extension mode (1/0), 1 means include key signatures and key data.
+ *
+ * This function will return the all OpenPGP key information encapsulated as
+ * a XML string.
+ **/
+int
+gnutls_openpgp_key_to_xml( const gnutls_datum *cert,
+ gnutls_datum *xmlkey, int ext )
+{
+ CDK_KBNODE knode, node, ctx = NULL;
+ CDK_PACKET *pkt;
+ gnutls_openpgp_name dn;
+ const char *s;
+ int idx = 0, rc = 0;
+ gnutls_string string_xml_key;
+
+ if( !cert || !xmlkey ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ rc = cdk_kbnode_read_from_mem( &knode, cert->data, cert->size );
+ if( (rc = _gnutls_map_cdk_rc( rc )) )
+ return rc;
+
+ _gnutls_string_init( &string_xml_key, malloc, realloc, free );
+ memset( xmlkey, 0, sizeof *xmlkey );
+
+ s = "<?xml version=\"1.0\"?>\n\n";
+ _gnutls_string_append_str( &string_xml_key, s );
+
+ s = "<gnutls:openpgp:key version=\"1.0\">\n";
+ _gnutls_string_append_str( &string_xml_key, s );
+
+ s = " <OPENPGPKEY>\n";
+ _gnutls_string_append_str( &string_xml_key, s );
+
+ idx = 1;
+ while( (node = cdk_kbnode_walk( knode, &ctx, 0 )) ) {
+ pkt = cdk_kbnode_get_packet( node );
+ switch ( pkt->pkttype ) {
+ case CDK_PKT_PUBLIC_KEY:
+ rc = xml_add_key( &string_xml_key, ext, pkt->pkt.public_key, 0 );
+ break;
+
+ case CDK_PKT_PUBLIC_SUBKEY:
+ rc = xml_add_key( &string_xml_key, ext, pkt->pkt.public_key, 1 );
+ break;
+
+ case CDK_PKT_USER_ID:
+ gnutls_openpgp_extract_key_name( cert, idx, &dn );
+ rc = xml_add_userid( &string_xml_key, ext, &dn, pkt->pkt.user_id );
+ idx++;
+ break;
+
+ case CDK_PKT_SIGNATURE:
+ rc = xml_add_sig( &string_xml_key, ext, pkt->pkt.signature );
+ break;
+
+ default:
+ break;
+ }
+ }
+ if( !rc ) {
+ s = " </OPENPGPKEY>\n";
+ _gnutls_string_append_str( &string_xml_key, s );
+ }
+ s = "</gnutls:openpgp:key>\n";
+ _gnutls_string_append_str( &string_xml_key, s );
+ _gnutls_string_append_data( &string_xml_key, "\n\0", 2 );
+
+ *xmlkey = _gnutls_string2datum( &string_xml_key );
+ xmlkey->size--;
+
+ cdk_kbnode_release( knode );
+ return rc;
+}
+
+
+/**
+ * gnutls_certificate_set_openpgp_trustdb - Used to set an GnuPG trustdb
+ * @res: the destination context to save the data.
+ * @trustdb: is the trustdb filename
+ *
+ * This funtion will set a GnuPG trustdb which will be used in key
+ * verification functions. Only version 3 trustdb files are supported.
+ *
+ **/
+int
+gnutls_certificate_set_openpgp_trustdb( gnutls_certificate_credentials res,
+ char* trustdb )
+{
+ if( !res || !trustdb ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* the old v2 format was used with 1.0.6, do we still need to check
+ it now because GPG 1.0.7, 1.2.0, 1.2.1 and even 1.3.0 is out? */
+
+ gnutls_free( res->pgp_trustdb);
+ res->pgp_trustdb = gnutls_strdup( trustdb );
+ if( res->pgp_trustdb==NULL )
+ return GNUTLS_E_MEMORY_ERROR;
+
+ return 0;
+}
+
+/**
+ * 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( gnutls_session session,
+ gnutls_openpgp_recv_key_func func )
+{
+ session->internals.openpgp_recv_key_func = func;
+}
+
+#else /*!HAVE_LIBOPENCDK*/
+int
+_gnutls_openpgp_key2gnutls_key( gnutls_privkey *pkey,
+ gnutls_datum raw_key )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+_gnutls_openpgp_cert2gnutls_cert( gnutls_cert *cert, const gnutls_datum *raw )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_certificate_set_openpgp_key_mem(gnutls_certificate_credentials res,
+ gnutls_datum *cert,
+ gnutls_datum *key)
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_certificate_set_openpgp_key_file( gnutls_certificate_credentials res,
+ char* CERTFILE,
+ char* KEYFILE )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_extract_key_name( const gnutls_datum *cert, int idx,
+ gnutls_openpgp_name *dn )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_extract_key_pk_algorithm(const gnutls_datum *cert, int *r_bits)
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_extract_key_version( const gnutls_datum *cert )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+time_t
+gnutls_openpgp_extract_key_creation_time( const gnutls_datum *cert )
+{
+ return (time_t)-1;
+}
+
+time_t
+gnutls_openpgp_extract_key_expiration_time( const gnutls_datum *cert )
+{
+ return (time_t)-1;
+}
+
+int
+gnutls_openpgp_verify_key( const char* ign, const gnutls_datum* keyring,
+ const gnutls_datum* cert_list,
+ int cert_list_length )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_fingerprint(const gnutls_datum *cert, unsigned char *fpr, size_t *fprlen)
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_add_keyring_file( gnutls_datum *keyring, const char *name )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_add_keyring_mem( gnutls_datum *keyring,
+ const opaque *data, size_t len )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_certificate_set_openpgp_keyring_file( gnutls_certificate_credentials c,
+ const char *file )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_certificate_set_openpgp_keyring_mem( gnutls_certificate_credentials c,
+ const opaque* data,
+ size_t dlen)
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+_gnutls_openpgp_request_key( gnutls_session session, gnutls_datum* ret,
+ const gnutls_certificate_credentials cred,
+ opaque* key_fpr,
+ int key_fpr_size )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_certificate_set_openpgp_keyserver( gnutls_certificate_credentials res,
+ char* keyserver,
+ int port )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_certificate_set_openpgp_trustdb( gnutls_certificate_credentials res,
+ char* trustdb )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_key_to_xml( const gnutls_datum *cert,
+ gnutls_datum *xmlkey, int ext )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_extract_key_id( const gnutls_datum *cert,
+ unsigned char keyid[8] )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+void gnutls_openpgp_set_recv_key_function( gnutls_session session,
+ gnutls_openpgp_recv_key_func func )
+{
+
+}
+
+int
+gnutls_openpgp_extract_key_name_string( const gnutls_datum *cert,
+ int idx,
+ char *buf, unsigned int sizeof_buf)
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+int
+gnutls_openpgp_get_key( gnutls_datum *key, const gnutls_datum *keyring,
+ key_attr_t by, opaque *pattern )
+{
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+}
+
+#endif /* HAVE_LIBOPENCDK */
+
diff --git a/libextra/openpgp/openpgp.c b/libextra/openpgp/openpgp.c
new file mode 100644
index 0000000000..f2b3fd1155
--- /dev/null
+++ b/libextra/openpgp/openpgp.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2002 Timo Schulz
+ * Portions Copyright (C) 2003 Nikos Mavroyanopoulos
+ *
+ * This file is part of GNUTLS-EXTRA.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Functions on OpenPGP key parsing
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_errors.h>
+#include <opencdk.h>
+#include <openpgp.h>
+#include <x509/rfc2818.h>
+
+/**
+ * gnutls_openpgp_key_init - This function initializes a gnutls_openpgp_key structure
+ * @key: The structure to be initialized
+ *
+ * This function will initialize an OpenPGP key structure.
+ *
+ * Returns 0 on success.
+ *
+ **/
+int gnutls_openpgp_key_init(gnutls_openpgp_key * key)
+{
+ *key = gnutls_calloc( 1, sizeof(gnutls_openpgp_key_int));
+
+ if (*key) {
+ return 0; /* success */
+ }
+ return GNUTLS_E_MEMORY_ERROR;
+}
+
+/**
+ * gnutls_openpgp_key_deinit - This function deinitializes memory used by a gnutls_openpgp_key structure
+ * @key: The structure to be initialized
+ *
+ * This function will deinitialize a CRL structure.
+ *
+ **/
+void gnutls_openpgp_key_deinit(gnutls_openpgp_key key)
+{
+ if (key->knode) {
+ cdk_kbnode_release( key->knode);
+ key->knode = NULL;
+ }
+
+ gnutls_free(key);
+}
+
+/**
+ * gnutls_openpgp_key_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_key_fmt elements.
+ *
+ * This function will convert the given RAW or Base64 encoded key
+ * to the native gnutls_openpgp_key format. The output will be stored in 'key'.
+ *
+ * Returns 0 on success.
+ *
+ **/
+int gnutls_openpgp_key_import(gnutls_openpgp_key key,
+ const gnutls_datum * data,
+ gnutls_openpgp_key_fmt format)
+{
+int rc;
+
+ rc = cdk_kbnode_read_from_mem( &key->knode, data->data, data->size);
+ if( (rc = _gnutls_map_cdk_rc( rc ))) {
+ gnutls_assert();
+ return rc;
+ }
+
+ return 0;
+}
+
+
+/**
+ * gnutls_openpgp_key_get_fingerprint - Gets the fingerprint
+ * @key: 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_key_get_fingerprint( gnutls_openpgp_key key,
+ unsigned char *fpr, size_t *fprlen )
+{
+ CDK_PACKET *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;
+
+ 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_key key)
+{
+ cdk_kbnode_t p, ctx = NULL;
+ CDK_PACKET *pkt;
+ int nuids = 0;
+
+ if( key == NULL ) {
+ gnutls_assert();
+ return 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_key_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 size of 'buf'
+ *
+ * Extracts the userID from the parsed OpenPGP key.
+ **/
+int
+gnutls_openpgp_key_get_name( gnutls_openpgp_key key,
+ int idx,
+ char *buf, unsigned int *sizeof_buf)
+{
+ cdk_kbnode_t ctx = NULL, p;
+ CDK_PACKET *pkt = NULL;
+ cdk_pkt_userid_t uid = NULL;
+ int pos = 0;
+ size_t size = 0;
+ int rc = 0;
+
+ if( !key || !buf ) {
+ gnutls_assert( );
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if( idx < 0 || idx > _gnutls_openpgp_count_key_names( key) ) {
+ gnutls_assert( );
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ 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 ) {
+ rc = GNUTLS_E_INTERNAL_ERROR;
+ goto leave;
+ }
+
+ uid = pkt->pkt.user_id;
+
+ if (uid->len >= *sizeof_buf) {
+ gnutls_assert();
+ *sizeof_buf = uid->len + 1;
+ rc = GNUTLS_E_SHORT_MEMORY_BUFFER;
+ goto leave;
+ }
+
+ size = uid->len < *sizeof_buf? uid->len : *sizeof_buf-1;
+ memcpy( buf, uid->name, size);
+
+ buf[size] = '\0'; /* make sure it's a string */
+
+ if( uid->is_revoked ) {
+ rc = GNUTLS_E_OPENPGP_UID_REVOKED;
+ goto leave;
+ }
+
+leave:
+ return rc;
+}
+
+/**
+ * gnutls_openpgp_key_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.
+ *
+ **/
+int
+gnutls_openpgp_key_get_pk_algorithm( gnutls_openpgp_key key, int *r_bits)
+{
+ CDK_PACKET *pkt;
+ int algo = 0;
+
+ if( !key )
+ return GNUTLS_E_INVALID_REQUEST;
+
+ pkt = cdk_kbnode_find_packet( key->knode, CDK_PKT_PUBLIC_KEY );
+ if( pkt && pkt->pkttype == CDK_PKT_PUBLIC_KEY ) {
+ if( r_bits )
+ *r_bits = cdk_pk_get_nbits( pkt->pkt.public_key );
+ algo = pkt->pkt.public_key->pubkey_algo;
+ if( is_RSA( algo ) )
+ algo = GNUTLS_PK_RSA;
+ else if( is_DSA( algo ) )
+ algo = GNUTLS_PK_DSA;
+ else
+ algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+ }
+
+ return algo;
+}
+
+
+/**
+ * gnutls_openpgp_key_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_extract_key_version( gnutls_openpgp_key key)
+{
+ CDK_PACKET *pkt;
+ int version = 0;
+
+ if( !key)
+ return -1;
+
+ pkt = cdk_kbnode_find_packet( key->knode, CDK_PKT_PUBLIC_KEY );
+ if( pkt )
+ version = pkt->pkt.public_key->version;
+
+ return version;
+}
+
+
+/**
+ * gnutls_openpgp_key_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_extract_key_creation_time( gnutls_openpgp_key key)
+{
+ CDK_PACKET *pkt;
+ time_t timestamp = 0;
+
+ 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;
+
+ return timestamp;
+}
+
+
+/**
+ * gnutls_openpgp_key_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_key_get_expiration_time( gnutls_openpgp_key key)
+{
+ CDK_PACKET *pkt;
+ time_t expiredate = 0;
+
+ 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;
+
+ return expiredate;
+}
+
+/**
+ * gnutls_openpgp_key_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_key_get_id( gnutls_openpgp_key key,
+ unsigned char keyid[8])
+{
+ CDK_PACKET *pkt;
+ cdk_pkt_pubkey_t pk = NULL;
+ unsigned long 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;
+
+ pk = pkt->pkt.public_key;
+ cdk_pk_get_keyid( pk, 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_key_check_hostname - This function compares the given hostname with the hostname in the key
+ * @key: should contain an gnutls_openpgp_key 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_key_check_hostname(gnutls_openpgp_key cert,
+ const char *hostname)
+{
+
+ char dnsname[MAX_CN];
+ int dnsnamesize;
+ int ret = 0;
+ int i = 0;
+
+ /* Check through all included names.
+ */
+ for (i = 0; !(ret < 0); i++) {
+
+ dnsnamesize = sizeof(dnsname);
+ ret =
+ gnutls_openpgp_key_get_name(key, i,
+ dnsname, &dnsnamesize);
+
+ if (_gnutls_hostname_compare(dnsname, hostname)) {
+ return 1;
+ }
+ }
+
+ /* not found a matching name
+ */
+ return 0;
+}
+
diff --git a/libextra/openpgp/openpgp.h b/libextra/openpgp/openpgp.h
new file mode 100644
index 0000000000..89c96155d2
--- /dev/null
+++ b/libextra/openpgp/openpgp.h
@@ -0,0 +1,16 @@
+#ifndef OPENPGP_H
+# define OPENPGP_H
+
+typedef struct gnutls_openpgp_key_int {
+ cdk_kbnode_t knode;
+} gnutls_openpgp_key_int;
+
+typedef enum gnutls_openpgp_key_fmt { GNUTLS_X509_FMT_RAW,
+ GNUTLS_X509_FMT_BASE64 } gnutls_openpgp_key_fmt;
+
+typedef struct gnutls_openpgp_key_int *gnutls_openpgp_key;
+
+int
+_gnutls_map_cdk_rc( int rc);
+
+#endif