Moved generic PGP parsing functions to pgp_utils.[ch]
authorMartin Willi <martin@strongswan.org>
Mon, 14 Sep 2009 14:06:19 +0000 (16:06 +0200)
committerMartin Willi <martin@strongswan.org>
Tue, 15 Sep 2009 06:23:47 +0000 (08:23 +0200)
src/libstrongswan/plugins/pgp/Makefile.am
src/libstrongswan/plugins/pgp/pgp_builder.c
src/libstrongswan/plugins/pgp/pgp_utils.c [new file with mode: 0644]
src/libstrongswan/plugins/pgp/pgp_utils.h [new file with mode: 0644]

index 3eb3992..6cbc09e 100644 (file)
@@ -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
 
index 5147237..d262d18 100644 (file)
  */
 
 #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 (file)
index 0000000..b55896f
--- /dev/null
@@ -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 (file)
index 0000000..93c51c4
--- /dev/null
@@ -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_ @}*/