]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
implemented PGP Secret-Key Packet parsing
authorMartin Willi <martin@strongswan.org>
Fri, 28 Aug 2009 15:23:58 +0000 (17:23 +0200)
committerMartin Willi <martin@strongswan.org>
Fri, 28 Aug 2009 15:23:58 +0000 (17:23 +0200)
src/libstrongswan/plugins/pgp/pgp_builder.c
src/libstrongswan/plugins/pgp/pgp_builder.h
src/libstrongswan/plugins/pgp/pgp_plugin.c

index 5e500396ad24c322889d7fa4650adb0d62e7dff7..37dd1518baf01a5cbc8722ace46fcf95458235c6 100644 (file)
@@ -105,6 +105,28 @@ static bool read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar)
        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
  */
@@ -120,7 +142,7 @@ static bool read_mpi(chunk_t *blob, chunk_t *mpi)
        bytes = (bits + 7) / 8;
        if (bytes > blob->len)
        {
-               DBG1("PGP data too short to %d byte MPI", bytes);
+               DBG1("PGP data too short to read %d byte MPI", bytes);
                return FALSE;
        }
        *mpi = chunk_create(blob->ptr, bytes);
@@ -213,6 +235,7 @@ static private_key_t *parse_rsa_private_key(chunk_t blob)
                        return NULL;
                }
        }
+       
        /* PGP has uses p < q, but we use p > q */
        return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, 
                                                BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1],
@@ -221,6 +244,120 @@ static private_key_t *parse_rsa_private_key(chunk_t blob)
                                                BUILD_END);
 }
 
+/**
+ * Implementation of private_key_t.sign for encryption-only keys
+ */
+static bool sign_not_allowed(private_key_t *this, signature_scheme_t scheme,
+                                                        chunk_t data, chunk_t *signature)
+{
+       DBG1("signing failed - decryption only key");
+       return FALSE;
+}
+
+/**
+ * Implementation of private_key_t.decrypt for signature-only keys
+ */
+static bool decrypt_not_allowed(private_key_t *this,
+                                                               chunk_t crypto, chunk_t *plain)
+{
+       DBG1("decryption failed - signature only key");
+       return FALSE;
+}
+
+/**
+ * Load a generic private key from a PGP packet
+ */
+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;
+       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)
+       {
+               DBG1("invalid packet length");
+               return NULL;
+       }
+       packet.len = len;
+       packet.ptr = blob.ptr;
+       blob = chunk_skip(blob, len);
+       
+       if (!read_scalar(&packet, 1, &version))
+       {
+               return NULL;
+       }
+       if (version < 3 || version > 4)
+       {
+               DBG1("OpenPGP packet version V%d not supported", version);
+               return NULL;
+       }
+       if (!read_scalar(&packet, 4, &created))
+       {
+               return NULL;
+       }
+       if (version == 3)
+       {
+               if (!read_scalar(&packet, 2, &days))
+               {
+                       return NULL;
+               }
+       }
+       if (!read_scalar(&packet, 1, &alg))
+       {
+               return NULL;
+       }
+       switch (alg)
+       {
+               case PGP_PUBKEY_ALG_RSA:
+                       POS;
+                       return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+                                                                         BUILD_BLOB_PGP, packet, BUILD_END);
+               case PGP_PUBKEY_ALG_RSA_ENC_ONLY:
+                       key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+                                                                         BUILD_BLOB_PGP, packet, BUILD_END);
+                       if (key)
+                       {
+                               key->sign = sign_not_allowed;
+                       }
+                       return key;
+               case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
+                       key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+                                                                         BUILD_BLOB_PGP, packet, BUILD_END);
+                       if (key)
+                       {
+                               key->decrypt = decrypt_not_allowed;
+                       }
+                       return key;
+               case PGP_PUBKEY_ALG_ECDSA:
+                       return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA,
+                                                                         BUILD_BLOB_PGP, packet, BUILD_END);
+               case PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY:
+               case PGP_PUBKEY_ALG_DSA:
+               case PGP_PUBKEY_ALG_ECC:
+               case PGP_PUBKEY_ALG_ELGAMAL:
+               case PGP_PUBKEY_ALG_DIFFIE_HELLMAN:
+               default:
+                       return NULL;
+       }
+}
+
 typedef struct private_builder_t private_builder_t;
 
 /**
@@ -266,7 +403,7 @@ static void add_public(private_builder_t *this, builder_part_t part, ...)
        
        switch (part)
        {
-               case BUILD_BLOB_PEM:
+               case BUILD_BLOB_PGP:
                {
                        va_start(args, part);
                        this->blob = va_arg(args, chunk_t);
@@ -306,9 +443,19 @@ builder_t *pgp_public_key_builder(key_type_t type)
  */
 static private_key_t *build_private(private_builder_t *this)
 {
-       private_key_t *key;
+       private_key_t *key = NULL;
        
-       key = parse_rsa_private_key(this->blob);
+       switch (this->type)
+       {
+               case KEY_ANY:
+                       key = parse_private_key(this->blob);
+                       break;
+               case KEY_RSA:
+                       key = parse_rsa_private_key(this->blob);
+                       break;
+               default:
+                       break;
+       }
        free(this);
        return key;
 }
@@ -342,7 +489,7 @@ builder_t *pgp_private_key_builder(key_type_t type)
 {
        private_builder_t *this;
        
-       if (type != KEY_RSA)
+       if (type != KEY_ANY && type != KEY_RSA)
        {
                return NULL;
        }
index 739456e03151242763be9770f1f8d8051d901067..4968d7caaf919623141f4604f4a48450b2ff152f 100644 (file)
@@ -32,9 +32,9 @@
 builder_t *pgp_public_key_builder(key_type_t type);
 
 /**
- * Create the builder for a RSA private key using PGP decoding.
+ * Create the builder for a generic or RSA private key using PGP decoding.
  *
- * @param type         type of the key, KEY_RSA
+ * @param type         type of the key, either KEY_ANY or KEY_RSA
  * @return                     builder instance
  */
 builder_t *pgp_private_key_builder(key_type_t type);
index d31666b5923f696fd5bafacb2b3beec8f1bc52a4..98f5c3356710ff3d1089032be574efca1208c44c 100644 (file)
@@ -60,6 +60,8 @@ plugin_t *plugin_create()
                                                        (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_ANY,
+                                                       (builder_constructor_t)pgp_private_key_builder);
        lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
                                                        (builder_constructor_t)pgp_private_key_builder);