Author: spouliot
Date: 2006-12-07 16:13:23 -0500 (Thu, 07 Dec 2006)
New Revision: 69204

Modified:
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/ChangeLog
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X500DistinguishedName.cs
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Chain.cs
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElement.cs
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
   
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Store.cs
Log:
2006-12-07  Sebastien Pouliot  <[EMAIL PROTECTED]>

        * X500DistinguishedName.cs: Add an internal method to compare 
        (canonized) DN so the class can be used in X509Chain.
        * X509Certificate2.cs: Expose the internal certificate (from Mono.
        Security.dll) as X509Certificate2 isn't complete enough to implement
        chaining.
        * X509Chain.cs: A (working) *subset( of RFC3280 path building and 
        validation. 
        * X509ChainElementCollection.cs: Add help method Contains and change
        Add not to require a flag parameter.
        * X509ChainElement.cs: Keeps flags compressed (as flags!) and add
        a method to uncompress them when validation is complete.
        * X509Store.cs: Expose the internal store (from Mono.Security.dll) as
        internal. Map Trust and Root as the same store (for compatibility).



Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/ChangeLog
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/ChangeLog  
    2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/ChangeLog  
    2006-12-07 21:13:23 UTC (rev 69204)
@@ -1,3 +1,19 @@
+2006-12-07  Sebastien Pouliot  <[EMAIL PROTECTED]>
+
+       * X500DistinguishedName.cs: Add an internal method to compare 
+       (canonized) DN so the class can be used in X509Chain.
+       * X509Certificate2.cs: Expose the internal certificate (from Mono.
+       Security.dll) as X509Certificate2 isn't complete enough to implement
+       chaining.
+       * X509Chain.cs: A (working) *subset( of RFC3280 path building and 
+       validation. 
+       * X509ChainElementCollection.cs: Add help method Contains and change
+       Add not to require a flag parameter.
+       * X509ChainElement.cs: Keeps flags compressed (as flags!) and add
+       a method to uncompress them when validation is complete.
+       * X509Store.cs: Expose the internal store (from Mono.Security.dll) as
+       internal. Map Trust and Root as the same store (for compatibility).
+
 2006-11-24  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
        * X509Certificate2.cs: Modified Verify to use CryptoConfig to create

Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X500DistinguishedName.cs
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X500DistinguishedName.cs
       2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X500DistinguishedName.cs
       2006-12-07 21:13:23 UTC (rev 69204)
@@ -176,6 +176,51 @@
                        ASN1 sequence = new ASN1 (RawData);
                        name = MX.X501.ToString (sequence, true, ", ", true);
                }
+
+               private static string Canonize (string s)
+               {
+                       int i = s.IndexOf ('=');
+                       StringBuilder r = new StringBuilder (s.Substring (0, i 
+ 1));
+                       // skip any white space starting the value
+                       while (Char.IsWhiteSpace (s, ++i));
+                       // ensure we skip white spaces at the end of the value
+                       s = s.TrimEnd ();
+                       // keep track of internal multiple spaces
+                       bool space = false;
+                       for (; i < s.Length; i++) {
+                               if (space) {
+                                       space = Char.IsWhiteSpace (s, i);
+                                       if (space)
+                                               continue;
+                               }
+                               if (Char.IsWhiteSpace (s, i))
+                                       space = true;
+                               r.Append (Char.ToUpperInvariant (s[i]));
+                       }
+                       return r.ToString ();
+               }
+
+               // of all X500DistinguishedNameFlags flags nothing can do a 
"correct" comparison :|
+               internal static bool AreEqual (X500DistinguishedName name1, 
X500DistinguishedName name2)
+               {
+                       if (name1 == null)
+                               return (name2 == null);
+                       if (name2 == null)
+                               return false;
+
+                       X500DistinguishedNameFlags flags = 
X500DistinguishedNameFlags.UseNewLines | 
X500DistinguishedNameFlags.DoNotUseQuotes;
+                       string[] split = new string[] { Environment.NewLine };
+                       string[] parts1 = name1.Decode (flags).Split (split, 
StringSplitOptions.RemoveEmptyEntries);
+                       string[] parts2 = name2.Decode (flags).Split (split, 
StringSplitOptions.RemoveEmptyEntries);
+                       if (parts1.Length != parts2.Length)
+                               return false;
+
+                       for (int i = 0; i < parts1.Length; i++) {
+                               if (Canonize (parts1[i]) != Canonize 
(parts2[i]))
+                                       return false;
+                       }
+                       return true;
+               }
        }
 }
 

Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
    2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
    2006-12-07 21:13:23 UTC (rev 69204)
@@ -632,6 +632,13 @@
                        byte[] data = Load (fileName);
                        return GetCertContentType (data);
                }
+
+               // internal stuff because X509Certificate2 isn't complete enough
+               // (maybe X509Certificate3 will be better?)
+
+               internal MX.X509Certificate MonoCertificate {
+                       get { return _cert; }
+               }
        }
 }
 

Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Chain.cs
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Chain.cs
   2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Chain.cs
   2006-12-07 21:13:23 UTC (rev 69204)
@@ -30,12 +30,14 @@
 #if NET_2_0 && SECURITY_DEP
 
 using System.Collections;
+using System.Text;
 
+using MX = Mono.Security.X509;
+
 namespace System.Security.Cryptography.X509Certificates {
 
        public class X509Chain {
 
-               // Set to internal to remove a warning
                private StoreLocation location;
                private X509ChainElementCollection elements;
                private X509ChainPolicy policy;
@@ -43,6 +45,15 @@
 
                static X509ChainStatus[] Empty = new X509ChainStatus [0];
 
+               // RFC3280 variables
+               private int max_path_length;
+               private X500DistinguishedName working_issuer_name;
+               private string working_public_key_algorithm;
+               private AsymmetricAlgorithm working_public_key;
+
+               // other flags
+               private X509ChainElement bce_restriction;
+
                // constructors
 
                public X509Chain ()
@@ -90,28 +101,32 @@
 
                // methods
 
-               [MonoTODO ("Work in progress")]
+               [MonoTODO ("Not totally RFC3280 compliant, but neither is MS 
implementation...")]
                public bool Build (X509Certificate2 certificate)
                {
                        if (certificate == null)
                                throw new ArgumentException ("certificate");
 
                        Reset ();
-
                        X509ChainStatusFlags flag;
                        try {
-                               flag = BuildFrom (certificate);
+                               flag = BuildChainFrom (certificate);
+                               ValidateChain (flag);
                        }
                        catch (CryptographicException ce) {
                                throw new ArgumentException ("certificate", ce);
                        }
 
+                       X509ChainStatusFlags total = 
X509ChainStatusFlags.NoError;
                        ArrayList list = new ArrayList ();
                        // build "global" ChainStatus from the ChainStatus of 
every ChainElements
-                       foreach (X509ChainElement ce in elements) {
-                               foreach (X509ChainStatus cs in 
ce.ChainElementStatus) {
-                                       // FIXME - avoid duplicates ?
-                                       list.Add (cs);
+                       foreach (X509ChainElement ce in elements) {
+                               foreach (X509ChainStatus cs in 
ce.ChainElementStatus) {
+                                       // we MUST avoid duplicates in the 
"global" list
+                                       if ((total & cs.Status) != cs.Status) {
+                                               list.Add (cs);
+                                               total |= cs.Status;
+                                       }
                                }
                        }
                        // and if required add some
@@ -121,7 +136,7 @@
                        status = (X509ChainStatus[]) list.ToArray (typeof 
(X509ChainStatus));
 
                        // (fast path) this ignore everything we have checked
-                       if (ChainPolicy.VerificationFlags == 
X509VerificationFlags.AllFlags)
+                       if ((status.Length == 0) || 
(ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
                                return true;
 
                        bool result = true;
@@ -185,11 +200,22 @@
 
                public void Reset () 
                {
+                       // note: this call doesn't Reset the X509ChainPolicy
                        if ((status != null) && (status.Length != 0))
                                status = null;
                        if (elements.Count > 0)
-                               elements.Clear ();
-                       // note: this call doesn't Reset the X509ChainPolicy
+                               elements.Clear ();
+                       if (roots != null) {
+                               roots.Close ();
+                               roots = null;
+                       }
+                       if (cas != null) {
+                               cas.Close ();
+                               cas = null;
+                       }
+                       collection = null;
+                       bce_restriction = null;
+                       working_public_key = null;
                }
 
                // static methods
@@ -201,155 +227,637 @@
 
                // private stuff
 
-               private X509ChainStatusFlags BuildFrom (X509Certificate2 
certificate)
-               {
-                       X509ChainStatusFlags result = 
X509ChainStatusFlags.NoError;
-                       X509ChainStatusFlags flags = 
X509ChainStatusFlags.NoError;
+               private X509Store roots;
+               private X509Store cas;
+
+               private X509Store Roots {
+                       get {
+                               if (roots == null) {
+                                       roots = new X509Store (StoreName.Root, 
location);
+                                       roots.Open (OpenFlags.ReadOnly);
+                               }
+                               return roots;
+                       }
+               }
 
-                       // check certificate
-                       Process (certificate, ref flags);
+               private X509Store CertificateAuthorities {
+                       get {
+                               if (cas == null) {
+                                       cas = new X509Store 
(StoreName.CertificateAuthority, location);
+                                       cas.Open (OpenFlags.ReadOnly);
+                               }
+                               return cas;
+                       }
+               }
 
-                       // check if certificate is self-signed
-                       if (IsSelfSigned (certificate)) {
-                               // FIXME - add support for cross-certificate, 
bridges
-                               ProcessRoot (certificate, ref flags);
-                       } else {
-                               CheckRevocation (certificate, ref flags);
+               // *** certificate chain/path building stuff ***
 
-                               X509Certificate2 parent = FindParent 
(certificate, ref flags);
-                               if (parent != null) {
-                                       // recurse
-                                       result = BuildFrom (parent);
-                                       if (result != 
X509ChainStatusFlags.NoError)
-                                               return result;
-                               } else {
-                                       // we didn't end with a root, nor could 
we find one (stores)
-                                       result = 
X509ChainStatusFlags.PartialChain;
+               private X509Certificate2Collection collection;
+
+               // we search local user (default) or machine certificate store 
+               // and in the extra certificate supplied in 
ChainPolicy.ExtraStore
+               private X509Certificate2Collection CertificateCollection {
+                       get {
+                               if (collection == null) {
+                                       collection = new 
X509Certificate2Collection (ChainPolicy.ExtraStore);
+                                       if (Roots.Certificates.Count > 0)
+                                               collection.AddRange 
(Roots.Certificates);
+                                       if 
(CertificateAuthorities.Certificates.Count > 0)
+                                               collection.AddRange 
(CertificateAuthorities.Certificates);
                                }
-                       }
-                       elements.Add (certificate, flags);
-                       return result;
+                               return collection;
+                       }
                }
 
-               private void Process (X509Certificate2 certificate, ref 
X509ChainStatusFlags flags)
+               // This is a non-recursive chain/path building algorithm. 
+               //
+               // At this stage we only checks for PartialChain, Cyclic and 
UntrustedRoot errors are they
+               // affect the path building (other errors are verification 
errors).
+               //
+               // Note that the order match the one we need to match MS and 
not the one defined in RFC3280,
+               // we also include the trusted root certificate (trust anchor 
in RFC3280) in the list.
+               // (this isn't an issue, just keep that in mind if you look at 
the source and the RFC)
+               private X509ChainStatusFlags BuildChainFrom (X509Certificate2 
certificate)
                {
-                       // is it the end-entity ?
-                       if (elements.Count == 0) {
-                       }
-
-                       if ((ChainPolicy.VerificationTime < 
certificate.NotBefore) ||
-                               (ChainPolicy.VerificationTime > 
certificate.NotAfter)) {
-                               flags |= X509ChainStatusFlags.NotTimeValid;
+                       elements.Add (certificate);
+
+                       while (!IsChainComplete (certificate)) {
+                               certificate = FindParent (certificate);
+
+                               if (certificate == null)
+                                       return 
X509ChainStatusFlags.PartialChain;
+
+                               if (elements.Contains (certificate))
+                                       return X509ChainStatusFlags.Cyclic;
+
+                               elements.Add (certificate);
                        }
 
-                       // TODO - for X509ChainStatusFlags.NotTimeNested (needs 
global structure)
-
-                       // TODO - for X509ChainStatusFlags.InvalidExtension
+                       // roots may be supplied (e.g. in the ExtraStore) so we 
need to confirm their
+                       // trustiness (what a cute word) in the trusted root 
collection
+                       if (!Roots.Certificates.Contains (certificate))
+                               elements [elements.Count - 1].StatusFlags |= 
X509ChainStatusFlags.UntrustedRoot;
 
-                       // TODO - check for 
X509ChainStatusFlags.InvalidBasicConstraint
+                       return X509ChainStatusFlags.NoError;
+               }
 
-                       // TODO - for 
X509ChainStatusFlags.InvalidPolicyConstraints
-                       //      using X509ChainPolicy.ApplicationPolicy and 
X509ChainPolicy.CertificatePolicy
 
-                       // TODO - check for 
X509ChainStatusFlags.NoIssuanceChainPolicy
+               private X509Certificate2 SelectBestFromCollection 
(X509Certificate2 child, X509Certificate2Collection c)
+               {
+                       switch (c.Count) {
+                       case 0:
+                               return null;
+                       case 1:
+                               return c [0];
+                       default:
+                               // multiple candidate, keep only the ones that 
are still valid
+                               X509Certificate2Collection time_valid = c.Find 
(X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
+                               switch (time_valid.Count) {
+                               case 0:
+                                       // that's too restrictive, let's revert 
and try another thing...
+                                       time_valid = c;
+                                       break;
+                               case 1:
+                                       return time_valid [0];
+                               default:
+                                       break;
+                               }
 
-                       // TODO - check for 
X509ChainStatusFlags.InvalidNameConstraint
-                       // TODO - check for 
X509ChainStatusFlags.HasNotSupportedNameConstraint
-                       // TODO - check for 
X509ChainStatusFlags.HasNotPermittedNameConstraint
-                       // TODO - check for 
X509ChainStatusFlags.HasExcludedNameConstraint
+                               // again multiple candidates, let's find the 
AKI that match the SKI (if we have one)
+                               string aki = GetAuthorityKeyIdentifier (child);
+                               if ((aki == null) || (aki.Length == 0)) {
+                                       return time_valid [0]; // FIXME: out of 
luck, you get the first one
+                               }
+                               foreach (X509Certificate2 parent in time_valid) 
{
+                                       string ski = GetSubjectKeyIdentifier 
(parent);
+                                       // if both id are available then they 
must match
+                                       if (aki == ski)
+                                               return parent;
+                               }
+                               return time_valid [0]; // FIXME: out of luck, 
you get the first one
+                       }
+               }
+
+               private X509Certificate2 FindParent (X509Certificate2 
certificate)
+               {
+                       X509Certificate2Collection subset = 
CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, 
certificate.Issuer, false);
+                       string aki = GetAuthorityKeyIdentifier (certificate);
+                       if ((aki != null) && (aki.Length > 0)) {
+                               subset.AddRange (CertificateCollection.Find 
(X509FindType.FindBySubjectKeyIdentifier, aki, false));
+                       }
+                       X509Certificate2 parent = SelectBestFromCollection 
(certificate, subset);
+                       // if parent==certificate we're looping but it's not 
(probably) a bug and not a true cyclic (over n certs)
+                       return certificate.Equals (parent) ? null : parent;
                }
 
-               private void ProcessEndEntity (X509Certificate2 certificate, 
ref X509ChainStatusFlags flags)
+               private bool IsChainComplete (X509Certificate2 certificate)
                {
+                       // the chain is complete if we have a self-signed 
certificate
+                       if (!IsSelfIssued (certificate))
+                               return false;
+
+                       // we're very limited to what we can do without 
certificate extensions
+                       if (certificate.Version < 3)
+                               return true;
+
+                       // check that Authority Key Identifier == Subject Key 
Identifier
+                       // e.g. it will be different if a self-signed 
certificate is part (not the end) of the chain
+                       string ski = GetSubjectKeyIdentifier (certificate);
+                       if ((ski == null) || (ski.Length == 0))
+                               return true;
+                       string aki = GetAuthorityKeyIdentifier (certificate);
+                       if ((aki == null) || (aki.Length == 0))
+                               return true;
+                       // if both id are available then they must match
+                       return (aki == ski);
                }
 
-               private void ProcessCertificateAuthority (X509Certificate2 
certificate, ref X509ChainStatusFlags flags)
+               // check for "self-issued" certificate - without verifying the 
signature
+               // note that self-issued doesn't always mean it's a root 
certificate!
+               private bool IsSelfIssued (X509Certificate2 certificate)
+               {
+                       return (certificate.Issuer == certificate.Subject);
+               }
+
+
+               // *** certificate chain/path validation stuff ***
+
+               // Currently a subset of RFC3280 (hopefully a full 
implementation someday)
+               private void ValidateChain (X509ChainStatusFlags flag)
                {
+                       // 'n' should be the root certificate... 
+                       int n = elements.Count - 1;
+                       X509Certificate2 certificate = elements [n].Certificate;
+
+                       // ... and, if so, must be treated outside the chain... 
+                       if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
+                               Process (n);
+                               // deal with the case where the chain == the 
root certificate 
+                               // (which isn't for RFC3280) part of the chain
+                               if (n == 0) {
+                                       elements [0].UncompressFlags ();
+                                       return;
+                               }
+                               // skip the root certificate when processing 
the chain (in 6.1.3)
+                               n--;
+                       }
+                       // ... unless the chain is a partial one (then we start 
with that one)
+
+                       // 6.1.1 - Inputs
+                       // 6.1.1.a - a prospective certificate path of length n 
(i.e. elements)
+                       // 6.1.1.b - the current date/time (i.e. 
ChainPolicy.VerificationTime)
+                       // 6.1.1.c - user-initial-policy-set (i.e. 
ChainPolicy.CertificatePolicy)
+                       // 6.1.1.d - the trust anchor information (i.e. 
certificate, unless it's a partial chain)
+                       // 6.1.1.e - initial-policy-mapping-inhibit (NOT 
SUPPORTED BY THE API)
+                       // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY 
THE API)
+                       // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED 
BY THE API)
+
+                       // 6.1.2 - Initialization (incomplete)
+                       // 6.1.2.a-f - policy stuff, some TODO, some not 
supported
+                       // 6.1.2.g - working public key algorithm
+                       working_public_key_algorithm = 
certificate.PublicKey.Oid.Value;
+                       // 6.1.2.h-i - our key contains both the "working 
public key" and "working public key parameters" data
+                       working_public_key = certificate.PublicKey.Key;
+                       // 6.1.2.j - working issuer name
+                       working_issuer_name = certificate.IssuerName;
+                       // 6.1.2.k - this integer is initialized to n, is 
decremented for each non-self-issued, certificate and
+                       //           may be reduced to the value in the path 
length constraint field
+                       max_path_length = n;
+
+                       // 6.1.3 - Basic Certificate Processing
+                       // note: loop looks reversed (the list is) but we 
process this part just like RFC3280 does
+                       for (int i = n; i > 0; i--) {
+                               Process (i);
+                               // 6.1.4 - preparation for certificate i+1 (for 
not with i+1, or i-1 in our loop)
+                               PrepareForNextCertificate (i);
+                       }
+                       Process (0);
+
+                       // 6.1.3.a.3 - revocation checks
+                       CheckRevocationOnChain (flag);
+
+                       // 6.1.5 - Wrap-up procedure
+                       WrapUp ();
                }
 
-               // CTL == Certificate Trust List / not sure how/if they apply 
here
-               private void ProcessCTL (X509Certificate2 certificate, ref 
X509ChainStatusFlags flags)
+               private void Process (int n)
                {
-                       // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
-                       // TODO - check for 
X509ChainStatusFlags.CtlNotSignatureValid
-                       // TODO - check for 
X509ChainStatusFlags.CtlNotValidForUsage
+                       X509ChainElement element = elements [n];
+                       X509Certificate2 certificate = element.Certificate;
+
+                       // pre-step: DSA certificates may inherit the 
parameters of their CA
+                       if ((n != elements.Count - 1) && 
(certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
+                               if 
(certificate.MonoCertificate.KeyAlgorithmParameters == null) {
+                                       X509Certificate2 parent = elements 
[n+1].Certificate;
+                                       
certificate.MonoCertificate.KeyAlgorithmParameters = 
parent.MonoCertificate.KeyAlgorithmParameters;
+                               }
+                       }
+
+                       bool root = (working_public_key == null);
+                       // 6.1.3.a.1 - check signature (with special case to 
deal with root certificates)
+                       if (!IsSignedWith (certificate, root ? 
certificate.PublicKey.Key : working_public_key)) {
+                               // another special case where only an 
end-entity is available and can't be verified.
+                               // In this case we do not report an invalid 
signature (since this is unknown)
+                               if (root || (n != elements.Count - 1) || 
IsSelfIssued (certificate)) {
+                                       element.StatusFlags |= 
X509ChainStatusFlags.NotSignatureValid;
+                               }
+                       }
+
+                       // 6.1.3.a.2 - check validity period
+                       if ((ChainPolicy.VerificationTime < 
certificate.NotBefore) ||
+                               (ChainPolicy.VerificationTime > 
certificate.NotAfter)) {
+                               element.StatusFlags |= 
X509ChainStatusFlags.NotTimeValid;
+                       }
+                       // TODO - for X509ChainStatusFlags.NotTimeNested (needs 
global structure)
+
+                       // note: most of them don't apply to the root 
certificate
+                       if (root) {
+                               return;
+                       }
+
+                       // 6.1.3.a.3 - revocation check (we're doing at the 
last stage)
+                       // note: you revoke a trusted root by removing it from 
your trusted store (i.e. no CRL can do this job)
+
+                       // 6.1.3.a.4 - check certificate issuer name
+                       if (!X500DistinguishedName.AreEqual 
(certificate.IssuerName, working_issuer_name)) {
+                               // NOTE: this is not the "right" error flag, 
but it's the closest one defined
+                               element.StatusFlags |= 
X509ChainStatusFlags.InvalidNameConstraints;
+                       }
+
+                       if (!IsSelfIssued (certificate) && (n != 0)) {
+                               // TODO 6.1.3.b - subject name in the 
permitted_subtrees ...
+                               // TODO 6.1.3.c - subject name not within 
excluded_subtrees...
+
+                               // TODO - check for 
X509ChainStatusFlags.InvalidNameConstraint
+                               // TODO - check for 
X509ChainStatusFlags.HasNotSupportedNameConstraint
+                               // TODO - check for 
X509ChainStatusFlags.HasNotPermittedNameConstraint
+                               // TODO - check for 
X509ChainStatusFlags.HasExcludedNameConstraint
+                       }
+
+                       // TODO 6.1.3.d - check if certificate policies 
extension is present
+                       if (false) {
+                               // TODO - for 
X509ChainStatusFlags.InvalidPolicyConstraints
+                               //      using X509ChainPolicy.ApplicationPolicy 
and X509ChainPolicy.CertificatePolicy
+
+                               // TODO - check for 
X509ChainStatusFlags.NoIssuanceChainPolicy
+
+                       } else {
+                               // TODO 6.1.3.e - set valid_policy_tree to NULL
+                       }
+
+                       // TODO 6.1.3.f - verify explict_policy > 0 if 
valid_policy_tree != NULL
                }
 
-               private void ProcessRoot (X509Certificate2 certificate, ref 
X509ChainStatusFlags flags)
+               // CTL == Certificate Trust List / NOT SUPPORTED
+               // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
+               // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
+               // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
+
+               private void PrepareForNextCertificate (int n) 
                {
-                       X509Store trust = new X509Store (StoreName.Root, 
location);
-                       trust.Open (OpenFlags.ReadOnly);
-                       if (!trust.Certificates.Contains (certificate)) {
-                               flags |= X509ChainStatusFlags.UntrustedRoot;
+                       X509ChainElement element = elements [n];
+                       X509Certificate2 certificate = element.Certificate;
+
+                       // TODO 6.1.4.a-b
+
+                       // 6.1.4.c
+                       working_issuer_name = certificate.SubjectName;
+                       // 6.1.4.d-e - our key includes both the public key and 
it's parameters
+                       working_public_key = certificate.PublicKey.Key;
+                       // 6.1.4.f
+                       working_public_key_algorithm = 
certificate.PublicKey.Oid.Value;
+
+                       // TODO 6.1.4.g-j
+
+                       // 6.1.4.k - Verify that the certificate is a CA 
certificate
+                       X509BasicConstraintsExtension bce = 
(X509BasicConstraintsExtension) certificate.Extensions["2.5.29.19"];
+                       if (bce != null) {
+                               if (!bce.CertificateAuthority) {
+                                       element.StatusFlags |= 
X509ChainStatusFlags.InvalidBasicConstraints;
+                               }
+                       } else if (certificate.Version >= 3) {
+                               // recent (v3+) CA certificates must include BCE
+                               element.StatusFlags |= 
X509ChainStatusFlags.InvalidBasicConstraints;
                        }
-                       trust.Close ();
 
-                       if (!IsSignedBy (certificate, certificate)) {
-                               flags |= X509ChainStatusFlags.NotSignatureValid;
+                       // 6.1.4.l - if the certificate isn't self-issued...
+                       if (!IsSelfIssued (certificate)) {
+                               // ... verify that max_path_length > 0
+                               if (max_path_length > 0) {
+                                       max_path_length--;
+                               } else {
+                                       // to match MS the reported status must 
be against the certificate 
+                                       // with the BCE and not where the path 
is too long. It also means
+                                       // that this condition has to be 
reported only once
+                                       if (bce_restriction != null) {
+                                               bce_restriction.StatusFlags |= 
X509ChainStatusFlags.InvalidBasicConstraints;
+                                       }
+                               }
                        }
+
+                       // 6.1.4.m - if pathLengthConstraint is present...
+                       if ((bce != null) && (bce.HasPathLengthConstraint)) {
+                               // ... and is less that max_path_length, set 
max_path_length to it's value
+                               if (bce.PathLengthConstraint < max_path_length) 
{
+                                       max_path_length = 
bce.PathLengthConstraint;
+                                       bce_restriction = element;
+                               }
+                       }
+
+                       // 6.1.4.n - if key usage extension is present...
+                       X509KeyUsageExtension kue = (X509KeyUsageExtension) 
certificate.Extensions["2.5.29.15"];
+                       if (kue != null) {
+                               // ... verify keyCertSign is set
+                               X509KeyUsageFlags success = 
X509KeyUsageFlags.KeyCertSign;
+                               if ((kue.KeyUsages & success) != success)
+                                       element.StatusFlags |= 
X509ChainStatusFlags.NotValidForUsage;
+                       }
+
+                       // 6.1.4.o - recognize and process other critical 
extension present in the certificate
+                       ProcessCertificateExtensions (element);
                }
 
-               // we search local user (default) or machine certificate store 
-               // and in the extra certificate supplied in 
ChainPolicy.ExtraStore
-               private X509Certificate2 FindParent (X509Certificate2 
certificate, ref X509ChainStatusFlags flags)
+               private void WrapUp ()
                {
-                       X509Certificate2 parent = null;
+                       X509ChainElement element = elements [0];
+                       X509Certificate2 certificate = element.Certificate;
 
-                       // TODO - check for X509ChainStatusFlags.Cyclic
+                       // 6.1.5.a - TODO if certificate n (our 0) wasn't self 
issued and explicit_policy != 0
+                       if (IsSelfIssued (certificate)) {
+                               // TODO... decrement explicit_policy by 1
+                       }
 
-                       if ((parent != null) && !IsSignedBy (certificate, 
parent)) {
-                               flags |= X509ChainStatusFlags.NotSignatureValid;
+                       // 6.1.5.b - TODO
+
+                       // 6.1.5.c,d,e - not required by the X509Chain 
implementation
+
+                       // 6.1.5.f - recognize and process other critical 
extension present in the certificate
+                       ProcessCertificateExtensions (element);
+
+                       // 6.1.5.g - TODO
+
+                       // uncompressed the flags into several elements
+                       for (int i = elements.Count - 1; i >= 0; i--) {
+                               elements [i].UncompressFlags ();
                        }
-                       return null;
                }
 
-               // check for "self-signed" certificate - without verifying the 
signature
-               private bool IsSelfSigned (X509Certificate2 certificate)
-               {
-                       // FIXME - very incomplete
-                       return (certificate.Issuer == certificate.Subject);
+               private void ProcessCertificateExtensions (X509ChainElement 
element)
+               {
+                       foreach (X509Extension ext in 
element.Certificate.Extensions) {
+                               if (ext.Critical) {
+                                       switch (ext.Oid.Value) {
+                                       case "2.5.29.15": // 
X509KeyUsageExtension
+                                       case "2.5.29.19": // 
X509BasicConstraintsExtension
+                                               // we processed this extension
+                                               break;
+                                       default:
+                                               // note: Under Windows XP MS 
implementation seems to ignore 
+                                               // certificate with unknown 
critical extensions.
+                                               element.StatusFlags |= 
X509ChainStatusFlags.InvalidExtension;
+                                               break;
+                                       }
+                               }
+                       }
                }
 
-               // this method verify the signature
-               private bool IsSignedBy (X509Certificate2 signed, 
X509Certificate2 signer)
-               {
-                       // FIXME
-                       return true;
+               private bool IsSignedWith (X509Certificate2 signed, 
AsymmetricAlgorithm pubkey)
+               {
+                       if (pubkey == null)
+                               return false;
+                       // Sadly X509Certificate2 doesn't expose the signature 
nor the tbs (to be signed) structure
+                       MX.X509Certificate mx = signed.MonoCertificate;
+                       return (mx.VerifySignature (pubkey));
+               }
+
+               private string GetSubjectKeyIdentifier (X509Certificate2 
certificate)
+               {
+                       X509SubjectKeyIdentifierExtension ski = 
(X509SubjectKeyIdentifierExtension) certificate.Extensions["2.5.29.14"];
+                       return (ski == null) ? String.Empty : 
ski.SubjectKeyIdentifier;
+               }
+
+               // System.dll v2 doesn't have a class to deal with the 
AuthorityKeyIdentifier extension
+               private string GetAuthorityKeyIdentifier (X509Certificate2 
certificate)
+               {
+                       return GetAuthorityKeyIdentifier 
(certificate.MonoCertificate.Extensions ["2.5.29.35"]);
                }
-
-               private void CheckRevocation (X509Certificate2 certificate, ref 
X509ChainStatusFlags flags)
-               {
+
+               // but anyway System.dll v2 doesn't expose CRL in any way so...
+               private string GetAuthorityKeyIdentifier (MX.X509Crl crl)
+               {
+                       return GetAuthorityKeyIdentifier (crl.Extensions 
["2.5.29.35"]);
+               }
+
+               private string GetAuthorityKeyIdentifier (MX.X509Extension ext)
+               {
+                       if (ext == null)
+                               return String.Empty;
+                       MX.Extensions.AuthorityKeyIdentifierExtension aki = new 
MX.Extensions.AuthorityKeyIdentifierExtension (ext);
+                       byte[] id = aki.Identifier;
+                       if (id == null) 
+                               return String.Empty;
+                       StringBuilder sb = new StringBuilder ();
+                       foreach (byte b in id)
+                               sb.Append (b.ToString ("X02"));
+                       return sb.ToString ();
+               }
+
+               // we check the revocation only once we have built the complete 
chain
+               private void CheckRevocationOnChain (X509ChainStatusFlags flag)
+               {
+                       bool partial = ((flag & 
X509ChainStatusFlags.PartialChain) != 0);
+                       bool online;
+
                        switch (ChainPolicy.RevocationMode) {
                        case X509RevocationMode.Online:
-                               // local?/download CRL and OCSP
-                               CheckOnlineRevocation (certificate, ref flags);
+                               // default
+                               online = true;
                                break;
-                       case X509RevocationMode.Offline:
-                               // only local CRL ?
-                               CheckOfflineRevocation (certificate, ref flags);
+                       case X509RevocationMode.Offline:
+                               online = false;
                                break;
-                       case X509RevocationMode.NoCheck:
-                               break;
+                       case X509RevocationMode.NoCheck:
+                               return;
                        default:
-                               throw new InvalidOperationException ();
+                               throw new InvalidOperationException 
(Locale.GetText ("Invalid revocation mode."));
                        }
+
+                       bool unknown = partial;
+                       // from the root down to the end-entity
+                       for (int i = elements.Count - 1; i >= 0; i--) {
+                               bool check = true;
+
+                               switch (ChainPolicy.RevocationFlag) {
+                               case X509RevocationFlag.EndCertificateOnly:
+                                       check = (i == 0);
+                                       break;
+                               case X509RevocationFlag.EntireChain:
+                                       check = true;
+                                       break;
+                               case X509RevocationFlag.ExcludeRoot:
+                                       // default
+                                       check = (i != (elements.Count - 1));
+                                       // anyway, who's gonna sign that the 
root is invalid ?
+                                       break;
+                               }
+
+                               X509ChainElement element = elements [i];
+
+                               // we can't assume the revocation status if the 
certificate is bad (e.g. invalid signature)
+                               if (!unknown)
+                                       unknown |= ((element.StatusFlags & 
X509ChainStatusFlags.NotSignatureValid) != 0);
+
+                               if (unknown) {
+                                       // we can skip the revocation checks as 
we can't be sure of them anyway
+                                       element.StatusFlags |= 
X509ChainStatusFlags.RevocationStatusUnknown;
+                                       element.StatusFlags |= 
X509ChainStatusFlags.OfflineRevocation;
+                               } else if (check && !partial && !IsSelfIssued 
(element.Certificate)) {
+                                       // check for revocation (except for the 
trusted root and self-issued certs)
+                                       element.StatusFlags |= CheckRevocation 
(element.Certificate, i+1, online);
+                                       // if revoked, then all others 
following in the chain are unknown...
+                                       unknown |= ((element.StatusFlags & 
X509ChainStatusFlags.Revoked) != 0);
+                               }
+                       }
                }
 
-               private void CheckOfflineRevocation (X509Certificate2 
certificate, ref X509ChainStatusFlags flags)
-               {
-                       // TODO - check for X509ChainStatusFlags.Revoked
-                       // TODO - check for 
X509ChainStatusFlags.RevocationStatusUnknown
-                       // TODO - check for 
X509ChainStatusFlags.OfflineRevocation
-                       //       (using X509ChainPolicy.RevocationFlag and 
X509ChainPolicy.RevocationMode)
-               }
+               // This isn't how RFC3280 (section 6.3) deals with CRL, but 
then we don't (yet) support DP, deltas...
+               private X509ChainStatusFlags CheckRevocation (X509Certificate2 
certificate, int ca, bool online)
+               {
+                       X509ChainStatusFlags result = 
X509ChainStatusFlags.RevocationStatusUnknown;
+                       X509ChainElement element = elements [ca];
+                       X509Certificate2 ca_cert = element.Certificate;
+
+                       // find the CRL from the "right" CA
+                       while (IsSelfIssued (ca_cert) && (ca < elements.Count - 
1)) {
+                               // try with this self-issued
+                               result = CheckRevocation (certificate, ca_cert, 
online);
+                               if (result != 
X509ChainStatusFlags.RevocationStatusUnknown)
+                                       break;
+                               ca++;
+                               element = elements [ca];
+                               ca_cert = element.Certificate;
+                       }
+                       if (result == 
X509ChainStatusFlags.RevocationStatusUnknown)
+                               result = CheckRevocation (certificate, ca_cert, 
online);
+                       return result;
+               }
+
+               private X509ChainStatusFlags CheckRevocation (X509Certificate2 
certificate, X509Certificate2 ca_cert, bool online)
+               {
+                       // change this if/when we support OCSP
+                       X509KeyUsageExtension kue = (X509KeyUsageExtension) 
ca_cert.Extensions["2.5.29.15"];
+                       if (kue != null) {
+                               // ... verify CrlSign is set
+                               X509KeyUsageFlags success = 
X509KeyUsageFlags.CrlSign;
+                               if ((kue.KeyUsages & success) != success) {
+                                       // FIXME - we should try to find an 
alternative CA that has the CrlSign bit
+                                       return 
X509ChainStatusFlags.RevocationStatusUnknown;
+                               }
+                       }
+
+                       MX.X509Crl crl = FindCrl (ca_cert);
+
+                       if ((crl == null) && online) {
+                               // FIXME - download and install new CRL
+                               // then you get a second chance
+                               // crl = FindCrl (ca_cert, ref valid, ref 
out_of_date);
+                       }
+
+                       if (crl != null) {
+                               // validate the digital signature on the CRL 
using the CA public key
+                               // note #1: we can't use 
X509Crl.VerifySignature(X509Certificate) because it duplicates
+                               // checks and we loose the "why" of the failure
+                               // note #2: we do this before other tests as an 
invalid signature could be a hacked CRL
+                               // (so anything within can't be trusted)
+                               if (!crl.VerifySignature 
(ca_cert.PublicKey.Key)) {
+                                       return 
X509ChainStatusFlags.RevocationStatusUnknown;
+                               }
+
+                               MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry 
(certificate.MonoCertificate);
+                               if (entry != null) {
+                                       // We have an entry for this CRL that 
includes an unknown CRITICAL extension
+                                       // See [X.509 7.3] NOTE 4
+                                       if (!ProcessCrlEntryExtensions (entry))
+                                               return 
X509ChainStatusFlags.Revoked;
+
+                                       // FIXME - a little more is involved
+                                       if (entry.RevocationDate <= 
ChainPolicy.VerificationTime)
+                                               return 
X509ChainStatusFlags.Revoked;
+                               }
+
+                               // are we overdue for a CRL update ? if so we 
can't be sure of any certificate status
+                               if (crl.NextUpdate < 
ChainPolicy.VerificationTime)
+                                       return 
X509ChainStatusFlags.RevocationStatusUnknown | 
X509ChainStatusFlags.OfflineRevocation;
+
+                               // we have a CRL that includes an unknown 
CRITICAL extension
+                               // we put this check at the end so we do not 
"hide" any Revoked flags
+                               if (!ProcessCrlExtensions (crl)) {
+                                       return 
X509ChainStatusFlags.RevocationStatusUnknown;
+                               }
+                       } else {
+                               return 
X509ChainStatusFlags.RevocationStatusUnknown;
+                       }
 
-               private void CheckOnlineRevocation (X509Certificate2 
certificate, ref X509ChainStatusFlags flags)
+                       return X509ChainStatusFlags.NoError;
+               }
+
+               private MX.X509Crl OnlineCheck (X509Certificate2 certificate)
                {
-                       // TODO - check for X509ChainStatusFlags.Revoked
-                       // TODO - check for 
X509ChainStatusFlags.RevocationStatusUnknown
-                       // TODO - check for 
X509ChainStatusFlags.OfflineRevocation
-                       //       (using X509ChainPolicy.RevocationFlag and 
X509ChainPolicy.RevocationMode)
+                       // CRL doesn't exists or couldn't be downloaded
+                       return null;
                }
+
+               private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
+               {
+                       string subject = caCertificate.SubjectName.Decode 
(X500DistinguishedNameFlags.None);
+                       string ski = GetSubjectKeyIdentifier (caCertificate);
+                       foreach (MX.X509Crl crl in 
CertificateAuthorities.Store.Crls) {
+                               if (crl.IssuerName == subject) {
+                                       if ((ski.Length == 0) || (ski == 
GetAuthorityKeyIdentifier (crl)))
+                                               return crl;
+                               }
+                       }
+                       foreach (MX.X509Crl crl in Roots.Store.Crls) {
+                               if (crl.IssuerName == subject) {
+                                       if ((ski.Length == 0) || (ski == 
GetAuthorityKeyIdentifier (crl)))
+                                               return crl;
+                               }
+                       }
+                       return null;
+               }
+
+               private bool ProcessCrlExtensions (MX.X509Crl crl)
+               {
+                       foreach (MX.X509Extension ext in crl.Extensions) {
+                               if (ext.Critical) {
+                                       switch (ext.Oid) {
+                                       case "2.5.29.20": // cRLNumber
+                                       case "2.5.29.35": // 
authorityKeyIdentifier
+                                               // we processed/know about this 
extension
+                                               break;
+                                       default:
+                                               return false;
+                                       }
+                               }
+                       }
+                       return true;
+               }
+
+               private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry 
entry)
+               {
+                       foreach (MX.X509Extension ext in entry.Extensions) {
+                               if (ext.Critical) {
+                                       switch (ext.Oid) {
+                                       case "2.5.29.21": // cRLReason
+                                               // we processed/know about this 
extension
+                                               break;
+                                       default:
+                                               return false;
+                                       }
+                               }
+                       }
+                       return true;
+               }
        }
 }
 

Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElement.cs
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElement.cs
    2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElement.cs
    2006-12-07 21:13:23 UTC (rev 69204)
@@ -36,46 +36,14 @@
                private X509Certificate2 certificate;
                private X509ChainStatus[] status;
                private string info;
+               private X509ChainStatusFlags compressed_status_flags;
 
                // constructors
 
                // only accessible from X509Chain.ChainElements
-               internal X509ChainElement (X509Certificate2 certificate, 
X509ChainStatusFlags flags)
+               internal X509ChainElement (X509Certificate2 certificate)
                {
                        this.certificate = certificate;
-
-                       if (flags == X509ChainStatusFlags.NoError) {
-                               status = new X509ChainStatus [0];
-                       } else {
-                               int size = Count (flags);
-                               status = new X509ChainStatus [size];
-
-                               int n = 0;
-                               // process every possible error
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.UntrustedRoot);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.NotTimeValid);
-                               // not yet sorted after this...
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.NotTimeNested);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.Revoked);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.NotSignatureValid);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.NotValidForUsage);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.RevocationStatusUnknown);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.Cyclic);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.InvalidExtension);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.InvalidPolicyConstraints);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.InvalidBasicConstraints);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.InvalidNameConstraints);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.HasNotSupportedNameConstraint);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.HasNotDefinedNameConstraint);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.HasNotPermittedNameConstraint);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.HasExcludedNameConstraint);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.PartialChain);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.CtlNotTimeValid);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.CtlNotSignatureValid);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.CtlNotValidForUsage);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.OfflineRevocation);
-                               Set (status, ref n, flags, 
X509ChainStatusFlags.NoIssuanceChainPolicy);
-                       }
                        // so far String.Empty is the only thing I've seen. 
                        // The interesting stuff is inside 
X509ChainStatus.Information
                        info = String.Empty;
@@ -97,6 +65,11 @@
 
                // private stuff
 
+               internal X509ChainStatusFlags StatusFlags {
+                       get { return compressed_status_flags; }
+                       set { compressed_status_flags = value; }
+               }
+
                private int Count (X509ChainStatusFlags flags)
                {
                        int size = 0;
@@ -119,6 +92,41 @@
                                position++;
                        }
                }
+
+               internal void UncompressFlags ()
+               {
+                       if (compressed_status_flags == 
X509ChainStatusFlags.NoError) {
+                               status = new X509ChainStatus [0];
+                       } else {
+                               int size = Count (compressed_status_flags);
+                               status = new X509ChainStatus [size];
+
+                               int n = 0;
+                               // process every possible error
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.UntrustedRoot);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.NotTimeValid);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.NotTimeNested);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.Revoked);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.NotSignatureValid);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.NotValidForUsage);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.RevocationStatusUnknown);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.Cyclic);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.InvalidExtension);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.InvalidPolicyConstraints);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.InvalidBasicConstraints);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.InvalidNameConstraints);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.HasNotSupportedNameConstraint);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.HasNotDefinedNameConstraint);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.HasNotPermittedNameConstraint);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.HasExcludedNameConstraint);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.PartialChain);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.CtlNotTimeValid);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.CtlNotSignatureValid);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.CtlNotValidForUsage);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.OfflineRevocation);
+                               Set (status, ref n, compressed_status_flags, 
X509ChainStatusFlags.NoIssuanceChainPolicy);
+                       }
+               }
        }
 }
 

Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
  2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
  2006-12-07 21:13:23 UTC (rev 69204)
@@ -2,12 +2,11 @@
 // X509ChainElementCollection.cs - 
System.Security.Cryptography.X509Certificates.X509ChainElementCollection
 //
 // Author:
-//     Sebastien Pouliot ([EMAIL PROTECTED])
+//     Sebastien Pouliot  <[EMAIL PROTECTED]>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2006 Novell Inc. (http://www.novell.com)
 //
-
-//
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
@@ -88,15 +87,24 @@
 
                // private stuff
 
-               internal void Add (X509Certificate2 certificate, 
X509ChainStatusFlags flags)
+               internal void Add (X509Certificate2 certificate)
                {
-                       _list.Add (new X509ChainElement (certificate, flags));
+                       _list.Add (new X509ChainElement (certificate));
                }
 
                internal void Clear ()
                {
                        _list.Clear ();
                }
+
+               internal bool Contains (X509Certificate2 certificate)
+               {
+                       for (int i=0; i < _list.Count; i++) {
+                               if (certificate.Equals (( _list [i] as 
X509ChainElement).Certificate))
+                                       return true;
+                       }
+                       return false;
+               }
        }
 }
 

Modified: 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Store.cs
===================================================================
--- 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Store.cs
   2006-12-07 21:12:13 UTC (rev 69203)
+++ 
trunk/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Store.cs
   2006-12-07 21:13:23 UTC (rev 69204)
@@ -139,6 +139,10 @@
                        get { return ((_flags & OpenFlags.ReadWrite) == 
OpenFlags.ReadOnly); }
                }
 
+               internal MX.X509Store Store {
+                       get { return store; }
+               }
+
                [MonoTODO ("Mono's stores are fully managed. Always returns 
IntPtr.Zero.")]
                public IntPtr StoreHandle {
                        get { return IntPtr.Zero; }
@@ -203,8 +207,19 @@
                        if (String.IsNullOrEmpty (_name))
                                throw new CryptographicException 
(Locale.GetText ("Invalid store name (null or empty)."));
 
+                       /* keep existing Mono installations (pre 2.0) 
compatible with new stuff */
+                       string name;
+                       switch (_name) {
+                       case "Root":
+                               name = "Trust";
+                               break;
+                       default:
+                               name = _name;
+                               break;
+                       }
+
                        bool create = ((flags & OpenFlags.OpenExistingOnly) != 
OpenFlags.OpenExistingOnly);
-                       store = Factory.Open (_name, create);
+                       store = Factory.Open (name, create);
                        if (store == null)
                                throw new CryptographicException 
(Locale.GetText ("Store {0} doesn't exists.", _name));
                        _flags = flags;

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to