2006-12-05 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / Mono.Security / Mono.Security.X509 / X509Certificate.cs
index d351bd06c1c8941169d0b6371d878d8f2b7571be..ac9d5cfefc513e4b6ac31928e0eab50ebe76780f 100644 (file)
@@ -93,28 +93,24 @@ namespace Mono.Security.X509 {
                private int version;
                private byte[] serialnumber;
 
-//             private byte[] issuerUniqueID;
-//             private byte[] subjectUniqueID;
+               private byte[] issuerUniqueID;
+               private byte[] subjectUniqueID;
                private X509ExtensionCollection extensions;
 
-#if NET_2_0
-               private const bool reversed = true;
-#else
-               private const bool reversed = false;
-#endif
+               private static string encoding_error = Locale.GetText ("Input data cannot be coded as a valid certificate.");
+
 
                // that's were the real job is!
                private void Parse (byte[] data) 
                {
-                       string e = "Input data cannot be coded as a valid certificate.";
                        try {
                                decoder = new ASN1 (data);
                                // Certificate 
                                if (decoder.Tag != 0x30)
-                                       throw new CryptographicException (e);
+                                       throw new CryptographicException (encoding_error);
                                // Certificate / TBSCertificate
                                if (decoder [0].Tag != 0x30)
-                                       throw new CryptographicException (e);
+                                       throw new CryptographicException (encoding_error);
 
                                ASN1 tbsCertificate = decoder [0];
 
@@ -131,7 +127,7 @@ namespace Mono.Security.X509 {
                                // Certificate / TBSCertificate / CertificateSerialNumber
                                ASN1 sn = decoder [0][tbs++];
                                if (sn.Tag != 0x02) 
-                                       throw new CryptographicException (e);
+                                       throw new CryptographicException (encoding_error);
                                serialnumber = sn.Value;
                                Array.Reverse (serialnumber, 0, serialnumber.Length);
                
@@ -184,17 +180,17 @@ namespace Mono.Security.X509 {
                                        m_signaturealgoparams = null;
 
                                // Certificate / TBSCertificate / issuerUniqueID
-                               ASN1 issuerUID = tbsCertificate.Element (tbs, 0xA1);
+                               ASN1 issuerUID = tbsCertificate.Element (tbs, 0x81);
                                if (issuerUID != null) {
                                        tbs++;
-//                                     issuerUniqueID = issuerUID.Value;
+                                       issuerUniqueID = issuerUID.Value;
                                }
 
                                // Certificate / TBSCertificate / subjectUniqueID
-                               ASN1 subjectUID = tbsCertificate.Element (tbs, 0xA2);
+                               ASN1 subjectUID = tbsCertificate.Element (tbs, 0x82);
                                if (subjectUID != null) {
                                        tbs++;
-//                                     subjectUniqueID = subjectUID.Value;
+                                       subjectUniqueID = subjectUID.Value;
                                }
 
                                // Certificate / TBSCertificate / Extensions
@@ -208,7 +204,7 @@ namespace Mono.Security.X509 {
                                m_encodedcert = (byte[]) data.Clone ();
                        }
                        catch (Exception ex) {
-                               throw new CryptographicException (e, ex);
+                               throw new CryptographicException (encoding_error, ex);
                        }
                }
 
@@ -216,8 +212,18 @@ namespace Mono.Security.X509 {
 
                public X509Certificate (byte[] data) 
                {
-                       if (data != null)
+                       if (data != null) {
+                               // does it looks like PEM ?
+                               if ((data.Length > 0) && (data [0] == 0x2D)) {
+                                       try {
+                                               data = PEM ("CERTIFICATE", data);
+                                       }
+                                       catch (Exception ex) {
+                                               throw new CryptographicException (encoding_error, ex);
+                                       }
+                               }
                                Parse (data);
+                       }
                }
 
                private byte[] GetUnsignedBigInteger (byte[] integer) 
@@ -238,6 +244,9 @@ namespace Mono.Security.X509 {
 
                public DSA DSA {
                        get {
+                               if (m_keyalgoparams == null)
+                                       throw new CryptographicException ("Missing key algorithm parameters.");
+
                                if (_dsa == null) {
                                        DSAParameters dsaParams = new DSAParameters ();
                                        // for DSA m_publickey contains 1 ASN.1 integer - Y
@@ -323,6 +332,7 @@ namespace Mono.Security.X509 {
                                        return null;
                                return (byte[]) m_keyalgoparams.Clone (); 
                        }
+                       set { m_keyalgoparams = value; }
                }
 
                public virtual byte[] PublicKey {
@@ -400,12 +410,17 @@ namespace Mono.Security.X509 {
                                                ASN1 sign = new ASN1 (signature);
                                                if ((sign == null) || (sign.Count != 2))
                                                        return null;
-                                               // parts may be less than 20 bytes (i.e. first bytes were 0x00)
                                                byte[] part1 = sign [0].Value;
                                                byte[] part2 = sign [1].Value;
                                                byte[] sig = new byte [40];
-                                               Buffer.BlockCopy (part1, 0, sig, (20 - part1.Length), part1.Length);
-                                               Buffer.BlockCopy (part2, 0, sig, (40 - part2.Length), part2.Length);
+                                               // parts may be less than 20 bytes (i.e. first bytes were 0x00)
+                                               // parts may be more than 20 bytes (i.e. first byte > 0x80, negative)
+                                               int s1 = System.Math.Max (0, part1.Length - 20);
+                                               int e1 = System.Math.Max (0, 20 - part1.Length);
+                                               Buffer.BlockCopy (part1, s1, sig, e1, part1.Length - s1);
+                                               int s2 = System.Math.Max (0, part2.Length - 20);
+                                               int e2 = System.Math.Max (20, 40 - part2.Length);
+                                               Buffer.BlockCopy (part2, s2, sig, e2, part2.Length - s2);
                                                return sig;
 
                                        default:
@@ -451,6 +466,24 @@ namespace Mono.Security.X509 {
                        return ((instant > ValidFrom) && (instant <= ValidUntil));
                }
 
+               // uncommon v2 "extension"
+               public byte[] IssuerUniqueIdentifier {
+                       get {
+                               if (issuerUniqueID == null)
+                                       return null;
+                               return (byte[]) issuerUniqueID.Clone ();
+                       }
+               }
+
+               // uncommon v2 "extension"
+               public byte[] SubjectUniqueIdentifier {
+                       get {
+                               if (subjectUniqueID == null)
+                                       return null;
+                               return (byte[]) subjectUniqueID.Clone ();
+                       }
+               }
+
                internal bool VerifySignature (DSA dsa) 
                {
                        // signatureOID is check by both this.Hash and this.Signature
@@ -535,5 +568,16 @@ namespace Mono.Security.X509 {
                        // note: we NEVER serialize the private key
                }
 #endif
+
+               static byte[] PEM (string type, byte[] data) 
+               {
+                       string pem = Encoding.ASCII.GetString (data);
+                       string header = String.Format ("-----BEGIN {0}-----", type);
+                       string footer = String.Format ("-----END {0}-----", type);
+                       int start = pem.IndexOf (header) + header.Length;
+                       int end = pem.IndexOf (footer, start);
+                       string base64 = pem.Substring (start, (end - start));
+                       return Convert.FromBase64String (base64);
+               }
        }
 }