[pgsqlclient-checkins] pgsqlclient_10/Mono.Security/Mono.Security/Mono.Security.X509 PKCS12.cs,NONE,
Status: Inactive
Brought to you by:
carlosga_fb
Update of /cvsroot/pgsqlclient/pgsqlclient_10/Mono.Security/Mono.Security/Mono.Security.X509 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25152 Modified Files: TrustAnchors.cs X509Certificate.cs X509CertificateCollection.cs X509Chain.cs X520Attributes.cs Added Files: PKCS12.cs X509Builder.cs X509CertificateBuilder.cs X509ChainStatusFlags.cs X509CRL.cs X509Store.cs X509StoreManager.cs X509Stores.cs Log Message: Sync security stuff with mono CVS classes. --- NEW FILE: PKCS12.cs --- // // PKCS12.cs: PKCS 12 - Personal Information Exchange Syntax // // Author: // Sebastien Pouliot (spo...@mo...) // // (C) 2003 Motus Technologies Inc. (http://www.motus.com) // // Key derivation translated from Bouncy Castle JCE (http://www.bouncycastle.org/) // See bouncycastle.txt for license. // using System; using System.Collections; using System.IO; using System.Security.Cryptography; using System.Text; using Mono.Security; using Mono.Security.Cryptography; namespace Mono.Security.X509 { internal class PKCS5 { public const string pbeWithMD2AndDESCBC = "1.2.840.113549.1.5.1"; public const string pbeWithMD5AndDESCBC = "1.2.840.113549.1.5.3"; public const string pbeWithMD2AndRC2CBC = "1.2.840.113549.1.5.4"; public const string pbeWithMD5AndRC2CBC = "1.2.840.113549.1.5.6"; public const string pbeWithSHA1AndDESCBC = "1.2.840.113549.1.5.10"; public const string pbeWithSHA1AndRC2CBC = "1.2.840.113549.1.5.11"; public PKCS5 () {} } internal class PKCS12 { public const string pbeWithSHAAnd128BitRC4 = "1.2.840.113549.1.12.1.1"; public const string pbeWithSHAAnd40BitRC4 = "1.2.840.113549.1.12.1.2"; public const string pbeWithSHAAnd3KeyTripleDESCBC = "1.2.840.113549.1.12.1.3"; public const string pbeWithSHAAnd2KeyTripleDESCBC = "1.2.840.113549.1.12.1.4"; public const string pbeWithSHAAnd128BitRC2CBC = "1.2.840.113549.1.12.1.5"; public const string pbeWithSHAAnd40BitRC2CBC = "1.2.840.113549.1.12.1.6"; // bags public const string keyBag = "1.2.840.113549.1.12.10.1.1"; public const string pkcs8ShroudedKeyBag = "1.2.840.113549.1.12.10.1.2"; public const string certBag = "1.2.840.113549.1.12.10.1.3"; public const string crlBag = "1.2.840.113549.1.12.10.1.4"; public const string secretBag = "1.2.840.113549.1.12.10.1.5"; public const string safeContentsBag = "1.2.840.113549.1.12.10.1.6"; // types public const string x509Certificate = "1.2.840.113549.1.9.22.1"; public const string sdsiCertificate = "1.2.840.113549.1.9.22.2"; public const string x509Crl = "1.2.840.113549.1.9.23.1"; // Adapted from BouncyCastle PKCS12ParametersGenerator.java public class DeriveBytes { public enum Purpose { Key, IV, MAC } static private byte[] keyDiversifier = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; static private byte[] ivDiversifier = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }; static private byte[] macDiversifier = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }; private string _hashName; private int _iterations; private byte[] _password; private byte[] _salt; public DeriveBytes () {} public string HashName { get { return _hashName; } set { _hashName = value; } } public int IterationCount { get { return _iterations; } set { _iterations = value; } } public byte[] Password { get { return (byte[]) _password.Clone (); } set { if (value == null) _password = new byte [0]; else _password = (byte[]) value.Clone (); } } public byte[] Salt { get { return (byte[]) _salt.Clone (); } set { if (value != null) _salt = (byte[]) value.Clone (); else _salt = null; } } private void Adjust (byte[] a, int aOff, byte[] b) { int x = (b[b.Length - 1] & 0xff) + (a [aOff + b.Length - 1] & 0xff) + 1; a [aOff + b.Length - 1] = (byte) x; x >>= 8; for (int i = b.Length - 2; i >= 0; i--) { x += (b [i] & 0xff) + (a [aOff + i] & 0xff); a [aOff + i] = (byte) x; x >>= 8; } } private byte[] Derive (byte[] diversifier, int n) { HashAlgorithm digest = HashAlgorithm.Create (_hashName); int u = (digest.HashSize >> 3); // div 8 int v = 64; byte[] dKey = new byte [n]; byte[] S; if ((_salt != null) && (_salt.Length != 0)) { S = new byte[v * ((_salt.Length + v - 1) / v)]; for (int i = 0; i != S.Length; i++) { S[i] = _salt[i % _salt.Length]; } } else { S = new byte[0]; } byte[] P; if ((_password != null) && (_password.Length != 0)) { P = new byte[v * ((_password.Length + v - 1) / v)]; for (int i = 0; i != P.Length; i++) { P[i] = _password[i % _password.Length]; } } else { P = new byte[0]; } byte[] I = new byte [S.Length + P.Length]; Buffer.BlockCopy (S, 0, I, 0, S.Length); Buffer.BlockCopy (P, 0, I, S.Length, P.Length); byte[] B = new byte[v]; int c = (n + u - 1) / u; for (int i = 1; i <= c; i++) { digest.TransformBlock (diversifier, 0, diversifier.Length, diversifier, 0); digest.TransformFinalBlock (I, 0, I.Length); byte[] A = digest.Hash; digest.Initialize (); for (int j = 1; j != _iterations; j++) { A = digest.ComputeHash (A, 0, A.Length); } for (int j = 0; j != B.Length; j++) { B [j] = A [j % A.Length]; } for (int j = 0; j != I.Length / v; j++) { Adjust (I, j * v, B); } if (i == c) { Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u)); } else { Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, A.Length); } } return dKey; } public byte[] DeriveKey (int size) { return Derive (keyDiversifier, size); } public byte[] DeriveIV (int size) { return Derive (ivDiversifier, size); } public byte[] DeriveMAC (int size) { return Derive (macDiversifier, size); } } private int _version; private byte[] _password; private ArrayList _keyBags; private X509CertificateCollection _certs; // constructors public PKCS12 () { _keyBags = new ArrayList (); _certs = new X509CertificateCollection (); } public PKCS12 (byte[] data) : this (data, null) {} /* * PFX ::= SEQUENCE { * version INTEGER {v3(3)}(v3,...), * authSafe ContentInfo, * macData MacData OPTIONAL * } * * MacData ::= SEQUENCE { * mac DigestInfo, * macSalt OCTET STRING, * iterations INTEGER DEFAULT 1 * -- Note: The default is for historical reasons and its use is deprecated. A higher * -- value, like 1024 is recommended. * } * * SafeContents ::= SEQUENCE OF SafeBag * * SafeBag ::= SEQUENCE { * bagId BAG-TYPE.&id ({PKCS12BagSet}), * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), * bagAttributes SET OF PKCS12Attribute OPTIONAL * } */ public PKCS12 (byte[] data, string password) : this () { Password = password; ASN1 pfx = new ASN1 (data); if (pfx.Tag != 0x30) throw new ArgumentException ("invalid data"); ASN1 version = pfx [0]; if (version.Tag != 0x02) throw new ArgumentException ("invalid PFX version"); _version = version.Value [0]; PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (pfx [1]); if (authSafe.ContentType != PKCS7.data) throw new ArgumentException ("invalid authenticated safe"); // now that we know it's a PKCS#12 file, check the (optional) MAC // before decoding anything else in the file if (pfx.Count > 2) { ASN1 macData = pfx [2]; if (macData.Tag != 0x30) throw new ArgumentException ("invalid MAC"); ASN1 mac = macData [0]; if (mac.Tag != 0x30) throw new ArgumentException ("invalid MAC"); ASN1 macAlgorithm = mac [0]; string macOid = ASN1Convert.ToOID (macAlgorithm [0]); if (macOid != "1.3.14.3.2.26") throw new ArgumentException ("unsupported HMAC"); byte[] macValue = mac [1].Value; ASN1 macSalt = macData [1]; if (macSalt.Tag != 0x04) throw new ArgumentException ("missing MAC salt"); int iterations = 1; // default value if (macData.Count > 2) { ASN1 iters = macData [2]; if (iters.Tag != 0x02) throw new ArgumentException ("invalid MAC iteration"); iterations = ASN1Convert.ToInt32 (iters); } PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes (); pd.HashName = "SHA1"; pd.Password = _password; pd.Salt = macSalt.Value; pd.IterationCount = iterations; HMACSHA1 hmac = (HMACSHA1) HMACSHA1.Create (); hmac.Key = pd.DeriveMAC (20); byte[] authSafeData = authSafe.Content [0].Value; byte[] calculatedMac = hmac.ComputeHash (authSafeData, 0, authSafeData.Length); if (!Compare (macValue, calculatedMac)) throw new CryptographicException ("Invalid MAC - file may have been tampered!"); } // we now returns to our original presentation - PFX ASN1 authenticatedSafe = new ASN1 (authSafe.Content [0].Value); for (int i=0; i < authenticatedSafe.Count; i++) { PKCS7.ContentInfo ci = new PKCS7.ContentInfo (authenticatedSafe [i]); switch (ci.ContentType) { case PKCS7.data: // unencrypted (by PKCS#12) ASN1 safeContents = new ASN1 (ci.Content [0].Value); for (int j=0; j < safeContents.Count; j++) { ASN1 safeBag = safeContents [j]; ReadSafeBag (safeBag); } break; case PKCS7.encryptedData: // password encrypted PKCS7.EncryptedData ed = new PKCS7.EncryptedData (ci.Content [0]); ASN1 decrypted = new ASN1 (Decrypt (ed)); for (int j=0; j < decrypted.Count; j++) { ASN1 safeBag = decrypted [j]; ReadSafeBag (safeBag); } break; case PKCS7.envelopedData: // public key encrypted throw new NotImplementedException ("public key encrypted"); default: throw new ArgumentException ("unknown authenticatedSafe"); } } } ~PKCS12 () { if (_password != null) { Array.Clear (_password, 0, _password.Length); } } // properties public string Password { set { if (value != null) { if (value.EndsWith ("\0")) _password = Encoding.BigEndianUnicode.GetBytes (value); else _password = Encoding.BigEndianUnicode.GetBytes (value + "\0"); } else _password = null; // no password } } public ArrayList Keys { get { return _keyBags; } } public X509CertificateCollection Certificates { get { return _certs; } } // private methods private bool Compare (byte[] expected, byte[] actual) { bool compare = false; if (expected.Length == actual.Length) { for (int i=0; i < expected.Length; i++) { if (expected [i] != actual [i]) return false; } compare = true; } return compare; } public byte[] Decrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] encryptedData) { string algorithm = null; int keyLength = 8; // 64 bits (default) int ivLength = 8; // 64 bits (default) PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes (); pd.Password = _password; pd.Salt = salt; pd.IterationCount = iterationCount; switch (algorithmOid) { case PKCS5.pbeWithMD2AndDESCBC: // no unit test available pd.HashName = "MD2"; algorithm = "DES"; break; case PKCS5.pbeWithMD5AndDESCBC: // no unit test available pd.HashName = "MD5"; algorithm = "DES"; break; case PKCS5.pbeWithMD2AndRC2CBC: // no unit test available // TODO - RC2-CBC-Parameter (PKCS5) // if missing default to 32 bits !!! pd.HashName = "MD2"; algorithm = "RC2"; keyLength = 4; // default break; case PKCS5.pbeWithMD5AndRC2CBC: // no unit test available // TODO - RC2-CBC-Parameter (PKCS5) // if missing default to 32 bits !!! pd.HashName = "MD5"; algorithm = "RC2"; keyLength = 4; // default break; case PKCS5.pbeWithSHA1AndDESCBC: // no unit test available pd.HashName = "SHA1"; algorithm = "DES"; break; case PKCS5.pbeWithSHA1AndRC2CBC: // no unit test available // TODO - RC2-CBC-Parameter (PKCS5) // if missing default to 32 bits !!! pd.HashName = "SHA1"; algorithm = "RC2"; keyLength = 4; // default break; case PKCS12.pbeWithSHAAnd128BitRC4: // no unit test available pd.HashName = "SHA1"; algorithm = "RC4"; keyLength = 16; ivLength = 0; // N/A break; case PKCS12.pbeWithSHAAnd40BitRC4: // no unit test available pd.HashName = "SHA1"; algorithm = "RC4"; keyLength = 5; ivLength = 0; // N/A break; case PKCS12.pbeWithSHAAnd3KeyTripleDESCBC: pd.HashName = "SHA1"; algorithm = "TripleDES"; keyLength = 24; break; case PKCS12.pbeWithSHAAnd2KeyTripleDESCBC: // no unit test available pd.HashName = "SHA1"; algorithm = "TripleDES"; keyLength = 16; break; case PKCS12.pbeWithSHAAnd128BitRC2CBC: // no unit test available pd.HashName = "SHA1"; algorithm = "RC2"; keyLength = 16; break; case PKCS12.pbeWithSHAAnd40BitRC2CBC: pd.HashName = "SHA1"; algorithm = "RC2"; keyLength = 5; break; default: throw new NotSupportedException ("unknown oid " + algorithm); } SymmetricAlgorithm sa = SymmetricAlgorithm.Create (algorithm); sa.Key = pd.DeriveKey (keyLength); // IV required only for block ciphers (not stream ciphers) if (ivLength > 0) { sa.IV = pd.DeriveIV (ivLength); sa.Mode = CipherMode.CBC; } ICryptoTransform ct = sa.CreateDecryptor (); return ct.TransformFinalBlock (encryptedData, 0, encryptedData.Length); } public byte[] Decrypt (PKCS7.EncryptedData ed) { return Decrypt (ed.EncryptionAlgorithm.ContentType, ed.EncryptionAlgorithm.Content [0].Value, ASN1Convert.ToInt32 (ed.EncryptionAlgorithm.Content [1]), ed.EncryptedContent); } private void AddPrivateKey (PKCS8.PrivateKeyInfo pki) { byte[] privateKey = pki.PrivateKey; switch (privateKey [0]) { case 0x02: DSAParameters p = new DSAParameters (); // FIXME _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p)); break; case 0x30: _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey)); break; default: Array.Clear (privateKey, 0, privateKey.Length); throw new CryptographicException ("Unknown private key format"); } Array.Clear (privateKey, 0, privateKey.Length); } private void ReadSafeBag (ASN1 safeBag) { if (safeBag.Tag != 0x30) throw new ArgumentException ("invalid safeBag"); ASN1 bagId = safeBag [0]; if (bagId.Tag != 0x06) throw new ArgumentException ("invalid safeBag id"); ASN1 bagValue = safeBag [1]; string oid = ASN1Convert.ToOID (bagId); switch (oid) { case keyBag: // NEED UNIT TEST AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value)); break; case pkcs8ShroudedKeyBag: PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted)); Array.Clear (decrypted, 0, decrypted.Length); break; case certBag: PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value); if (cert.ContentType != x509Certificate) throw new NotSupportedException ("unsupport certificate type"); X509Certificate x509 = new X509Certificate (cert.Content [0].Value); _certs.Add (x509); break; case crlBag: // TODO break; case secretBag: // TODO break; case safeContentsBag: // TODO - ? recurse ? break; default: throw new ArgumentException ("unknown safeBag oid"); } } static private int recommendedIterationCount = 2000; /* * SafeContents ::= SEQUENCE OF SafeBag * * SafeBag ::= SEQUENCE { * bagId BAG-TYPE.&id ({PKCS12BagSet}), * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), * bagAttributes SET OF PKCS12Attribute OPTIONAL * } */ public byte[] GetBytes () { PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (PKCS7.data); // TODO (incomplete) byte[] salt = new byte [20]; RandomNumberGenerator rng = RandomNumberGenerator.Create (); rng.GetBytes (salt); ASN1 macData = new ASN1 (0x30); byte[] macValue = null; if (macValue != null) { // only for password based encryption ASN1 mac = new ASN1 (0x30); mac.Add (ASN1Convert.FromOID ("1.3.14.3.2.26")); // SHA1 mac.Add (new ASN1 (0x04, macValue)); macData.Add (mac); macData.Add (new ASN1 (0x04, salt)); macData.Add (ASN1Convert.FromInt32 (recommendedIterationCount)); } ASN1 version = new ASN1 (0x02, new byte [1] { 0x03 }); ASN1 pfx = new ASN1 (0x30); pfx.Add (version); pfx.Add (authSafe.ASN1); if (macValue != null) { // only for password based encryption pfx.Add (macData); } return pfx.GetBytes (); } // static methods static private byte[] LoadFile (string filename) { byte[] data = null; using (FileStream fs = File.OpenRead (filename)) { data = new byte [fs.Length]; fs.Read (data, 0, data.Length); fs.Close (); } return data; } static public PKCS12 LoadFromFile (string filename) { if (filename == null) throw new ArgumentNullException ("filename"); return new PKCS12 (LoadFile (filename)); } static public PKCS12 LoadFromFile (string filename, string password) { if (filename == null) throw new ArgumentNullException ("filename"); if (password == null) throw new ArgumentNullException ("password"); return new PKCS12 (LoadFile (filename), password); } } } --- NEW FILE: X509Builder.cs --- using System; using System.Security.Cryptography; using Mono.Security; namespace Mono.Security.X509 { internal abstract class X509Builder { private const string defaultHash = "SHA1"; private string hashName; public X509Builder () { hashName = defaultHash; } protected abstract ASN1 ToBeSigned (string hashName); // move to PKCS1 protected string GetOID (string hashName) { switch (hashName.ToLower ()) { case "md2": // md2withRSAEncryption (1 2 840 113549 1 1 2) return "1.2.840.113549.1.1.2"; case "md4": // md4withRSAEncryption (1 2 840 113549 1 1 3) return "1.2.840.113549.1.1.3"; case "md5": // md5withRSAEncryption (1 2 840 113549 1 1 4) return "1.2.840.113549.1.1.4"; case "sha1": // sha1withRSAEncryption (1 2 840 113549 1 1 5) return "1.2.840.113549.1.1.5"; case "sha256": // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } return "1.2.840.113549.1.1.11"; case "sha384": // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } return "1.2.840.113549.1.1.12"; case "sha512": // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } return "1.2.840.113549.1.1.13"; default: throw new NotSupportedException ("Unknown hash algorithm " + hashName); } } public string Hash { get { return hashName; } set { if (hashName == null) hashName = defaultHash; else hashName = value; } } public virtual byte[] Sign (AsymmetricAlgorithm aa) { if (aa is RSA) return Sign (aa as RSA); else if (aa is DSA) return Sign (aa as DSA); else throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString()); } private byte[] Build (ASN1 tbs, string hashoid, byte[] signature) { ASN1 builder = new ASN1 (0x30); builder.Add (tbs); builder.Add (PKCS7.AlgorithmIdentifier (hashoid)); // first byte of BITSTRING is the number of unused bits in the first byte byte[] bitstring = new byte [signature.Length + 1]; Array.Copy (signature, 0, bitstring, 1, signature.Length); builder.Add (new ASN1 (0x03, bitstring)); return builder.GetBytes (); } public virtual byte[] Sign (RSA key) { string oid = GetOID (hashName); ASN1 tbs = ToBeSigned (oid); HashAlgorithm ha = HashAlgorithm.Create (hashName); byte[] hash = ha.ComputeHash (tbs.GetBytes ()); RSAPKCS1SignatureFormatter pkcs1 = new RSAPKCS1SignatureFormatter (key); pkcs1.SetHashAlgorithm (hashName); byte[] signature = pkcs1.CreateSignature (hash); return Build (tbs, oid, signature); } public virtual byte[] Sign (DSA key) { string oid = "1.2.840.10040.4.3"; ASN1 tbs = ToBeSigned (oid); HashAlgorithm ha = HashAlgorithm.Create (hashName); if (!(ha is SHA1)) throw new NotSupportedException ("Only SHA-1 is supported for DSA"); byte[] hash = ha.ComputeHash (tbs.GetBytes ()); DSASignatureFormatter dsa = new DSASignatureFormatter (key); dsa.SetHashAlgorithm (hashName); byte[] rs = dsa.CreateSignature (hash); // split R and S byte[] r = new byte [20]; Array.Copy (rs, 0, r, 0, 20); byte[] s = new byte [20]; Array.Copy (rs, 20, s, 0, 20); ASN1 signature = new ASN1 (0x30); signature.Add (new ASN1 (0x02, r)); signature.Add (new ASN1 (0x02, s)); // dsaWithSha1 (1 2 840 10040 4 3) return Build (tbs, oid, signature.GetBytes ()); } } } --- NEW FILE: X509CertificateBuilder.cs --- // // X509CertificateBuilder.cs: Handles building of X.509 certificates. // // Author: // Sebastien Pouliot (spo...@mo...) // // (C) 2003 Motus Technologies Inc. (http://www.motus.com) using System; using System.Security.Cryptography; namespace Mono.Security.X509 { // From RFC3280 /* * Certificate ::= SEQUENCE { * tbsCertificate TBSCertificate, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING * } * TBSCertificate ::= SEQUENCE { * version [0] Version DEFAULT v1, * serialNumber CertificateSerialNumber, * signature AlgorithmIdentifier, * issuer Name, * validity Validity, * subject Name, * subjectPublicKeyInfo SubjectPublicKeyInfo, * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version MUST be v2 or v3 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version MUST be v2 or v3 * extensions [3] Extensions OPTIONAL * -- If present, version MUST be v3 -- * } * Version ::= INTEGER { v1(0), v2(1), v3(2) } * CertificateSerialNumber ::= INTEGER * Validity ::= SEQUENCE { * notBefore Time, * notAfter Time * } * Time ::= CHOICE { * utcTime UTCTime, * generalTime GeneralizedTime * } */ internal class X509CertificateBuilder : X509Builder { private byte version; private byte[] sn; private string issuer; private DateTime notBefore; private DateTime notAfter; private string subject; private AsymmetricAlgorithm aa; private byte[] issuerUniqueID; private byte[] subjectUniqueID; private X509Extensions extensions; public X509CertificateBuilder () : this (3) {} public X509CertificateBuilder (byte version) { if (version > 3) throw new ArgumentException ("Invalid certificate version"); this.version = version; extensions = new X509Extensions (); } public byte Version { get { return version; } set { version = value; } } public byte[] SerialNumber { get { return sn; } set { sn = value; } } public string IssuerName { get { return issuer; } set { issuer = value; } } public DateTime NotBefore { get { return notBefore; } set { notBefore = value; } } public DateTime NotAfter { get { return notAfter; } set { notAfter = value; } } public string SubjectName { get { return subject; } set { subject = value; } } public AsymmetricAlgorithm SubjectPublicKey { get { return aa; } set { aa = value; } } public byte[] IssuerUniqueID { get { return issuerUniqueID; } set { issuerUniqueID = value; } } public byte[] SubjectUniqueID { get { return subjectUniqueID; } set { subjectUniqueID = value; } } public X509Extensions Extensions { get { return extensions; } } /* SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING } */ private ASN1 SubjectPublicKeyInfo () { ASN1 keyInfo = new ASN1 (0x30); if (aa is RSA) { keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.113549.1.1.1")); RSAParameters p = (aa as RSA).ExportParameters (false); /* RSAPublicKey ::= SEQUENCE { * modulus INTEGER, -- n * publicExponent INTEGER } -- e */ ASN1 key = new ASN1 (0x30); key.Add (ASN1Convert.FromUnsignedBigInteger (p.Modulus)); key.Add (ASN1Convert.FromUnsignedBigInteger (p.Exponent)); keyInfo.Add (new ASN1 (UniqueIdentifier (key.GetBytes ()))); } else if (aa is DSA) { DSAParameters p = (aa as DSA).ExportParameters (false); /* Dss-Parms ::= SEQUENCE { * p INTEGER, * q INTEGER, * g INTEGER } */ ASN1 param = new ASN1 (0x30); param.Add (ASN1Convert.FromUnsignedBigInteger (p.P)); param.Add (ASN1Convert.FromUnsignedBigInteger (p.Q)); param.Add (ASN1Convert.FromUnsignedBigInteger (p.G)); keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.10040.4.1", param)); ASN1 key = keyInfo.Add (new ASN1 (0x03)); // DSAPublicKey ::= INTEGER -- public key, y key.Add (ASN1Convert.FromUnsignedBigInteger (p.Y)); } else throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ()); return keyInfo; } private byte[] UniqueIdentifier (byte[] id) { // UniqueIdentifier ::= BIT STRING ASN1 uid = new ASN1 (0x03); // first byte in a BITSTRING is the number of unused bits in the first byte byte[] v = new byte [id.Length + 1]; Array.Copy (id, 0, v, 1, id.Length); uid.Value = v; return uid.GetBytes (); } protected override ASN1 ToBeSigned (string oid) { // TBSCertificate ASN1 tbsCert = new ASN1 (0x30); if (version > 1) { // TBSCertificate / [0] Version DEFAULT v1, byte[] ver = { (byte)(version - 1) }; ASN1 v = tbsCert.Add (new ASN1 (0xA0)); v.Add (new ASN1 (0x02, ver)); } // TBSCertificate / CertificateSerialNumber, tbsCert.Add (new ASN1 (0x02, sn)); // TBSCertificate / AlgorithmIdentifier, tbsCert.Add (PKCS7.AlgorithmIdentifier (oid)); // TBSCertificate / Name tbsCert.Add (X501.FromString (issuer)); // TBSCertificate / Validity ASN1 validity = tbsCert.Add (new ASN1 (0x30)); // TBSCertificate / Validity / Time validity.Add (ASN1Convert.FromDateTime (notBefore)); // TBSCertificate / Validity / Time validity.Add (ASN1Convert.FromDateTime (notAfter)); // TBSCertificate / Name tbsCert.Add (X501.FromString (subject)); // TBSCertificate / SubjectPublicKeyInfo ASN1 keyInfo = tbsCert.Add (SubjectPublicKeyInfo ()); if (version > 1) { // TBSCertificate / [1] IMPLICIT UniqueIdentifier OPTIONAL if (issuerUniqueID != null) tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (issuerUniqueID))); // TBSCertificate / [2] IMPLICIT UniqueIdentifier OPTIONAL if (subjectUniqueID != null) tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (subjectUniqueID))); // TBSCertificate / [3] Extensions OPTIONAL if ((version > 2) && (extensions.Count > 0)) tbsCert.Add (new ASN1 (0xA3, extensions.GetBytes ())); } return tbsCert; } } } --- NEW FILE: X509ChainStatusFlags.cs --- // // X509ChainStatusFlags.cs: X.509 Chain Status // // Author: // Sebastien Pouliot <seb...@xi...> // // (C) 2004 Novell (http://www.novell.com) // using System; namespace Mono.Security.X509 { // definitions from Fx 1.2 // commented flags aren't implemented in X509Chain [Serializable] internal enum X509ChainStatusFlags { // CtlNotSignatureValid = 262144, // CtlNotTimeValid = 131072, // CtlNotValidForUsage = 524288, // Cyclic = 128, // HasExcludedNameConstraint = 32768, // HasNotDefinedNameConstraint = 8192, // HasNotPermittedNameConstraint = 16384, // HasNotSupportedNameConstraint = 4096, InvalidBasicConstraints = 1024, // InvalidExtension = 256, // InvalidNameConstraints = 2048, // InvalidPolicyConstraints = 512, NoError = 0, // NoIssuanceChainPolicy = 33554432, NotSignatureValid = 8, NotTimeNested = 2, NotTimeValid = 1, // NotValidForUsage = 16, // OfflineRevocation = 16777216, PartialChain = 65536, // RevocationStatusUnknown = 64, // Revoked = 4, UntrustedRoot = 32 } } --- NEW FILE: X509CRL.cs --- // // X509CRL.cs: Handles X.509 certificates revocation lists. // // Author: // Sebastien Pouliot <seb...@xi...> // // (C) 2004 Novell (http://www.novell.com) // using System; using System.Collections; using System.IO; using System.Security.Cryptography; using Mono.Security.X509.Extensions; namespace Mono.Security.X509 { /* * CertificateList ::= SEQUENCE { * tbsCertList TBSCertList, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING * } * * TBSCertList ::= SEQUENCE { * version Version OPTIONAL, * -- if present, MUST be v2 * signature AlgorithmIdentifier, * issuer Name, * thisUpdate Time, * nextUpdate Time OPTIONAL, * revokedCertificates SEQUENCE OF SEQUENCE { * userCertificate CertificateSerialNumber, * revocationDate Time, * crlEntryExtensions Extensions OPTIONAL * -- if present, MUST be v2 * } OPTIONAL, * crlExtensions [0] Extensions OPTIONAL } * -- if present, MUST be v2 */ internal class X509CRL { internal class X509CRLEntry { private byte[] sn; private DateTime revocationDate; private X509Extensions extensions; internal X509CRLEntry (byte[] serialNumber, DateTime revocationDate, X509Extensions extensions) { sn = serialNumber; this.revocationDate = revocationDate; if (extensions == null) this.extensions = new X509Extensions (); else this.extensions = extensions; } internal X509CRLEntry (ASN1 entry) { sn = entry [0].Value; Array.Reverse (sn); revocationDate = ASN1Convert.ToDateTime (entry [1]); extensions = new X509Extensions (entry [2]); } public byte[] SerialNumber { get { return sn; } } public DateTime RevocationDate { get { return revocationDate; } } public X509Extensions Extensions { get { return extensions; } } public byte[] GetBytes () { ASN1 sequence = new ASN1 (0x30); sequence.Add (new ASN1 (0x02, sn)); sequence.Add (ASN1Convert.FromDateTime (revocationDate)); if (extensions.Count > 0) sequence.Add (new ASN1 (extensions.GetBytes ())); return sequence.GetBytes (); } } private string issuer; private byte version; private DateTime thisUpdate; private DateTime nextUpdate; private ArrayList entries; private string signatureOID; private byte[] signature; private X509Extensions extensions; private byte[] encoded; public X509CRL (byte[] crl) { if (crl == null) throw new ArgumentNullException ("crl"); encoded = (byte[]) crl.Clone (); Parse (encoded); } private void Parse (byte[] crl) { string e = "Input data cannot be coded as a valid CRL."; try { // CertificateList ::= SEQUENCE { ASN1 encodedCRL = new ASN1 (encoded); if ((encodedCRL.Tag != 0x30) || (encodedCRL.Count != 3)) throw new CryptographicException (e); // CertificateList / TBSCertList, ASN1 toBeSigned = encodedCRL [0]; if ((toBeSigned.Tag != 0x30) || (toBeSigned.Count < 3)) throw new CryptographicException (e); int n = 0; // CertificateList / TBSCertList / Version OPTIONAL, -- if present, MUST be v2 if (toBeSigned [n].Tag == 0x02) { version = (byte) (toBeSigned [n++].Value [0] + 1); } else version = 1; // DEFAULT // CertificateList / TBSCertList / AlgorithmIdentifier, signatureOID = ASN1Convert.ToOID (toBeSigned [n++][0]); // CertificateList / TBSCertList / Name, issuer = X501.ToString (toBeSigned [n++]); // CertificateList / TBSCertList / Time, thisUpdate = ASN1Convert.ToDateTime (toBeSigned [n++]); // CertificateList / TBSCertList / Time OPTIONAL, ASN1 next = toBeSigned [n++]; if ((next.Tag == 0x17) || (next.Tag == 0x18)) { nextUpdate = ASN1Convert.ToDateTime (next); next = toBeSigned [n++]; } // CertificateList / TBSCertList / revokedCertificates SEQUENCE OF SEQUENCE { entries = new ArrayList (); ASN1 revokedCertificates = next; for (int i=0; i < revokedCertificates.Count; i++) { entries.Add (new X509CRLEntry (revokedCertificates [i])); } // CertificateList / TBSCertList / crlExtensions [0] Extensions OPTIONAL } ASN1 extns = toBeSigned [n]; if ((extns != null) && (extns.Tag == 0xA0) && (extns.Count == 1)) extensions = new X509Extensions (extns [0]); else extensions = new X509Extensions (null); // result in a read only object // CertificateList / AlgorithmIdentifier string signatureAlgorithm = ASN1Convert.ToOID (encodedCRL [1][0]); if (signatureOID != signatureAlgorithm) throw new CryptographicException (e + " [Non-matching signature algorithms in CRL]"); // CertificateList / BIT STRING byte[] bitstring = encodedCRL [2].Value; // first byte contains unused bits in first byte signature = new byte [bitstring.Length - 1]; Array.Copy (bitstring, 1, signature, 0, signature.Length); } catch { throw new CryptographicException (e); } } public ArrayList Entries { get { return ArrayList.ReadOnly (entries); } } public X509CRLEntry this [int index] { get { return (X509CRLEntry) entries [index]; } } public X509CRLEntry this [byte[] serialNumber] { get { return GetCRLEntry (serialNumber); } } public X509Extensions Extensions { get { return extensions; } } public string IssuerName { get { return issuer; } } public DateTime NextUpdate { get { return nextUpdate; } } public DateTime ThisUpdate { get { return thisUpdate; } } public string SignatureAlgorithm { get { return signatureOID; } } public byte[] Signature { get { return signature; } } public byte Version { get { return version; } } public bool IsCurrent { get { return WasCurrent (DateTime.UtcNow); } } public bool WasCurrent (DateTime date) { if (nextUpdate == DateTime.MinValue) return (date >= thisUpdate); else return ((date >= thisUpdate) && (date <= nextUpdate)); } public byte[] GetBytes () { return encoded; } private bool Compare (byte[] array1, byte[] array2) { if ((array1 == null) && (array2 == null)) return true; if ((array1 == null) || (array2 == null)) return false; if (array1.Length != array2.Length) return false; for (int i=0; i < array1.Length; i++) { if (array1 [i] != array2 [i]) return false; } return true; } public X509CRLEntry GetCRLEntry (X509Certificate x509) { if (x509 == null) throw new ArgumentNullException ("x509"); return GetCRLEntry (x509.SerialNumber); } public X509CRLEntry GetCRLEntry (byte[] serialNumber) { if (serialNumber == null) throw new ArgumentNullException ("serialNumber"); for (int i=0; i < entries.Count; i++) { X509CRLEntry entry = (X509CRLEntry) entries [i]; if (Compare (serialNumber, entry.SerialNumber)) return entry; } return null; } public bool VerifySignature (X509Certificate x509) { // 1. x509 certificate must be a CA certificate (unknown for v1 or v2 certs) if (x509.Version >= 3) { // 1.1. Check for "cRLSign" bit in KeyUsage extension X509Extension ext = x509.Extensions ["2.5.29.15"]; if (ext != null) { KeyUsageExtension keyUsage = new KeyUsageExtension (ext); if (!keyUsage.Support (KeyUsage.cRLSign)) return false; } // 1.2. Check for ca = true in BasicConstraint ext = x509.Extensions ["2.5.29.19"]; if (ext != null) { BasicConstraintsExtension basicConstraints = new BasicConstraintsExtension (ext); if (!basicConstraints.CertificateAuthority) return false; } } // 2. CRL issuer must match CA subject name if (issuer != x509.SubjectName) return false; // 3. Check the CRL signature with the CA certificate public key switch (signatureOID) { case "1.2.840.10040.4.3": return VerifySignature (x509.DSA); default: return VerifySignature (x509.RSA); } } private byte[] GetHash (string hashName) { ASN1 encodedCRL = new ASN1 (encoded); byte[] toBeSigned = encodedCRL [0].GetBytes (); HashAlgorithm ha = HashAlgorithm.Create (hashName); return ha.ComputeHash (toBeSigned); } public bool VerifySignature (DSA dsa) { if (signatureOID != "1.2.840.10040.4.3") throw new CryptographicException ("Unsupported hash algorithm: " + signatureOID); DSASignatureDeformatter v = new DSASignatureDeformatter (dsa); // only SHA-1 is supported string hashName = "SHA1"; v.SetHashAlgorithm (hashName); ASN1 sign = new ASN1 (signature); if ((sign == null) || (sign.Count != 2)) return false; // 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]; Array.Copy (part1, 0, sig, (20 - part1.Length), part1.Length); Array.Copy (part2, 0, sig, (40 - part2.Length), part2.Length); return v.VerifySignature (GetHash (hashName), sig); } public bool VerifySignature (RSA rsa) { RSAPKCS1SignatureDeformatter v = new RSAPKCS1SignatureDeformatter (rsa); string hashName = null; switch (signatureOID) { // MD2 with RSA encryption case "1.2.840.113549.1.1.2": // maybe someone installed MD2 ? hashName = "MD2"; break; // MD5 with RSA encryption case "1.2.840.113549.1.1.4": hashName = "MD5"; break; // SHA-1 with RSA Encryption case "1.2.840.113549.1.1.5": hashName = "SHA1"; break; default: throw new CryptographicException ("Unsupported hash algorithm: " + signatureOID); } v.SetHashAlgorithm (hashName); return v.VerifySignature (GetHash (hashName), signature); } public bool VerifySignature (AsymmetricAlgorithm aa) { // only validate the signature (in case we don't have the CA certificate) if (aa is RSA) return VerifySignature (aa as RSA); else if (aa is DSA) return VerifySignature (aa as DSA); else throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ()); } static public X509CRL CreateFromFile (string filename) { FileStream fs = File.Open (filename, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] crl = new byte [fs.Length]; fs.Read (crl, 0, crl.Length); fs.Close (); return new X509CRL (crl); } } } --- NEW FILE: X509Store.cs --- // // X509Store.cs: Handles a X.509 certificates/CRLs store // // Author: // Sebastien Pouliot <seb...@xi...> // // (C) 2004 Novell (http://www.novell.com) // using System; using System.Collections; using System.IO; using System.Text; using Mono.Security.X509.Extensions; namespace Mono.Security.X509 { internal class X509Store { private string _storePath; private X509CertificateCollection _certificates; private ArrayList _crls; private bool _crl; private string _name; internal X509Store (string path, bool crl) { _storePath = path; _crl = crl; } // properties public X509CertificateCollection Certificates { get { if (_certificates == null) { _certificates = BuildCertificatesCollection (_storePath); } return _certificates; } } public ArrayList CRLs { get { // CRL aren't applicable to all stores // but returning null is a little rude if (!_crl) { _crls = new ArrayList (); } if (_crls == null) { _crls = BuildCRLsCollection (_storePath); } return _crls; } } public string Name { get { if (_name == null) { int n = _storePath.LastIndexOf (Path.DirectorySeparatorChar); _name = _storePath.Substring (n+1); } return _name; } } // methods public void Clear () { if (_certificates != null) _certificates.Clear (); _certificates = null; if (_crls != null) _crls.Clear (); _crls = null; } public void Import (X509Certificate certificate) { if (!Directory.Exists (_storePath)) { Directory.CreateDirectory (_storePath); } string filename = Path.Combine (_storePath, GetUniqueName (certificate)); if (!File.Exists (filename)) { using (FileStream fs = File.OpenWrite (filename)) { byte[] data = certificate.RawData; fs.Write (data, 0, data.Length); fs.Close (); } } } public void Remove (X509Certificate certificate) { string filename = Path.Combine (_storePath, GetUniqueName (certificate)); if (File.Exists (filename)) { File.Delete (filename); } } // private stuff private string GetUniqueName (X509Certificate certificate) { string method = null; byte[] name = null; // We prefer Subject Key Identifier as the unique name // as it will provide faster lookups X509Extension ext = certificate.Extensions ["2.5.29.14"]; if (ext != null) { SubjectKeyIdentifierExtension ski = new SubjectKeyIdentifierExtension (ext); name = ski.Identifier; method = "ski"; } else { method = "tbp"; // thumbprint name = certificate.Hash; } StringBuilder sb = new StringBuilder (method); sb.Append ("-"); foreach (byte b in name) { sb.Append (b.ToString ("X2")); } sb.Append (".cer"); return sb.ToString (); } private byte[] Load (string filename) { byte[] data = null; using (FileStream fs = File.OpenRead (filename)) { data = new byte [fs.Length]; fs.Read (data, 0, data.Length); fs.Close (); } return data; } private X509Certificate LoadCertificate (string filename) { byte[] data = Load (filename); X509Certificate cert = new X509Certificate (data); return cert; } private X509CRL LoadCRL (string filename) { byte[] data = Load (filename); X509CRL crl = new X509CRL (data); return crl; } private X509CertificateCollection BuildCertificatesCollection (string storeName) { string path = Path.Combine (_storePath, storeName); if (!Directory.Exists (path)) { Directory.CreateDirectory (path); } X509CertificateCollection coll = new X509CertificateCollection (); string[] files = Directory.GetFiles (path, "*.cer"); if ((files != null) && (files.Length > 0)) { foreach (string file in files) { try { X509Certificate cert = LoadCertificate (file); coll.Add (cert); } catch { // in case someone is dumb enough // (like me) to include a base64 // encoded certs (or other junk // into the store). } } } return coll; } private ArrayList BuildCRLsCollection (string storeName) { ArrayList list = new ArrayList (); string path = Path.Combine (_storePath, storeName); string[] files = Directory.GetFiles (path, "*.crl"); if ((files != null) && (files.Length > 0)) { foreach (string file in files) { try { X509CRL crl = LoadCRL (file); list.Add (crl); } catch { // junk catcher } } } return list; } } } --- NEW FILE: X509StoreManager.cs --- // // X509StoreManager.cs: X.509 store manager. // // Author: // Sebastien Pouliot <seb...@xi...> // // (C) 2004 Novell (http://www.novell.com) // using System; using System.Collections; using System.IO; using Mono.Security.X509.Extensions; namespace Mono.Security.X509 { internal class X509StoreManager { static private X509Stores _userStore; static private X509Stores _machineStore; protected X509StoreManager () {} static public X509Stores CurrentUser { get { if (_userStore == null) { string _userPath = Path.Combine ( Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), ".mono"); _userPath = Path.Combine (_userPath, "certs"); _userStore = new X509Stores (_userPath); } return _userStore; } } static public X509Stores LocalMachine { get { if (_machineStore == null) { // FIXME: where should it be ? string _machinePath = Path.Combine ( Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), ".mono"); _machinePath = Path.Combine (_machinePath, "machinecerts"); // FIXME _machineStore = new X509Stores (_machinePath); } return _machineStore; } } // Merged stores collections // we need to look at both the user and the machine (entreprise) // certificates/CRLs when building/validating a chain static public X509CertificateCollection IntermediateCACertificates { get { X509CertificateCollection intermediateCerts = new X509CertificateCollection (); intermediateCerts.AddRange (CurrentUser.IntermediateCA.Certificates); intermediateCerts.AddRange (LocalMachine.IntermediateCA.Certificates); return intermediateCerts; } } static public ArrayList IntermediateCACRLs { get { ArrayList intermediateCRLs = new ArrayList (); intermediateCRLs.AddRange (CurrentUser.IntermediateCA.CRLs); intermediateCRLs.AddRange (LocalMachine.IntermediateCA.CRLs); return intermediateCRLs; } } static public X509CertificateCollection TrustedRootCertificates { get { X509CertificateCollection trustedCerts = new X509CertificateCollection (); trustedCerts.AddRange (CurrentUser.TrustedRoot.Certificates); trustedCerts.AddRange (LocalMachine.TrustedRoot.Certificates); return trustedCerts; } } static public ArrayList TrustedRootCACRLs { get { ArrayList trustedCRLs = new ArrayList (); trustedCRLs.AddRange (CurrentUser.TrustedRoot.CRLs); trustedCRLs.AddRange (LocalMachine.TrustedRoot.CRLs); return trustedCRLs; } } static public X509CertificateCollection UntrustedCertificates { get { X509CertificateCollection untrustedCerts = new X509CertificateCollection (); untrustedCerts.AddRange (CurrentUser.Untrusted.Certificates); untrustedCerts.AddRange (LocalMachine.Untrusted.Certificates); return untrustedCerts; } } } } --- NEW FILE: X509Stores.cs --- // // X509Stores.cs: Handles X.509 certificates/CRLs stores group. // // Author: // Sebastien Pouliot <seb...@xi...> // // (C) 2004 Novell (http://www.novell.com) // using System; using System.Collections; using System.IO; using Mono.Security.X509.Extensions; namespace Mono.Security.X509 { internal class X509Stores { private string _storePath; private X509Store _personal; private X509Store _other; private X509Store _intermediate; private X509Store _trusted; private X509Store _untrusted; internal X509Stores (string path) { _storePath = path; } // properties public X509Store Personal { get { if (_personal == null) { string path = Path.Combine (_storePath, Names.Personal); _personal = new X509Store (path, false); } return _personal; } } public X509Store OtherPeople { get { if (_other == null) { string path = Path.Combine (_storePath, Names.OtherPeople); _other = new X509Store (path, false); } return _other; } } public X509Store IntermediateCA { get { if (_intermediate == null) { string path = Path.Combine (_storePath, Names.IntermediateCA); _intermediate = new X509Store (path, true); } return _intermediate; } } public X509Store TrustedRoot { get { if (_trusted == null) { string path = Path.Combine (_storePath, Names.TrustedRoot); _trusted = new X509Store (path, true); } return _trusted; } } public X509Store Untrusted { get { if (_untrusted == null) { string path = Path.Combine (_storePath, Names.Untrusted); _untrusted = new X509Store (path, false); } return _untrusted; } } // methods public void Clear () { // this will force a reload of all stores if (_personal != null) _personal.Clear (); _personal = null; if (_other != null) _other.Clear (); _other = null; if (_intermediate != null) _intermediate.Clear (); _intermediate = null; if (_trusted != null) _trusted.Clear (); _trusted = null; if (_untrusted != null) _untrusted.Clear (); _untrusted = null; } // names internal class Names { // do not translate public const string Personal = "My"; public const string OtherPeople = "AddressBook"; public const string IntermediateCA = "CA"; public const string TrustedRoot = "Trust"; public const string Untrusted = "Disallowed"; public Names () {} } } } Index: TrustAnchors.cs =================================================================== RCS file: /cvsroot/pgsqlclient/pgsqlclient_10/Mono.Security/Mono.Security/Mono.Security.X509/TrustAnchors.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** TrustAnchors.cs 10 Feb 2004 09:46:25 -0000 1.1 --- TrustAnchors.cs 5 Mar 2004 23:18:17 -0000 1.2 *************** *** 268,271 **** --- 268,339 ---- 0xBD, 0x2B, 0x22, 0xFF, 0x1C }; + static byte[] thawte = { + 0x30, 0x82, 0x03, 0x13, 0x30, 0x82, 0x02, 0x7C, 0xA0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x81, 0xC4, 0x31, 0x0B, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5A, 0x41, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0C, 0x57, 0x65, + 0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x43, 0x61, 0x70, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x61, 0x70, + 0x65, 0x20, 0x54, 0x6F, 0x77, 0x6E, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, + 0x55, 0x04, 0x0A, 0x13, 0x14, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, + 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x63, + 0x63, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x1F, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x31, 0x26, + 0x30, 0x24, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, + 0x01, 0x16, 0x17, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2D, 0x63, 0x65, + 0x72, 0x74, 0x73, 0x40, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2E, 0x63, + 0x6F, 0x6D, 0x30, 0x1E, 0x17, 0x0D, 0x39, 0x36, 0x30, 0x38, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x30, 0x31, + 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5A, 0x30, 0x81, + 0xC4, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x5A, 0x41, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, + 0x0C, 0x57, 0x65, 0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x43, 0x61, 0x70, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, + 0x43, 0x61, 0x70, 0x65, 0x20, 0x54, 0x6F, 0x77, 0x6E, 0x31, 0x1D, 0x30, + 0x1B, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x14, 0x54, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x63, 0x63, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, + 0x0B, 0x13, 0x1F, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x54, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, + 0x41, 0x31, 0x26, 0x30, 0x24, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x09, 0x01, 0x16, 0x17, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2D, 0x63, 0x65, 0x72, 0x74, 0x73, 0x40, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xD3, 0xA4, + 0x50, 0x6E, 0xC8, 0xFF, 0x56, 0x6B, 0xE6, 0xCF, 0x5D, 0xB6, 0xEA, 0x0C, + 0x68, 0x75, 0x47, 0xA2, 0xAA, 0xC2, 0xDA, 0x84, 0x25, 0xFC, 0xA8, 0xF4, + 0x47, 0x51, 0xDA, 0x85, 0xB5, 0x20, 0x74, 0x94, 0x86, 0x1E, 0x0F, 0x75, + 0xC9, 0xE9, 0x08, 0x61, 0xF5, 0x06, 0x6D, 0x30, 0x6E, 0x15, 0x19, 0x02, + 0xE9, 0x52, 0xC0, 0x62, 0xDB, 0x4D, 0x99, 0x9E, 0xE2, 0x6A, 0x0C, 0x44, + 0x38, 0xCD, 0xFE, 0xBE, 0xE3, 0x64, 0x09, 0x70, 0xC5, 0xFE, 0xB1, 0x6B, + 0x29, 0xB6, 0x2F, 0x49, 0xC8, 0x3B, 0xD4, 0x27, 0x04, 0x25, 0x10, 0x97, + 0x2F, 0xE7, 0x90, 0x6D, 0xC0, 0x28, 0x42, 0x99, 0xD7, 0x4C, 0x43, 0xDE, + 0xC3, 0xF5, 0x21, 0x6D, 0x54, 0x9F, 0x5D, 0xC3, 0x58, 0xE1, 0xC0, 0xE4, + 0xD9, 0x5B, 0xB0, 0xB8, 0xDC, 0xB4, 0x7B, 0xDF, 0x36, 0x3A, 0xC2, 0xB5, + 0x66, 0x22, 0x12, 0xD6, 0x87, 0x0D, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, + 0x13, 0x30, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, + 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x07, 0xFA, 0x4C, 0x69, 0x5C, 0xFB, 0x95, 0xCC, 0x46, + 0xEE, 0x85, 0x83, 0x4D, 0x21, 0x30, 0x8E, 0xCA, 0xD9, 0xA8, 0x6F, 0x49, + 0x1A, 0xE6, 0xDA, 0x51, 0xE3, 0x60, 0x70, 0x6C, 0x84, 0x61, 0x11, 0xA1, + 0x1A, 0xC8, 0x48, 0x3E, 0x59, 0x43, 0x7D, 0x4F, 0x95, 0x3D, 0xA1, 0x8B, + 0xB7, 0x0B, 0x62, 0x98, 0x7A, 0x75, 0x8A, 0xDD, 0x88, 0x4E, 0x4E, 0x9E, + 0x40, 0xDB, 0xA8, 0xCC, 0x32, 0x74, 0xB9, 0x6F, 0x0D, 0xC6, 0xE3, 0xB3, + 0x44, 0x0B, 0xD9, 0x8A, 0x6F, 0x9A, 0x29, 0x9B, 0x99, 0x18, 0x28, 0x3B, + 0xD1, 0xE3, 0x40, 0x28, 0x9A, 0x5A, 0x3C, 0xD5, 0xB5, 0xE7, 0x20, 0x1B, + 0x8B, 0xCA, 0xA4, 0xAB, 0x8D, 0xE9, 0x51, 0xD9, 0xE2, 0x4C, 0x2C, 0x59, + 0xA9, 0xDA, 0xB9, 0xB2, 0x75, 0x1B, 0xF6, 0x42, 0xF2, 0xEF, 0xC7, 0xF2, + 0x18, 0xF9, 0x89, 0xBC, 0xA3, 0xFF, 0x8A, 0x23, 0x2E, 0x70, 0x47 }; + static internal X509CertificateCollection coll; *************** *** 276,279 **** --- 344,348 ---- coll.Add (new X509Certificate (verisign)); coll.Add (new X509Certificate (verisign_ts_root)); + coll.Add (new X509Certificate (thawte)); } Index: X509Certificate.cs =================================================================== RCS file: /cvsroot/pgsqlclient/pgsqlclient_10/Mono.Security/Mono.Security/Mono.Security.X509/X509Certificate.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** X509Certificate.cs 10 Feb 2004 09:46:25 -0000 1.1 --- X509Certificate.cs 5 Mar 2004 23:18:17 -0000 1.2 *************** *** 120,124 **** // so we dont ask for a specific (Element) type and return DER ASN1 parameters = algorithm [1]; ! m_keyalgoparams = parameters.GetBytes (); ASN1 subjectPublicKey = subjectPublicKeyInfo.Element (1, 0x03); --- 120,124 ---- // so we dont ask for a specific (Element) type and return DER ASN1 parameters = algorithm [1]; ! m_keyalgoparams = ((algorithm.Count > 1) ? parameters.GetBytes () : null); ASN1 subjectPublicKey = subjectPublicKeyInfo.Element (1, 0x03); *************** *** 240,243 **** --- 240,244 ---- break; case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption + case "1.3.14.3.2.29": // SHA1 with RSA signature case "1.2.840.10040.4.3": // SHA1-1 with DSA hash = SHA1.Create (); *************** *** 312,315 **** --- 313,317 ---- case "1.2.840.113549.1.1.4": // MD5 with RSA encryption case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption + case "1.3.14.3.2.29": // SHA1 with RSA signature return signature; case "1.2.840.10040.4.3": // SHA-1 with DSA *************** *** 394,397 **** --- 396,400 ---- // SHA-1 with RSA Encryption case "1.2.840.113549.1.1.5": + case "1.3.14.3.2.29": v.SetHashAlgorithm ("SHA1"); break; Index: X509CertificateCollection.cs =================================================================== RCS file: /cvsroot/pgsqlclient/pgsqlclient_10/Mono.Security/Mono.Security/Mono.Security.X509/X509CertificateCollection.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** X509CertificateCollection.cs 10 Feb 2004 09:46:25 -0000 1.1 --- X509CertificateCollection.cs 5 Mar 2004 23:18:17 -0000 1.2 *************** *** 5,9 **** // Authors: // Lawrence Pit (lo...@ca...) ! // Sebastien Pouliot (spo...@mo...) // --- 5,9 ---- // Authors: // Lawrence Pit (lo...@ca...) ! // Sebastien Pouliot <seb...@xi...> // *************** *** 65,69 **** public bool Contains (X509Certificate value) { ! return InnerList.Contains (value); } --- 65,69 ---- public bool Contains (X509Certificate value) { ! return (IndexOf (value) != -1); } *************** *** 90,94 **** public int IndexOf (X509Certificate value) { ! return InnerList.IndexOf (value); } --- 90,103 ---- public int IndexOf (X509Certificate value) { ! if (value == null) ! throw new ArgumentNullException ("value"); ! ! byte[] hash = value.Hash; ! for (int i=0; i < InnerList.Count; i++) { ! X509Certificate x509 = (X509Certificate) InnerList [i]; ! if (Compare (x509.Hash, hash)) ! return i; ! } ! return -1; } *************** *** 103,109 **** } // Inner Class ! public class X509CertificateEnumerator : IEnumerator { private IEnumerator enumerator; --- 112,135 ---- } + // private stuff + + private bool Compare (byte[] array1, byte[] array2) + { + if ((array1 == null) && (array2 == null)) + return true; + if ((array1 == null) || (array2 == null)) + return false; + if (array1.Length != array2.Length) + return false; + for (int i=0; i < array1.Length; i++) { + if (array1 [i] != array2 [i]) + return false; + } + return true; + } + // Inner Class ! internal class X509CertificateEnumerator : IEnumerator { private IEnumerator enumerator; Index: X509Chain.cs =================================================================== RCS file: /cvsroot/pgsqlclient/pgsqlclient_10/Mono.Security/Mono.Security/Mono.Security.X509/X509Chain.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** X509Chain.cs 10 Feb 2004 09:46:25 -0000 1.1 --- X509Chain.cs 5 Mar 2004 23:18:17 -0000 1.2 *************** *** 1,13 **** // // X509Chain.cs: X.509 Certificate Path ! // This is a VERY simplified and minimal version (for Authenticode support) // // Author: ! // Sebastien Pouliot (spo...@mo...) // // (C) 2003 Motus Technologies Inc. (http://www.motus.com) // using System; namespace Mono.Security.X509 { --- 1,20 ---- // // X509Chain.cs: X.509 Certificate Path ! // This is a VERY simplified and minimal version ! // used for ! // Authenticode support ! // TLS/SSL support // // Author: ! // Sebastien Pouliot <seb...@xi...> // // (C) 2003 Motus Technologies Inc. (http://www.m... [truncated message content] |