diff --git a/configure.in b/configure.in index 73941db43..dca56c999 100644 --- a/configure.in +++ b/configure.in @@ -298,6 +298,17 @@ AC_ARG_ENABLE( pkcs1=true ) +AC_ARG_ENABLE( + [pgp], + AS_HELP_STRING([--disable-pkcs],[disable PGP key decoding plugin. (default is NO).]), + [if test x$enableval = xyes; then + pgp=true + else + pgp=false + fi], + pgp=true +) + AC_ARG_ENABLE( [pem], AS_HELP_STRING([--disable-pem],[disable PEM decoding plugin. (default is NO).]), @@ -1207,6 +1218,10 @@ if test x$pkcs1 = xtrue; then libstrongswan_plugins=${libstrongswan_plugins}" pkcs1" pluto_plugins=${pluto_plugins}" pkcs1" fi +if test x$pgp = xtrue; then + libstrongswan_plugins=${libstrongswan_plugins}" pgp" + pluto_plugins=${pluto_plugins}" pgp" +fi if test x$pem = xtrue; then libstrongswan_plugins=${libstrongswan_plugins}" pem" pluto_plugins=${pluto_plugins}" pem" @@ -1268,6 +1283,7 @@ AM_CONDITIONAL(USE_RANDOM, test x$random = xtrue) AM_CONDITIONAL(USE_X509, test x$x509 = xtrue) AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue) AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue) +AM_CONDITIONAL(USE_PGP, test x$pgp = xtrue) AM_CONDITIONAL(USE_PEM, test x$pem = xtrue) AM_CONDITIONAL(USE_HMAC, test x$hmac = xtrue) AM_CONDITIONAL(USE_XCBC, test x$xcbc = xtrue) @@ -1364,6 +1380,7 @@ AC_OUTPUT( src/libstrongswan/plugins/x509/Makefile src/libstrongswan/plugins/pubkey/Makefile src/libstrongswan/plugins/pkcs1/Makefile + src/libstrongswan/plugins/pgp/Makefile src/libstrongswan/plugins/pem/Makefile src/libstrongswan/plugins/curl/Makefile src/libstrongswan/plugins/ldap/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index e3585cf99..23c42f674 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -165,6 +165,10 @@ if USE_PKCS1 SUBDIRS += plugins/pkcs1 endif +if USE_PGP + SUBDIRS += plugins/pgp +endif + if USE_PEM SUBDIRS += plugins/pem endif diff --git a/src/libstrongswan/plugins/pgp/Makefile.am b/src/libstrongswan/plugins/pgp/Makefile.am new file mode 100644 index 000000000..c143e9e2d --- /dev/null +++ b/src/libstrongswan/plugins/pgp/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-pgp.la + +libstrongswan_pgp_la_SOURCES = pgp_plugin.h pgp_plugin.c \ + pgp_builder.h pgp_builder.c + +libstrongswan_pgp_la_LDFLAGS = -module -avoid-version + diff --git a/src/libstrongswan/plugins/pgp/pgp_builder.c b/src/libstrongswan/plugins/pgp/pgp_builder.c new file mode 100644 index 000000000..8a6fc76b8 --- /dev/null +++ b/src/libstrongswan/plugins/pgp/pgp_builder.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2009 Martin Willi + * Copyright (C) 2002-2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * This program 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. See . + * + * This program 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. + */ + +#include "pgp_builder.h" + +#include +#include + + +ENUM_BEGIN(pgp_packet_tag_names, PGP_PKT_RESERVED, PGP_PKT_PUBLIC_SUBKEY, + "Reserved", + "Public-Key Encrypted Session Key Packet", + "Signature Packet", + "Symmetric-Key Encrypted Session Key Packet", + "One-Pass Signature Packet", + "Secret Key Packet", + "Public Key Packet", + "Secret Subkey Packet", + "Compressed Data Packet", + "Symmetrically Encrypted Data Packet", + "Marker Packet", + "Literal Data Packet", + "Trust Packet", + "User ID Packet", + "Public Subkey Packet" +); +ENUM_NEXT(pgp_packet_tag_names, PGP_PKT_USER_ATTRIBUTE, PGP_PKT_MOD_DETECT_CODE, PGP_PKT_PUBLIC_SUBKEY, + "User Attribute Packet", + "Sym. Encrypted and Integrity Protected Data Packet", + "Modification Detection Code Packet" +); +ENUM_END(pgp_packet_tag_names, PGP_PKT_MOD_DETECT_CODE); + +ENUM_BEGIN(pgp_pubkey_alg_names, PGP_PUBKEY_ALG_RSA, PGP_PUBKEY_ALG_RSA_SIGN_ONLY, + "RSA", + "RSA_ENC_ONLY", + "RSA_SIGN_ONLY" +); +ENUM_NEXT(pgp_pubkey_alg_names, PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY, PGP_PUBKEY_ALG_DIFFIE_HELLMAN, PGP_PUBKEY_ALG_RSA_SIGN_ONLY, + "ELGAMAL_ENC_ONLY", + "DSA", + "ECC", + "ECDSA", + "ELGAMAL", + "DIFFIE_HELLMAN" +); +ENUM_END(pgp_pubkey_alg_names, PGP_PUBKEY_ALG_DIFFIE_HELLMAN); + +ENUM(pgp_sym_alg_names, PGP_SYM_ALG_PLAIN, PGP_SYM_ALG_TWOFISH, + "PLAINTEXT", + "IDEA", + "3DES", + "CAST5", + "BLOWFISH", + "SAFER", + "DES", + "AES_128", + "AES_192", + "AES_256", + "TWOFISH" +); + +/** + * Read a PGP scalar of bytes length, advance blob + */ +static bool read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar) +{ + u_int32_t res = 0; + + if (bytes > blob->len) + { + DBG1("PGP data too short to read %d byte scalar", bytes); + return FALSE; + } + while (bytes-- > 0) + { + res = 256 * res + blob->ptr[0]; + *blob = chunk_skip(*blob, 1); + } + *scalar = res; + return TRUE; +} + +/** + * Read a PGP MPI, advance blob + */ +static bool read_mpi(chunk_t *blob, chunk_t *mpi) +{ + u_int32_t bits, bytes; + + if (!read_scalar(blob, 2, &bits)) + { + DBG1("PGP data too short to read MPI length"); + return FALSE; + } + bytes = (bits + 7) / 8; + if (bytes > blob->len) + { + DBG1("PGP data too short to %d byte MPI", bytes); + return FALSE; + } + *mpi = chunk_create(blob->ptr, bytes); + *blob = chunk_skip(*blob, bytes); + return TRUE; +} + +/** + * Load a generic public key from a PGP packet + */ +static public_key_t *parse_public_key(chunk_t blob) +{ + u_int32_t alg; + public_key_t *key; + + if (!read_scalar(&blob, 1, &alg)) + { + return NULL; + } + switch (alg) + { + case PGP_PUBKEY_ALG_RSA: + case PGP_PUBKEY_ALG_RSA_SIGN_ONLY: + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_PGP, blob, BUILD_END); + break; + default: + DBG1("PGP public key algorithm %N not supported", + pgp_pubkey_alg_names, alg); + return NULL; + } + return key; +} + +/** + * Load a RSA public key from a PGP packet + */ +static public_key_t *parse_rsa_public_key(chunk_t blob) +{ + chunk_t mpi[2]; + int i; + + for (i = 0; i < 2; i++) + { + if (!read_mpi(&blob, &mpi[i])) + { + return NULL; + } + } + return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1], + BUILD_END); +} + +/** + * Load a RSA private key from a PGP packet + */ +static private_key_t *parse_rsa_private_key(chunk_t blob) +{ + chunk_t mpi[6]; + u_int32_t s2k; + int i; + + for (i = 0; i < 2; i++) + { + if (!read_mpi(&blob, &mpi[i])) + { + return NULL; + } + } + if (!read_scalar(&blob, 1, &s2k)) + { + return NULL; + } + if (s2k == 255 || s2k == 254) + { + DBG1("string-to-key specifiers not supported"); + return NULL; + } + if (s2k != PGP_SYM_ALG_PLAIN) + { + DBG1("%N private key encryption not supported", pgp_sym_alg_names, s2k); + return NULL; + } + + for (i = 2; i < 6; i++) + { + if (!read_mpi(&blob, &mpi[i])) + { + return NULL; + } + } + return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1], + BUILD_RSA_PRIV_EXP, mpi[2], BUILD_RSA_PRIME1, mpi[3], + BUILD_RSA_PRIME2, mpi[4], BUILD_RSA_COEFF, mpi[5], + BUILD_END); +} + +typedef struct private_builder_t private_builder_t; + +/** + * Builder implementation for private/public key loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** PGP packet data */ + chunk_t blob; + /** type of key to build */ + key_type_t type; +}; + +/** + * Implementation of builder_t.build for public keys + */ +static public_key_t *build_public(private_builder_t *this) +{ + public_key_t *key = NULL; + + switch (this->type) + { + case KEY_ANY: + key = parse_public_key(this->blob); + break; + case KEY_RSA: + key = parse_rsa_public_key(this->blob); + break; + default: + break; + } + free(this); + return key; +} + +/** + * Implementation of builder_t.add for public keys + */ +static void add_public(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + switch (part) + { + case BUILD_BLOB_PEM: + { + va_start(args, part); + this->blob = va_arg(args, chunk_t); + va_end(args); + break; + } + default: + builder_cancel(&this->public); + break; + } +} + +/** + * Builder construction function for public keys + */ +builder_t *pgp_public_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_ANY && type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->blob = chunk_empty; + this->type = type; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add_public; + this->public.build = (void*(*)(builder_t *this))build_public; + + return &this->public; +} + +/** + * Implementation of builder_t.build for private keys + */ +static private_key_t *build_private(private_builder_t *this) +{ + private_key_t *key; + + key = parse_rsa_private_key(this->blob); + free(this); + return key; +} + +/** + * Implementation of builder_t.add for private keys + */ +static void add_private(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + switch (part) + { + case BUILD_BLOB_PGP: + { + va_start(args, part); + this->blob = va_arg(args, chunk_t); + va_end(args); + break; + } + default: + builder_cancel(&this->public); + break; + } +} + +/** + * Builder construction function for private keys + */ +builder_t *pgp_private_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->blob = chunk_empty; + this->type = type; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add_private; + this->public.build = (void*(*)(builder_t *this))build_private; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/pgp/pgp_builder.h b/src/libstrongswan/plugins/pgp/pgp_builder.h new file mode 100644 index 000000000..8d9935bcc --- /dev/null +++ b/src/libstrongswan/plugins/pgp/pgp_builder.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2009 Martin Willi + * Copyright (C) 2002-2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * This program 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. See . + * + * This program 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. + */ + +/** + * @defgroup pgp_public_key pgp_public_key + * @{ @ingroup pgp_p + */ + +#ifndef PGP_BUILDER_H_ +#define PGP_BUILDER_H_ + +#include +#include + +typedef enum pgp_packet_tag_t pgp_packet_tag_t; +typedef enum pgp_pubkey_alg_t pgp_pubkey_alg_t; +typedef enum pgp_sym_alg_t pgp_sym_alg_t; + +/** + * OpenPGP packet tags as defined in section 4.3 of RFC 4880 + */ +enum pgp_packet_tag_t { + PGP_PKT_RESERVED = 0, + PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, + PGP_PKT_SIGNATURE = 2, + PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, + PGP_PKT_ONE_PASS_SIGNATURE_PKT = 4, + PGP_PKT_SECRET_KEY = 5, + PGP_PKT_PUBLIC_KEY = 6, + PGP_PKT_SECRET_SUBKEY = 7, + PGP_PKT_COMPRESSED_DATA = 8, + PGP_PKT_SYMKEY_ENC_DATA = 9, + PGP_PKT_MARKER = 10, + PGP_PKT_LITERAL_DATA = 11, + PGP_PKT_TRUST = 12, + PGP_PKT_USER_ID = 13, + PGP_PKT_PUBLIC_SUBKEY = 14, + PGP_PKT_USER_ATTRIBUTE = 17, + PGP_PKT_SYM_ENC_INT_PROT_DATA = 18, + PGP_PKT_MOD_DETECT_CODE = 19 +}; + +/** + * Enum names for pgp_packet_tag_t + */ +extern enum_name_t *pgp_packet_tag_names; + +/** + * OpenPGP public key algorithms as defined in section 9.1 of RFC 4880 + */ +enum pgp_pubkey_alg_t { + PGP_PUBKEY_ALG_RSA = 1, + PGP_PUBKEY_ALG_RSA_ENC_ONLY = 2, + PGP_PUBKEY_ALG_RSA_SIGN_ONLY = 3, + PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY = 16, + PGP_PUBKEY_ALG_DSA = 17, + PGP_PUBKEY_ALG_ECC = 18, + PGP_PUBKEY_ALG_ECDSA = 19, + PGP_PUBKEY_ALG_ELGAMAL = 20, + PGP_PUBKEY_ALG_DIFFIE_HELLMAN = 21, +}; + +/** + * Enum names for pgp_pubkey_alg_t + */ +extern enum_name_t *pgp_pubkey_alg_names; + +/** + * OpenPGP symmetric key algorithms as defined in section 9.2 of RFC 4880 + */ +enum pgp_sym_alg_t { + PGP_SYM_ALG_PLAIN = 0, + PGP_SYM_ALG_IDEA = 1, + PGP_SYM_ALG_3DES = 2, + PGP_SYM_ALG_CAST5 = 3, + PGP_SYM_ALG_BLOWFISH = 4, + PGP_SYM_ALG_SAFER = 5, + PGP_SYM_ALG_DES = 6, + PGP_SYM_ALG_AES_128 = 7, + PGP_SYM_ALG_AES_192 = 8, + PGP_SYM_ALG_AES_256 = 9, + PGP_SYM_ALG_TWOFISH = 10 +}; + +/** + * Enum names for pgp_sym_alg_t + */ +extern enum_name_t *pgp_sym_alg_names; + +/** + * Create the builder for a generic or an RSA public key. + * + * @param type type of the key, either KEY_ANY or KEY_RSA + * @return builder instance + */ +builder_t *pgp_public_key_builder(key_type_t type); + +/** + * Create the builder for a RSA private key. + * + * @param type type of the key, KEY_RSA + * @return builder instance + */ +builder_t *pgp_private_key_builder(key_type_t type); + +#endif /** PGP_BUILDER_H_ @}*/ diff --git a/src/libstrongswan/plugins/pgp/pgp_plugin.c b/src/libstrongswan/plugins/pgp/pgp_plugin.c new file mode 100644 index 000000000..5e01d9dd3 --- /dev/null +++ b/src/libstrongswan/plugins/pgp/pgp_plugin.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program 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. See . + * + * This program 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. + */ + +#include "pgp_plugin.h" + +#include +#include "pgp_builder.h" + +typedef struct private_pgp_plugin_t private_pgp_plugin_t; + +/** + * private data of pgp_plugin + */ +struct private_pgp_plugin_t { + + /** + * public functions + */ + pgp_plugin_t public; +}; + +/** + * Implementation of pgp_plugin_t.pgptroy + */ +static void destroy(private_pgp_plugin_t *this) +{ + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)pgp_public_key_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)pgp_private_key_builder); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_pgp_plugin_t *this = malloc_thing(private_pgp_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + (builder_constructor_t)pgp_public_key_builder); + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + (builder_constructor_t)pgp_public_key_builder); + lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + (builder_constructor_t)pgp_private_key_builder); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/pgp/pgp_plugin.h b/src/libstrongswan/plugins/pgp/pgp_plugin.h new file mode 100644 index 000000000..841de5d2d --- /dev/null +++ b/src/libstrongswan/plugins/pgp/pgp_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program 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. See . + * + * This program 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. + */ + +/** + * @defgroup pgp_p pgp + * @ingroup plugins + * + * @defgroup pgp_plugin pgp_plugin + * @{ @ingroup pgp_p + */ + +#ifndef PGP_PLUGIN_H_ +#define PGP_PLUGIN_H_ + +#include + +typedef struct pgp_plugin_t pgp_plugin_t; + +/** + * Plugin providing PKCS#1 private/public key decoding functions + */ +struct pgp_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a pgp_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /** PGP_PLUGIN_H_ @}*/