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 extern alias PrebuiltSystem;
29 using XX509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
31 using XX509CertificateCollection = System.Security.Cryptography.X509Certificates.X509CertificateCollection;
35 using System.Runtime.InteropServices;
37 namespace System.Security.Cryptography.X509Certificates {
39 static class OSX509Certificates {
40 public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
41 public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
43 [DllImport (SecurityLibrary)]
44 extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
46 [DllImport (SecurityLibrary)]
47 extern static /* OSStatus */ int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
49 [DllImport (SecurityLibrary)]
50 extern static /* OSStatus */ int SecTrustSetAnchorCertificates (IntPtr /* SecTrustRef */ trust, IntPtr /* CFArrayRef */ anchorCertificates);
52 [DllImport (SecurityLibrary)]
53 extern static IntPtr SecPolicyCreateSSL ([MarshalAs (UnmanagedType.I1)] bool server, IntPtr cfStringHostname);
55 [DllImport (SecurityLibrary)]
56 extern static /* OSStatus */ int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
58 [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
59 extern static IntPtr CFStringCreateWithCharacters (IntPtr allocator, string str, /* CFIndex */ IntPtr count);
61 [DllImport (CoreFoundationLibrary)]
62 unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, /* CFIndex */ IntPtr length);
64 [DllImport (CoreFoundationLibrary)]
65 extern static void CFRetain (IntPtr handle);
67 [DllImport (CoreFoundationLibrary)]
68 extern static void CFRelease (IntPtr handle);
70 [DllImport (CoreFoundationLibrary)]
71 extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, /* CFIndex */ IntPtr numValues, IntPtr callbacks);
74 public enum SecTrustResult {
80 RecoverableTrustFailure,
85 static IntPtr MakeCFData (byte [] data)
88 fixed (byte *ptr = &data [0])
89 return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
93 static unsafe IntPtr FromIntPtrs (IntPtr [] values)
95 fixed (IntPtr* pv = values) {
96 return CFArrayCreate (
99 (IntPtr) values.Length,
104 static IntPtr GetCertificate (X509Certificate certificate, out IntPtr dataPtr)
106 var handle = certificate.Handle;
107 if (handle != IntPtr.Zero) {
108 dataPtr = IntPtr.Zero;
112 dataPtr = MakeCFData (certificate.GetRawCertData ());
113 return SecCertificateCreateWithData (IntPtr.Zero, dataPtr);
116 public static SecTrustResult TrustEvaluateSsl (XX509CertificateCollection certificates, XX509CertificateCollection anchors, string host)
118 if (certificates == null)
119 return SecTrustResult.Deny;
122 return _TrustEvaluateSsl (certificates, anchors, host);
124 return SecTrustResult.Deny;
128 static SecTrustResult _TrustEvaluateSsl (XX509CertificateCollection certificates, XX509CertificateCollection anchors, string hostName)
130 int certCount = certificates.Count;
131 int anchorCount = anchors != null ? anchors.Count : 0;
132 IntPtr [] cfDataPtrs = new IntPtr [certCount];
133 IntPtr [] secCerts = new IntPtr [certCount];
134 IntPtr [] cfDataAnchorPtrs = new IntPtr [anchorCount];
135 IntPtr [] secCertAnchors = new IntPtr [anchorCount];
136 IntPtr certArray = IntPtr.Zero;
137 IntPtr anchorArray = IntPtr.Zero;
138 IntPtr sslsecpolicy = IntPtr.Zero;
139 IntPtr host = IntPtr.Zero;
140 IntPtr sectrust = IntPtr.Zero;
141 SecTrustResult result = SecTrustResult.Deny;
144 for (int i = 0; i < certCount; i++) {
145 secCerts [i] = GetCertificate (certificates [i], out cfDataPtrs [i]);
146 if (secCerts [i] == IntPtr.Zero)
147 return SecTrustResult.Deny;
150 for (int i = 0; i < anchorCount; i++) {
151 secCertAnchors [i] = GetCertificate (anchors [i], out cfDataAnchorPtrs [i]);
152 if (secCertAnchors [i] == IntPtr.Zero)
153 return SecTrustResult.Deny;
156 certArray = FromIntPtrs (secCerts);
158 host = CFStringCreateWithCharacters (IntPtr.Zero, hostName, (IntPtr) hostName.Length);
159 sslsecpolicy = SecPolicyCreateSSL (true, host);
161 int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
163 return SecTrustResult.Deny;
165 if (anchorCount > 0) {
166 anchorArray = FromIntPtrs (secCertAnchors);
167 SecTrustSetAnchorCertificates (sectrust, anchorArray);
170 code = SecTrustEvaluate (sectrust, out result);
173 for (int i = 0; i < certCount; i++)
174 if (cfDataPtrs [i] != IntPtr.Zero)
175 CFRelease (cfDataPtrs [i]);
177 for (int i = 0; i < anchorCount; i++)
178 if (cfDataAnchorPtrs [i] != IntPtr.Zero)
179 CFRelease (cfDataAnchorPtrs [i]);
181 if (certArray != IntPtr.Zero)
182 CFRelease (certArray);
184 if (anchorArray != IntPtr.Zero)
185 CFRelease (anchorArray);
187 for (int i = 0; i < certCount; i++)
188 if (secCerts [i] != IntPtr.Zero)
189 CFRelease (secCerts [i]);
191 for (int i = 0; i < anchorCount; i++)
192 if (secCertAnchors [i] != IntPtr.Zero)
193 CFRelease (secCertAnchors [i]);
195 if (sslsecpolicy != IntPtr.Zero)
196 CFRelease (sslsecpolicy);
197 if (host != IntPtr.Zero)
199 if (sectrust != IntPtr.Zero)
200 CFRelease (sectrust);