1 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)
2 // Copyright 2012-2014 Xamarin Inc.
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #if MONOTOUCH || MONODROID
26 using MSX = Mono.Security.X509;
28 extern alias MonoSecurity;
29 using MSX = MonoSecurity::Mono.Security.X509;
33 using System.Collections.Generic;
34 using System.Runtime.InteropServices;
36 namespace System.Security.Cryptography.X509Certificates {
38 static class OSX509Certificates {
39 public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
40 public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
42 [DllImport (SecurityLibrary)]
43 extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
45 [DllImport (SecurityLibrary)]
46 extern static /* OSStatus */ int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
48 [DllImport (SecurityLibrary)]
49 extern static IntPtr SecPolicyCreateSSL ([MarshalAs (UnmanagedType.I1)] bool server, IntPtr cfStringHostname);
51 [DllImport (SecurityLibrary)]
52 extern static /* OSStatus */ int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
54 [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
55 extern static IntPtr CFStringCreateWithCharacters (IntPtr allocator, string str, /* CFIndex */ IntPtr count);
57 [DllImport (CoreFoundationLibrary)]
58 unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, /* CFIndex */ IntPtr length);
60 [DllImport (CoreFoundationLibrary)]
61 extern static void CFRelease (IntPtr handle);
63 [DllImport (CoreFoundationLibrary)]
64 extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, /* CFIndex */ IntPtr numValues, IntPtr callbacks);
67 public enum SecTrustResult {
73 RecoverableTrustFailure,
78 static IntPtr MakeCFData (byte [] data)
81 fixed (byte *ptr = &data [0])
82 return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
86 static unsafe IntPtr FromIntPtrs (IntPtr [] values)
88 fixed (IntPtr* pv = values) {
89 return CFArrayCreate (
92 (IntPtr) values.Length,
97 static IList<byte[]> CreateArray (X509Certificate2Collection certificates)
99 var list = new List<byte[]> (certificates.Count);
100 for (int i = 0; i < certificates.Count; i++)
101 list.Add (certificates [i].RawData);
105 static IList<byte[]> CreateArray (MSX.X509CertificateCollection certificates)
107 var list = new List<byte[]> (certificates.Count);
108 for (int i = 0; i < certificates.Count; i++)
109 list.Add (certificates [i].RawData);
113 public static SecTrustResult TrustEvaluateSsl (MSX.X509CertificateCollection certificates, string host)
115 if (certificates == null)
116 return SecTrustResult.Deny;
119 var certArray = CreateArray (certificates);
120 return _TrustEvaluateSsl (certArray, host);
122 return SecTrustResult.Deny;
126 public static SecTrustResult TrustEvaluateSsl (X509Certificate2Collection certificates, string host)
128 if (certificates == null)
129 return SecTrustResult.Deny;
132 var certArray = CreateArray (certificates);
133 return _TrustEvaluateSsl (certArray, host);
135 return SecTrustResult.Deny;
139 static SecTrustResult _TrustEvaluateSsl (IList<byte[]> certificates, string hostName)
141 int certCount = certificates.Count;
142 IntPtr [] cfDataPtrs = new IntPtr [certCount];
143 IntPtr [] secCerts = new IntPtr [certCount];
144 IntPtr certArray = IntPtr.Zero;
145 IntPtr sslsecpolicy = IntPtr.Zero;
146 IntPtr host = IntPtr.Zero;
147 IntPtr sectrust = IntPtr.Zero;
148 SecTrustResult result = SecTrustResult.Deny;
151 for (int i = 0; i < certCount; i++)
152 cfDataPtrs [i] = MakeCFData (certificates [i]);
154 for (int i = 0; i < certCount; i++){
155 secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
156 if (secCerts [i] == IntPtr.Zero)
157 return SecTrustResult.Deny;
159 certArray = FromIntPtrs (secCerts);
160 host = CFStringCreateWithCharacters (IntPtr.Zero, hostName, (IntPtr) hostName.Length);
161 sslsecpolicy = SecPolicyCreateSSL (true, host);
163 int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
165 code = SecTrustEvaluate (sectrust, out result);
168 for (int i = 0; i < certCount; i++)
169 if (cfDataPtrs [i] != IntPtr.Zero)
170 CFRelease (cfDataPtrs [i]);
172 if (certArray != IntPtr.Zero)
173 CFRelease (certArray);
175 for (int i = 0; i < certCount; i++)
176 if (secCerts [i] != IntPtr.Zero)
177 CFRelease (secCerts [i]);
179 if (sslsecpolicy != IntPtr.Zero)
180 CFRelease (sslsecpolicy);
181 if (host != IntPtr.Zero)
183 if (sectrust != IntPtr.Zero)
184 CFRelease (sectrust);