1 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)
2 // Copyright 2012 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 using System.Runtime.InteropServices;
26 using Mono.Security.X509;
27 using Mono.Security.X509.Extensions;
29 namespace Mono.Security.X509 {
31 internal class OSX509Certificates {
32 public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
33 public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
35 [DllImport (SecurityLibrary)]
36 extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
38 [DllImport (SecurityLibrary)]
39 extern static int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
41 [DllImport (SecurityLibrary)]
42 extern static IntPtr SecPolicyCreateSSL (bool server, IntPtr cfStringHostname);
44 [DllImport (SecurityLibrary)]
45 extern static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
47 [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
48 extern static IntPtr CFStringCreateWithCharacters (IntPtr allocator, string str, int count);
50 [DllImport (CoreFoundationLibrary)]
51 unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, IntPtr length);
53 [DllImport (CoreFoundationLibrary)]
54 unsafe extern static void CFRelease (IntPtr handle);
56 [DllImport (CoreFoundationLibrary)]
57 extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, IntPtr numValues, IntPtr callbacks);
59 public enum SecTrustResult {
65 RecoverableTrustFailure,
70 static IntPtr MakeCFData (byte [] data)
73 fixed (byte *ptr = &data [0])
74 return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
78 static unsafe IntPtr FromIntPtrs (IntPtr [] values)
80 fixed (IntPtr* pv = values) {
81 return CFArrayCreate (
84 (IntPtr) values.Length,
89 public static SecTrustResult TrustEvaluateSsl (X509CertificateCollection certificates, string host)
91 if (certificates == null)
92 return SecTrustResult.Deny;
95 return _TrustEvaluateSsl (certificates, host);
97 return SecTrustResult.Deny;
101 static SecTrustResult _TrustEvaluateSsl (X509CertificateCollection certificates, string hostName)
103 int certCount = certificates.Count;
104 IntPtr [] cfDataPtrs = new IntPtr [certCount];
105 IntPtr [] secCerts = new IntPtr [certCount];
106 IntPtr certArray = IntPtr.Zero;
107 IntPtr sslsecpolicy = IntPtr.Zero;
108 IntPtr host = IntPtr.Zero;
109 IntPtr sectrust = IntPtr.Zero;
110 SecTrustResult result = SecTrustResult.Deny;
113 for (int i = 0; i < certCount; i++)
114 cfDataPtrs [i] = MakeCFData (certificates [i].RawData);
116 for (int i = 0; i < certCount; i++){
117 secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
118 if (secCerts [i] == IntPtr.Zero)
119 return SecTrustResult.Deny;
121 certArray = FromIntPtrs (secCerts);
122 host = CFStringCreateWithCharacters (IntPtr.Zero, hostName, hostName.Length);
123 sslsecpolicy = SecPolicyCreateSSL (true, host);
125 int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
127 code = SecTrustEvaluate (sectrust, out result);
130 for (int i = 0; i < certCount; i++)
131 if (cfDataPtrs [i] != IntPtr.Zero)
132 CFRelease (cfDataPtrs [i]);
134 if (certArray != IntPtr.Zero)
135 CFRelease (certArray);
137 for (int i = 0; i < certCount; i++)
138 if (secCerts [i] != IntPtr.Zero)
139 CFRelease (secCerts [i]);
141 if (sslsecpolicy != IntPtr.Zero)
142 CFRelease (sslsecpolicy);
143 if (host != IntPtr.Zero)
145 if (sectrust != IntPtr.Zero)
146 CFRelease (sectrust);