Attached is a patch to allow creation of the SubjectAltName Extension using X509CertificateBuilder. There are some unit tests and I confirmed using openssl, System.Security.Cryptography.X509Certificates, and Mono.Security.X509 to read the certificates.

I also went ahead and fixed the IP Address code and again confirmed it worked with openssl. Please let me know if there needs to be more unit tests, I would like to believe that I didn't really add anything substantial that needed more thorough testing than what I did.

Are there any code freezes in Mono? Or will this appear in the next released version (assuming you're happy with the patch?).

Regards,
David

Sebastien Pouliot wrote:
Hello David,

On Thu, 2008-06-12 at 14:26 -0400, David Wolinsky wrote:
Is anyone working on X509CertificateBuilder.

AFAIK no one. The actual class does everything that mono itself requires
(mostly implementing the makecert tool).

I am putting together a little work to add a single URI to SubjectAltName and add the extension to the CertificateBuilder. It appears to work in both .Net and Mono. They were able to properly read the certificate and Identify the SubjectAltName. If someone is working on this, how much more robust would you want this before you would take it in as a patch?

Mono.Security is stable so any change must be forward compatible (e.g.
adding new stuff is possible but changing existing API is unlikely to be
possible).

Also any new features should come with unit tests to make sure any
future change won't break them.

Other than this it's as simple as posting your patch for review on this
list (as long as you're willing the code to be available under the MIT
X11 license).

Thanks!
Sebastien




diff -urpN mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security_test.dll.sources mono-1.9.1/mcs/class/Mono.Security/Mono.Security_test.dll.sources
--- mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security_test.dll.sources	2007-11-08 17:34:20.000000000 -0500
+++ mono-1.9.1/mcs/class/Mono.Security/Mono.Security_test.dll.sources	2008-06-13 01:58:07.000000000 -0400
@@ -40,3 +40,4 @@ Mono.Security.X509/X520AttributesTest.cs
 Mono.Security.X509.Extensions/KeyUsageExtensionTest.cs
 Mono.Security.X509.Extensions/ExtendedKeyUsageExtensionTest.cs
 Mono.Security.X509.Extensions/BasicConstraintsExtensionTest.cs
+Mono.Security.X509.Extensions/SubjectAltNameTest.cs
diff -urpN mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog
--- mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog	2007-11-08 17:34:18.000000000 -0500
+++ mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog	2008-06-13 02:02:37.000000000 -0400
@@ -1,3 +1,8 @@
+2008-06-13  David Wolinsky  <[EMAIL PROTECTED]>
+
+  * X509CertificateBuilder.cs: Extensions is now writable so that it
+	can be added unto during run time.
+
 2007-05-09  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
 	* PKCS12.cs: Adds SecretBag support. Patch by Jay Miller.
diff -urpN mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509.Extensions/ChangeLog mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509.Extensions/ChangeLog
--- mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509.Extensions/ChangeLog	2008-01-29 17:05:09.000000000 -0500
+++ mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509.Extensions/ChangeLog	2008-06-13 02:01:27.000000000 -0400
@@ -1,3 +1,9 @@
+2008-06-13  David Wolinsky  <[EMAIL PROTECTED]>
+  * SubjectAltName.cs: IP Addresses are handled and now this class
+	can be generated via the constructor from arrays.
+	* GeneralNames.cs: Added support to generate GeneralNames from
+	an arrays of strings.
+
 2007-12-14  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
 	* AuthorityKeyIdentifierExtension.cs: Don't throw on what we don't
diff -urpN mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509.Extensions/GeneralNames.cs mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509.Extensions/GeneralNames.cs
--- mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509.Extensions/GeneralNames.cs	2007-11-08 17:34:17.000000000 -0500
+++ mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509.Extensions/GeneralNames.cs	2008-06-13 01:58:52.000000000 -0400
@@ -72,11 +72,52 @@ namespace Mono.Security.X509.Extensions 
 		private ArrayList directoryNames;
 		private ArrayList uris;
 		private ArrayList ipAddr;
+    private ASN1 asn;
+
 
 		public GeneralNames ()
 		{
 		}
 
+    public GeneralNames(ArrayList rfc822s, ArrayList dnsNames, ArrayList ipAddresses, ArrayList uris)
+    {
+      // This is an extension
+      asn = new ASN1 ( 0x30);
+
+      if(rfc822s != null) {
+        foreach(string rfc822 in rfc822s) {
+          asn.Add( new ASN1 (0x81, Encoding.ASCII.GetBytes (rfc822)));
+        }
+        rfc822Name = rfc822s;
+      }
+
+      if(dnsNames != null) {
+        foreach(string dnsname in dnsNames) {
+          asn.Add( new ASN1 (0x82, Encoding.ASCII.GetBytes (dnsname)));
+        }
+        dnsName = dnsNames;
+      }
+
+      if(ipAddresses != null) {
+        foreach(string ipaddress in ipAddresses) {
+          string[] parts = ipaddress.Split('.', ':');
+          byte[] bytes = new byte[parts.Length];
+          for(int i = 0; i < parts.Length; i++) {
+            bytes[i] = Byte.Parse(parts[i]);
+          }
+          asn.Add( new ASN1 (0x87, bytes));
+        }
+        ipAddr = ipAddresses;
+      }
+
+      if(uris != null) {
+        foreach(string uri in uris) {
+          asn.Add( new ASN1 (0x86, Encoding.ASCII.GetBytes (uri)));
+        }
+        this.uris = uris;
+      }
+    }
+
 		public GeneralNames (ASN1 sequence)
 		{
 			for (int i = 0; i < sequence.Count; i++) {
@@ -103,9 +144,16 @@ namespace Mono.Security.X509.Extensions 
 					uris.Add (Encoding.ASCII.GetString (sequence[i].Value));
 					break;
 				case 0x87: // iPAddress				[7]     OCTET STRING
+        // Todo this is not correct!
 					if (ipAddr == null)
 						ipAddr = new ArrayList ();
-					// TODO - Must find sample certificates
+          byte[] bytes = sequence[i].Value;
+          string space = (bytes.Length == 4) ? "." : ":";
+          string res = string.Empty;
+          for (int j = 0; j < bytes.Length; j++) {
+            res += bytes[j] + ((j < bytes.Length - 1) ? space : string.Empty); 
+          }
+          ipAddr.Add ( res);
 					break;
 				default:
 					break;
@@ -145,7 +193,6 @@ namespace Mono.Security.X509.Extensions 
 			}
 		}
 
-		// Incomplete support
 		public string[] IPAddresses {
 			get {
 				if (ipAddr == null)
@@ -154,6 +201,11 @@ namespace Mono.Security.X509.Extensions 
 			}
 		}
 
+    public byte[] GetBytes()
+    {
+      return asn.GetBytes();
+    }
+
 		public override string ToString ()
 		{
 			StringBuilder sb = new StringBuilder ();
diff -urpN mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509.Extensions/SubjectAltNameExtension.cs mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509.Extensions/SubjectAltNameExtension.cs
--- mono-1.9.1-old/mcs/class/Mono.Security/Mono.Security.X509.Extensions/SubjectAltNameExtension.cs	2007-11-08 17:34:17.000000000 -0500
+++ mono-1.9.1/mcs/class/Mono.Security/Mono.Security.X509.Extensions/SubjectAltNameExtension.cs	2008-06-13 01:58:52.000000000 -0400
@@ -69,7 +69,6 @@ namespace Mono.Security.X509.Extensions 
 
 	// TODO - incomplete (only rfc822Name, dNSName are supported)
 	public class SubjectAltNameExtension : X509Extension {
-		
 		private GeneralNames _names;
 
 		public SubjectAltNameExtension ()
@@ -88,6 +87,16 @@ namespace Mono.Security.X509.Extensions 
 		{
 		}
 
+    public SubjectAltNameExtension (ArrayList rfc822, ArrayList dnsNames,
+        ArrayList ipAddresses, ArrayList uris)
+    {
+      _names = new GeneralNames(rfc822, dnsNames, ipAddresses, uris);
+      // 0x04 for string decoding and then the General Names!
+      extnValue = new ASN1( 0x04, _names.GetBytes());
+			extnOid = "2.5.29.17";
+		//  extnCritical = true;
+    }
+
 		protected override void Decode () 
 		{
 			ASN1 sequence = new ASN1 (extnValue.Value);
@@ -113,6 +122,10 @@ namespace Mono.Security.X509.Extensions 
 			get { return _names.IPAddresses; }
 		}
 
+		public string[] UniformResourceIdentifiers {
+			get { return _names.UniformResourceIdentifiers; }
+		}
+
 		public override string ToString () 
 		{
 			return _names.ToString ();
diff -urpN mono-1.9.1-old/mcs/class/Mono.Security/Test/Mono.Security.X509.Extensions/SubjectAltNameTest.cs mono-1.9.1/mcs/class/Mono.Security/Test/Mono.Security.X509.Extensions/SubjectAltNameTest.cs
--- mono-1.9.1-old/mcs/class/Mono.Security/Test/Mono.Security.X509.Extensions/SubjectAltNameTest.cs	1969-12-31 19:00:00.000000000 -0500
+++ mono-1.9.1/mcs/class/Mono.Security/Test/Mono.Security.X509.Extensions/SubjectAltNameTest.cs	2008-06-13 01:58:31.000000000 -0400
@@ -0,0 +1,66 @@
+//
+//  SubjectAltNameTest.cs - NUnit Test Cases for 
+//	Mono.Security.X509.Extensions.SubjectAltName
+//
+// Authors:
+//  David Wolinsky <[EMAIL PROTECTED]>
+//
+// Copyright (C) 2008 
+//
+
+using System;
+using System.Collections;
+using System.Security.Cryptography;
+using System.IO;
+
+using Mono.Security;
+using Mono.Security.X509;
+using Mono.Security.X509.Extensions;
+
+using NUnit.Framework;
+
+namespace MonoTests.Mono.Security.X509.Extensions {
+
+	[TestFixture]
+	public class SubjectAltNameTest {
+
+    [Test]
+    public void SubjectAltNameGenerator ()
+    {
+      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
+      X509CertificateBuilder x509 = new X509CertificateBuilder();
+      x509.IssuerName = "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server";
+      x509.NotAfter = DateTime.MaxValue;
+      x509.NotBefore = DateTime.MinValue;
+      x509.SubjectName = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org";
+      x509.SerialNumber = new byte[]{12, 34, 56, 78, 90};
+      x509.Version = 3;
+      x509.SubjectPublicKey = rsa;
+
+      ArrayList dns = new ArrayList();
+      dns.Add("one");
+      dns.Add("two");
+      ArrayList uris = new ArrayList();
+      uris.Add("one:two://three");
+      uris.Add("Here:I:AM://12345");
+      uris.Add("last:one");
+      SubjectAltNameExtension sane = new SubjectAltNameExtension(new ArrayList(0), dns, new ArrayList(0), uris);
+      x509.Extensions = new X509ExtensionCollection();
+      x509.Extensions.Add(sane);
+      byte[] data = x509.Sign(rsa);
+
+      X509Certificate x509_loaded = new X509Certificate(data);
+      SubjectAltNameExtension sane_test = null;
+      try {
+        sane_test = new SubjectAltNameExtension(x509_loaded.Extensions[0]);
+      } catch { }
+      Assert.IsTrue(sane_test != null, "Unable to get SubjectAltNameExtension from Extensions!");
+      Assert.AreEqual(sane_test.RFC822.Length, 0, "RFC822 count");
+      Assert.AreEqual(sane_test.DNSNames.Length, 2, "DNSName count");
+      Assert.AreEqual(sane_test.IPAddresses.Length, 0, "IPAddresses count");
+      Assert.AreEqual(sane_test.UniformResourceIdentifiers.Length, 3, "URI Count");
+      Assert.AreEqual(sane_test.DNSNames[1], "two", "DNSName test");
+      Assert.AreEqual(sane_test.UniformResourceIdentifiers[2], "last:one", "URI Test");
+    }
+  }
+}
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to