diff options
Diffstat (limited to 'src/libstrongswan/plugins')
-rw-r--r-- | src/libstrongswan/plugins/pgp/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pgp/pgp_builder.c | 198 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pgp/pgp_utils.c | 178 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pgp/pgp_utils.h | 130 |
4 files changed, 334 insertions, 173 deletions
diff --git a/src/libstrongswan/plugins/pgp/Makefile.am b/src/libstrongswan/plugins/pgp/Makefile.am index 3eb3992ec..6cbc09ed3 100644 --- a/src/libstrongswan/plugins/pgp/Makefile.am +++ b/src/libstrongswan/plugins/pgp/Makefile.am @@ -6,6 +6,7 @@ AM_CFLAGS = -rdynamic plugin_LTLIBRARIES = libstrongswan-pgp.la libstrongswan_pgp_la_SOURCES = pgp_plugin.h pgp_plugin.c \ + pgp_utils.h pgp_utils.c \ pgp_encoder.h pgp_encoder.c \ pgp_builder.h pgp_builder.c diff --git a/src/libstrongswan/plugins/pgp/pgp_builder.c b/src/libstrongswan/plugins/pgp/pgp_builder.c index 5147237c7..d262d18ff 100644 --- a/src/libstrongswan/plugins/pgp/pgp_builder.c +++ b/src/libstrongswan/plugins/pgp/pgp_builder.c @@ -15,141 +15,12 @@ */ #include "pgp_builder.h" +#include "pgp_utils.h" #include <enum.h> #include <debug.h> #include <credentials/keys/private_key.h> -typedef enum pgp_pubkey_alg_t pgp_pubkey_alg_t; -typedef enum pgp_sym_alg_t pgp_sym_alg_t; - -/** - * 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, -}; - -/** - * 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_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 length of an PGP old packet length encoding - */ -static bool old_packet_length(chunk_t *blob, u_int32_t *length) -{ - /* bits 0 and 1 define the packet length type */ - u_char type; - - if (!blob->len) - { - return FALSE; - } - type = 0x03 & blob->ptr[0]; - *blob = chunk_skip(*blob, 1); - - if (type > 2) - { - return FALSE; - } - return read_scalar(blob, type == 0 ? 1 : type * 2, length); -} - -/** - * 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 read %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 */ @@ -158,7 +29,7 @@ static public_key_t *parse_public_key(chunk_t blob) u_int32_t alg; public_key_t *key; - if (!read_scalar(&blob, 1, &alg)) + if (!pgp_read_scalar(&blob, 1, &alg)) { return NULL; } @@ -187,7 +58,7 @@ static public_key_t *parse_rsa_public_key(chunk_t blob) for (i = 0; i < 2; i++) { - if (!read_mpi(&blob, &mpi[i])) + if (!pgp_read_mpi(&blob, &mpi[i])) { return NULL; } @@ -208,12 +79,12 @@ static private_key_t *parse_rsa_private_key(chunk_t blob) for (i = 0; i < 2; i++) { - if (!read_mpi(&blob, &mpi[i])) + if (!pgp_read_mpi(&blob, &mpi[i])) { return NULL; } } - if (!read_scalar(&blob, 1, &s2k)) + if (!pgp_read_scalar(&blob, 1, &s2k)) { return NULL; } @@ -230,7 +101,7 @@ static private_key_t *parse_rsa_private_key(chunk_t blob) for (i = 2; i < 6; i++) { - if (!read_mpi(&blob, &mpi[i])) + if (!pgp_read_mpi(&blob, &mpi[i])) { return NULL; } @@ -270,56 +141,37 @@ static bool decrypt_not_allowed(private_key_t *this, static private_key_t *parse_private_key(chunk_t blob) { chunk_t packet; - u_char tag, type; - u_int32_t len, version, created, days, alg; + pgp_packet_tag_t tag; + u_int32_t version, created, days, alg; private_key_t *key; - tag = blob.ptr[0]; - - /* bit 7 must be set */ - if (!(tag & 0x80)) - { - DBG1("invalid packet tag"); - return NULL; - } - /* bit 6 set defines new packet format */ - if (tag & 0x40) - { - DBG1("new PGP packet format not supported"); - return NULL; - } - - type = (tag & 0x3C) >> 2; - if (!old_packet_length(&blob, &len) || len > blob.len) + if (!pgp_read_packet(&blob, &packet, &tag)) { - DBG1("invalid packet length"); return NULL; } - packet.len = len; - packet.ptr = blob.ptr; - blob = chunk_skip(blob, len); - - if (!read_scalar(&packet, 1, &version)) + if (!pgp_read_scalar(&packet, 1, &version)) { - return NULL; + return FALSE; } - if (version < 3 || version > 4) + switch (version) { - DBG1("OpenPGP packet version V%d not supported", version); - return NULL; + case 3: + if (!pgp_read_scalar(&packet, 2, &days)) + { + return NULL; + } + break; + case 4: + break; + default: + DBG1("PGP packet version V%d not supported", version); + return FALSE; } - if (!read_scalar(&packet, 4, &created)) + if (!pgp_read_scalar(&packet, 4, &created)) { return NULL; } - if (version == 3) - { - if (!read_scalar(&packet, 2, &days)) - { - return NULL; - } - } - if (!read_scalar(&packet, 1, &alg)) + if (!pgp_read_scalar(&packet, 1, &alg)) { return NULL; } diff --git a/src/libstrongswan/plugins/pgp/pgp_utils.c b/src/libstrongswan/plugins/pgp/pgp_utils.c new file mode 100644 index 000000000..b55896f74 --- /dev/null +++ b/src/libstrongswan/plugins/pgp/pgp_utils.c @@ -0,0 +1,178 @@ +/* + * 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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_utils.h" + +#include <debug.h> + +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" +); + +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); + +/** + * Read a PGP scalar of bytes length, advance blob + */ +bool pgp_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 + */ +bool pgp_read_mpi(chunk_t *blob, chunk_t *mpi) +{ + u_int32_t bits, bytes; + + if (!pgp_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 read %d byte MPI", bytes); + return FALSE; + } + *mpi = chunk_create(blob->ptr, bytes); + *blob = chunk_skip(*blob, bytes); + return TRUE; +} + +/** + * Read length of an PGP old packet length encoding + */ +static bool pgp_old_packet_length(chunk_t *blob, u_int32_t *length) +{ + /* bits 0 and 1 define the packet length type */ + u_char type; + + if (!blob->len) + { + return FALSE; + } + type = 0x03 & blob->ptr[0]; + *blob = chunk_skip(*blob, 1); + + if (type > 2) + { + return FALSE; + } + return pgp_read_scalar(blob, type == 0 ? 1 : type * 2, length); +} + +/** + * See header. + */ +bool pgp_read_packet(chunk_t *blob, chunk_t *data, pgp_packet_tag_t *tag) +{ + u_int32_t len; + u_char t; + + if (!blob->len) + { + DBG1("missing input"); + return FALSE; + } + t = blob->ptr[0]; + + /* bit 7 must be set */ + if (!(t & 0x80)) + { + DBG1("invalid packet tag"); + return FALSE; + } + /* bit 6 set defines new packet format */ + if (t & 0x40) + { + DBG1("new PGP packet format not supported"); + return FALSE; + } + + t = (t & 0x3C) >> 2; + if (!pgp_old_packet_length(blob, &len) || len > blob->len) + { + DBG1("invalid packet length"); + return FALSE; + } + *data = chunk_create(blob->ptr, len); + *blob = chunk_skip(*blob, len); + *tag = t; + return TRUE; +} + diff --git a/src/libstrongswan/plugins/pgp/pgp_utils.h b/src/libstrongswan/plugins/pgp/pgp_utils.h new file mode 100644 index 000000000..93c51c44b --- /dev/null +++ b/src/libstrongswan/plugins/pgp/pgp_utils.h @@ -0,0 +1,130 @@ +/* + * 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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_utils pgp_utils + * @{ @ingroup pgp + */ + +#ifndef PGP_UTILS_H_ +#define PGP_UTILS_H_ + +#include <library.h> + +typedef enum pgp_pubkey_alg_t pgp_pubkey_alg_t; +typedef enum pgp_sym_alg_t pgp_sym_alg_t; +typedef enum pgp_packet_tag_t pgp_packet_tag_t; + +/** + * 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 of 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 of pgp_sym_alg_t + */ +extern enum_name_t *pgp_sym_alg_names; + +/** + * 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 of pgp_packet_tag_t + */ +extern enum_name_t *pgp_packet_tag_names; + +/** + * Parse a PGP encoded MPI. + * + * @param blob blob to read from, gets advanced + * @param mpi parsed MPI value + * @return TRUE if MPI parsed successfully + */ +bool pgp_read_mpi(chunk_t *blob, chunk_t *mpi); + +/** + * Parse a PGP encoded Scalar. + * + * @param blob blob to read from, gets advanced + * @param bytes number of bytes the scalar uses for encoding + * @param scalar resultin scalar + * @return TRUE if scalar parsed successfully + */ +bool pgp_read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar); + +/** + * Parse a PGP packet. + * + * @param blob blob to read from, gets advanced + * @param data contained packet data + * @param tag tag of the parsed PGP packet + * @return TRUE if packet parsed successfully + */ +bool pgp_read_packet(chunk_t *blob, chunk_t *data, pgp_packet_tag_t *tag); + +#endif /* PGP_UTILS_ @}*/ |