Encode RSA public keys in RFC 3110 DNSKEY format
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 17 Feb 2013 16:37:45 +0000 (17:37 +0100)
committerTobias Brunner <tobias@strongswan.org>
Tue, 19 Feb 2013 11:25:00 +0000 (12:25 +0100)
src/libstrongswan/credentials/cred_encoding.h
src/libstrongswan/plugins/dnskey/Makefile.am
src/libstrongswan/plugins/dnskey/dnskey_builder.c
src/libstrongswan/plugins/dnskey/dnskey_encoder.c [new file with mode: 0644]
src/libstrongswan/plugins/dnskey/dnskey_encoder.h [new file with mode: 0644]
src/libstrongswan/plugins/dnskey/dnskey_plugin.c
src/pki/commands/pub.c
src/pki/pki.c

index b029fe2..41481f3 100644 (file)
@@ -85,6 +85,8 @@ enum cred_encoding_type_t {
        /** PGP key encoding */
        PUBKEY_PGP,
        PRIVKEY_PGP,
+       /** DNSKEY encoding */
+       PUBKEY_DNSKEY,
 
        /** ASN.1 DER encoded certificate */
        CERT_ASN1_DER,
index fbba95e..0f2e554 100644 (file)
@@ -11,6 +11,7 @@ endif
 
 libstrongswan_dnskey_la_SOURCES = \
        dnskey_plugin.h dnskey_plugin.c \
-       dnskey_builder.h dnskey_builder.c
+       dnskey_builder.h dnskey_builder.c \
+       dnskey_encoder.h dnskey_encoder.c
 
 libstrongswan_dnskey_la_LDFLAGS = -module -avoid-version
index b8a4515..7104043 100644 (file)
@@ -39,8 +39,14 @@ enum dnskey_algorithm_t {
        DNSKEY_ALG_RSA_MD5 = 1,
        DNSKEY_ALG_DH = 2,
        DNSKEY_ALG_DSA = 3,
-       DNSKEY_ALG_ECC = 4,
        DNSKEY_ALG_RSA_SHA1 = 5,
+       DNSKEY_ALG_DSA_NSEC3_SHA1 = 6,
+       DNSKEY_ALG_RSA_SHA1_NSEC3_SHA1 = 7,
+       DNSKEY_ALG_RSA_SHA256 = 8,
+       DNSKEY_ALG_RSA_SHA512 = 10,
+       DNSKEY_ALG_ECC_GOST = 12,
+       DNSKEY_ALG_ECDSA_P256_SHA256 = 13,
+       DNSKEY_ALG_ECDSA_P384_SHA384 = 14
 };
 
 /**
@@ -59,7 +65,11 @@ static dnskey_public_key_t *parse_public_key(chunk_t blob)
 
        switch (rr->algorithm)
        {
+               case DNSKEY_ALG_RSA_MD5:
                case DNSKEY_ALG_RSA_SHA1:
+               case DNSKEY_ALG_RSA_SHA1_NSEC3_SHA1:
+               case DNSKEY_ALG_RSA_SHA256:
+               case DNSKEY_ALG_RSA_SHA512:
                        return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
                                                                          BUILD_BLOB_DNSKEY, blob, BUILD_END);
                default:
diff --git a/src/libstrongswan/plugins/dnskey/dnskey_encoder.c b/src/libstrongswan/plugins/dnskey/dnskey_encoder.c
new file mode 100644 (file)
index 0000000..d2b9894
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2013 Andreas Steffen
+ * HSR 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 "dnskey_encoder.h"
+
+#include <utils/debug.h>
+
+/**
+ * Encode an RSA public key in DNSKEY format (RFC 3110)
+ */
+bool build_pub(chunk_t *encoding, va_list args)
+{
+       chunk_t n, e, pubkey;
+       size_t exp_len;
+       u_char *pos;
+
+       if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n,
+                                                  CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END))
+       {
+               /* remove leading zeros in exponent and modulus */
+               while (*e.ptr == 0)
+               {
+                       e = chunk_skip(e, 1);
+               }
+               while (*n.ptr == 0)
+               {
+                       n = chunk_skip(n, 1);
+               }
+
+               if (e.len < 256)
+               {
+                       /* exponent length fits into a single octet */
+                       exp_len = 1;
+                       pubkey = chunk_alloc(exp_len + e.len + n.len);
+                       pubkey.ptr[0] = (char)e.len;
+               }
+               else if (e.len < 65536)
+               {
+                       /* exponent length fits into two octets preceded by zero octet */
+                       exp_len = 3;
+                       pubkey = chunk_alloc(exp_len + e.len + n.len);
+                       pubkey.ptr[0] = 0x00;
+                       htoun16(pubkey.ptr + 1, e.len);
+               }                       
+               else
+               {
+                       /* exponent length is too large */
+                       return FALSE;
+               }
+
+               /* copy exponent and modulus and convert to base64 format */
+               pos = pubkey.ptr + exp_len;
+               memcpy(pos, e.ptr, e.len);
+               pos += e.len;
+               memcpy(pos, n.ptr, n.len);
+               *encoding = chunk_to_base64(pubkey, NULL);
+               chunk_free(&pubkey);
+
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * See header.
+ */
+bool dnskey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding,
+                                                  va_list args)
+{
+       switch (type)
+       {
+               case PUBKEY_DNSKEY:
+                       return build_pub(encoding, args);
+               default:
+                       return FALSE;
+       }
+}
+
+
diff --git a/src/libstrongswan/plugins/dnskey/dnskey_encoder.h b/src/libstrongswan/plugins/dnskey/dnskey_encoder.h
new file mode 100644 (file)
index 0000000..698d293
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 Andreas Steffen
+ * HSR 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 dnskey_encoder dnskey_encoder
+ * @{ @ingroup dnskey
+ */
+
+#ifndef DNSKEY_ENCODER_H_
+#define DNSKEY_ENCODER_H_
+
+#include <credentials/cred_encoding.h>
+
+/**
+ * Encoding function for DNSKEY (RFC 3110) public key format.
+ */
+bool dnskey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding,
+                                                 va_list args);
+
+#endif /** DNSKEY_ENCODER_H_ @}*/
index b6863e8..9a4f625 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <library.h>
 #include "dnskey_builder.h"
+#include "dnskey_encoder.h"
 
 typedef struct private_dnskey_plugin_t private_dnskey_plugin_t;
 
@@ -53,6 +54,8 @@ METHOD(plugin_t, get_features, int,
 METHOD(plugin_t, destroy, void,
        private_dnskey_plugin_t *this)
 {
+       lib->encoding->remove_encoder(lib->encoding, dnskey_encoder_encode);
+
        free(this);
 }
 
@@ -73,6 +76,8 @@ plugin_t *dnskey_plugin_create()
                },
        );
 
+       lib->encoding->add_encoder(lib->encoding, dnskey_encoder_encode);
+
        return &this->public.plugin;
 }
 
index 30078a8..9912061 100644 (file)
@@ -158,7 +158,7 @@ static void __attribute__ ((constructor))reg()
                pub, 'p', "pub",
                "extract the public key from a private key/certificate",
                {"[--in file|--keyid hex] [--type rsa|ecdsa|pkcs10|x509]",
-                "[--outform der|pem|pgp]"},
+                "[--outform der|pem|pgp|dnskey]"},
                {
                        {"help",        'h', 0, "show usage information"},
                        {"in",          'i', 1, "input file, default: stdin"},
index 3f77c5e..429517b 100644 (file)
@@ -76,6 +76,17 @@ bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type)
                                return FALSE;
                }
        }
+       else if (streq(form, "dnskey"))
+       {
+               switch (type)
+               {
+                       case CRED_PUBLIC_KEY:
+                               *enc =PUBKEY_DNSKEY;
+                               return TRUE;
+                       default:
+                               return FALSE;
+               }
+       }
        return FALSE;
 }