From d6e340397d17d08d5f0ac39a65ab2fea46fe779b Mon Sep 17 00:00:00 2001
From: Magnus Holmgren <holmgren@debian.org>
Date: Mon, 12 Oct 2009 10:00:22 +0200
Subject: [PATCH] Support for DSA keys, contributed by Magnus Holmgren.

Rev: nettle/tools/pkcs1-conv.c:1.2
---
 tools/pkcs1-conv.c | 84 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 78 insertions(+), 6 deletions(-)

diff --git a/tools/pkcs1-conv.c b/tools/pkcs1-conv.c
index d402da07..34a77948 100644
--- a/tools/pkcs1-conv.c
+++ b/tools/pkcs1-conv.c
@@ -1,10 +1,10 @@
 /* pkcs1-conv.c
  *
- * Converting pkcs#1 keys to sexp format. */
+ * Converting pkcs#1 and similar keys to sexp format. */
 
 /* nettle, low-level cryptographics library
  *
- * Copyright (C) 2005 Niels Möller
+ * Copyright (C) 2005, 2009 Niels Möller, Magnus Holmgren
  *  
  * The nettle library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
@@ -35,6 +35,7 @@
 #include "base64.h"
 #include "buffer.h"
 #include "rsa.h"
+#include "dsa.h"
 
 #include "getopt.h"
 #include "misc.h"
@@ -43,6 +44,9 @@ enum object_type
   {
     RSA_PRIVATE_KEY = 0x200,
     RSA_PUBLIC_KEY,
+    DSA_PRIVATE_KEY,
+    /* DSA public keys only supported as part of a
+       SubjectPublicKeyInfo, i.e., the GENERAL_PUBLIC_KEY case. */
     GENERAL_PUBLIC_KEY,
   };
 
@@ -303,6 +307,34 @@ convert_rsa_private_key(struct nettle_buffer *buffer, unsigned length, const uin
   return res;
 }
 
+static int
+convert_dsa_private_key(struct nettle_buffer *buffer, unsigned length, const uint8_t *data)
+{
+  struct dsa_public_key pub;
+  struct dsa_private_key priv;
+  int res;
+  
+  dsa_public_key_init(&pub);
+  dsa_private_key_init(&priv);
+
+  if (dsa_keypair_from_der(&pub, &priv, 0,
+			   length, data))
+    {
+      /* Reuses the buffer */
+      nettle_buffer_reset(buffer);
+      res = dsa_keypair_to_sexp(buffer, NULL, &pub, &priv);
+    }
+  else
+    {
+      werror("Invalid OpenSSL private key.\n");
+      res = 0;
+    }
+  dsa_public_key_clear(&pub);
+  dsa_private_key_clear(&priv);
+
+  return res;
+}
+
 /* Returns 1 on success, 0 on error, and -1 for unsupported algorithms. */
 static int
 convert_public_key(struct nettle_buffer *buffer, unsigned length, const uint8_t *data)
@@ -332,9 +364,8 @@ convert_public_key(struct nettle_buffer *buffer, unsigned length, const uint8_t
       && asn1_der_iterator_next(&i) == ASN1_ITERATOR_PRIMITIVE
       && i.type == ASN1_BITSTRING
 
-      /* Use i to parse the object wrapped in the bit string. For all
-	 currently supported key types, it is a sequence. */
-      && asn1_der_decode_bitstring_last(&i) == ASN1_ITERATOR_CONSTRUCTED)
+      /* Use i to parse the object wrapped in the bit string.*/
+      && asn1_der_decode_bitstring_last(&i))
     {
       /* pkcs-1 {
 	     iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)
@@ -349,7 +380,16 @@ convert_public_key(struct nettle_buffer *buffer, unsigned length, const uint8_t
       */
       static const uint8_t id_rsaEncryption[9] =
 	{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
-      
+      /*
+	 --
+	 -- When dsa is used in an AlgorithmIdentifier the
+	 -- parameters MUST be present and MUST NOT be NULL.
+	 --
+	 dsa    OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) 1 }
+      */
+      static const uint8_t id_dsa[7] =
+	{ 0x2A, 0x86, 0x48, 0xCE, 0x38, 0x04, 0x01 };
+
       switch (j.length)
 	{
 	unknown:
@@ -358,6 +398,27 @@ convert_public_key(struct nettle_buffer *buffer, unsigned length, const uint8_t
 	  res = -1;
 	  break;
 	  
+	case 7:
+	  if (memcmp(j.data, id_dsa, 7) == 0)
+	    {
+	      if (asn1_der_iterator_next(&j) == ASN1_ITERATOR_CONSTRUCTED
+		  && asn1_der_decode_constructed_last(&j) == ASN1_ITERATOR_PRIMITIVE)
+		{
+		  struct dsa_public_key pub;
+
+		  dsa_public_key_init(&pub);
+
+		  if (dsa_public_key_from_der_iterators(&pub, 0, &i, &j))
+		    {
+		      nettle_buffer_reset(buffer);
+		      res = dsa_keypair_to_sexp(buffer, NULL, &pub, NULL) > 0;
+		    }
+		}
+	      if (!res)
+		werror("SubjectPublicKeyInfo: Invalid DSA key.\n");
+	      break;
+	    }
+	  else goto unknown;
 	case 9:
 	  if (memcmp(j.data, id_rsaEncryption, 9) == 0)
 	    {
@@ -414,6 +475,10 @@ convert_type(struct nettle_buffer *buffer,
     case RSA_PRIVATE_KEY:
       res = convert_rsa_private_key(buffer, length, data);
       break;
+
+    case DSA_PRIVATE_KEY:
+      res = convert_dsa_private_key(buffer, length, data);
+      break;
     }
 
   if (res > 0)
@@ -487,6 +552,11 @@ convert_file(struct nettle_buffer *buffer,
 		  type = RSA_PRIVATE_KEY;
 		  break;
 		}
+	      if (memcmp(marker, "DSA PRIVATE KEY", 15) == 0)
+		{
+		  type = DSA_PRIVATE_KEY;
+		  break;
+		}
 	    }
 	  
 	  if (!type)
@@ -516,6 +586,7 @@ main(int argc, char **argv)
       { "version", no_argument, NULL, 'V' },
       { "private-rsa-key", no_argument, NULL, RSA_PRIVATE_KEY },
       { "public-rsa-key", no_argument, NULL, RSA_PUBLIC_KEY },
+      { "private-dsa-key", no_argument, NULL, DSA_PRIVATE_KEY },
       { "public-key-info", no_argument, NULL, GENERAL_PUBLIC_KEY },
       { "base-64", no_argument, NULL, 'b' },
       { NULL, 0, NULL, 0 }
@@ -534,6 +605,7 @@ main(int argc, char **argv)
 
 	case RSA_PRIVATE_KEY:
 	case RSA_PUBLIC_KEY:
+	case DSA_PRIVATE_KEY:
 	case GENERAL_PUBLIC_KEY:
 	  type = c;
 	  break;
-- 
GitLab