Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / OSX509Certificates.cs
index 4dc4e0a1560032964690910ab9ac72473df08d26..184e586471dd30c167be16eca420d930c5c12bfb 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 #if SECURITY_DEP
+#if MONO_X509_ALIAS
+extern alias PrebuiltSystem;
+#endif
 
-#if MONOTOUCH || MONODROID
-using MSX = Mono.Security.X509;
+#if MONO_X509_ALIAS
+using XX509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
 #else
-extern alias MonoSecurity;
-using MSX = MonoSecurity::Mono.Security.X509;
+using XX509CertificateCollection = System.Security.Cryptography.X509Certificates.X509CertificateCollection;
 #endif
 
 using System;
@@ -44,6 +46,9 @@ namespace System.Security.Cryptography.X509Certificates {
                [DllImport (SecurityLibrary)]
                extern static /* OSStatus */ int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
                
+               [DllImport (SecurityLibrary)]
+               extern static /* OSStatus */ int SecTrustSetAnchorCertificates (IntPtr /* SecTrustRef */ trust, IntPtr /* CFArrayRef */ anchorCertificates);
+
                [DllImport (SecurityLibrary)]
                extern static IntPtr SecPolicyCreateSSL ([MarshalAs (UnmanagedType.I1)] bool server, IntPtr cfStringHostname);
                
@@ -56,6 +61,9 @@ namespace System.Security.Cryptography.X509Certificates {
                [DllImport (CoreFoundationLibrary)]
                unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, /* CFIndex */ IntPtr length);
 
+               [DllImport (CoreFoundationLibrary)]
+               extern static void CFRetain (IntPtr handle);
+
                [DllImport (CoreFoundationLibrary)]
                extern static void CFRelease (IntPtr handle);
 
@@ -92,59 +100,98 @@ namespace System.Security.Cryptography.X509Certificates {
                                        IntPtr.Zero);
                        }
                }
+
+               static IntPtr GetCertificate (X509Certificate certificate, out IntPtr dataPtr)
+               {
+                       var handle = certificate.Handle;
+                       if (handle != IntPtr.Zero) {
+                               dataPtr = IntPtr.Zero;
+                               CFRetain (handle);
+                               return handle;
+                       }
+                       dataPtr = MakeCFData (certificate.GetRawCertData ());
+                       return SecCertificateCreateWithData (IntPtr.Zero, dataPtr);
+               }
                
-               public static SecTrustResult TrustEvaluateSsl (MSX.X509CertificateCollection certificates, string host)
+               public static SecTrustResult TrustEvaluateSsl (XX509CertificateCollection certificates, XX509CertificateCollection anchors, string host)
                {
                        if (certificates == null)
                                return SecTrustResult.Deny;
 
                        try {
-                               return _TrustEvaluateSsl (certificates, host);
+                               return _TrustEvaluateSsl (certificates, anchors, host);
                        } catch {
                                return SecTrustResult.Deny;
                        }
                }
-               
-               static SecTrustResult _TrustEvaluateSsl (MSX.X509CertificateCollection certificates, string hostName)
+
+               static SecTrustResult _TrustEvaluateSsl (XX509CertificateCollection certificates, XX509CertificateCollection anchors, string hostName)
                {
                        int certCount = certificates.Count;
+                       int anchorCount = anchors != null ? anchors.Count : 0;
                        IntPtr [] cfDataPtrs = new IntPtr [certCount];
                        IntPtr [] secCerts = new IntPtr [certCount];
+                       IntPtr [] cfDataAnchorPtrs = new IntPtr [anchorCount];
+                       IntPtr [] secCertAnchors = new IntPtr [anchorCount];
                        IntPtr certArray = IntPtr.Zero;
+                       IntPtr anchorArray = IntPtr.Zero;
                        IntPtr sslsecpolicy = IntPtr.Zero;
                        IntPtr host = IntPtr.Zero;
                        IntPtr sectrust = IntPtr.Zero;
                        SecTrustResult result = SecTrustResult.Deny;
 
                        try {
-                               for (int i = 0; i < certCount; i++)
-                                       cfDataPtrs [i] = MakeCFData (certificates [i].RawData);
-                               
-                               for (int i = 0; i < certCount; i++){
-                                       secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
+                               for (int i = 0; i < certCount; i++) {
+                                       secCerts [i] = GetCertificate (certificates [i], out cfDataPtrs [i]);
                                        if (secCerts [i] == IntPtr.Zero)
                                                return SecTrustResult.Deny;
                                }
+
+                               for (int i = 0; i < anchorCount; i++) {
+                                       secCertAnchors [i] = GetCertificate (anchors [i], out cfDataAnchorPtrs [i]);
+                                       if (secCertAnchors [i] == IntPtr.Zero)
+                                               return SecTrustResult.Deny;
+                               }
+
                                certArray = FromIntPtrs (secCerts);
+
                                host = CFStringCreateWithCharacters (IntPtr.Zero, hostName, (IntPtr) hostName.Length);
                                sslsecpolicy = SecPolicyCreateSSL (true, host);
 
                                int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
-                               if (code == 0)
-                                       code = SecTrustEvaluate (sectrust, out result);
+                               if (code != 0)
+                                       return SecTrustResult.Deny;
+
+                               if (anchorCount > 0) {
+                                       anchorArray = FromIntPtrs (secCertAnchors);
+                                       SecTrustSetAnchorCertificates (sectrust, anchorArray);
+                               }
+
+                               code = SecTrustEvaluate (sectrust, out result);
                                return result;
                        } finally {
                                for (int i = 0; i < certCount; i++)
                                        if (cfDataPtrs [i] != IntPtr.Zero)
                                                CFRelease (cfDataPtrs [i]);
 
+                               for (int i = 0; i < anchorCount; i++)
+                                       if (cfDataAnchorPtrs [i] != IntPtr.Zero)
+                                               CFRelease (cfDataAnchorPtrs [i]);
+
                                if (certArray != IntPtr.Zero)
                                        CFRelease (certArray);
+
+                               if (anchorArray != IntPtr.Zero)
+                                       CFRelease (anchorArray);
                                
                                for (int i = 0; i < certCount; i++)
                                        if (secCerts [i] != IntPtr.Zero)
                                                CFRelease (secCerts [i]);
 
+                               for (int i = 0; i < anchorCount; i++)
+                                       if (secCertAnchors [i] != IntPtr.Zero)
+                                               CFRelease (secCertAnchors [i]);
+
                                if (sslsecpolicy != IntPtr.Zero)
                                        CFRelease (sslsecpolicy);
                                if (host != IntPtr.Zero)