minor fix for bug 9520:
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / OSX509Certificates.cs
1 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)
2 // Copyright 2012 Xamarin Inc.
3 //
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:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
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.
22 //
23 #if SECURITY_DEP
24
25 extern alias MonoSecurity;
26
27 using System;
28 using System.Runtime.InteropServices;
29 using MSX = MonoSecurity::Mono.Security.X509;
30
31 namespace System.Security.Cryptography.X509Certificates {
32
33         static class OSX509Certificates {
34                 public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
35                 public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
36         
37                 [DllImport (SecurityLibrary)]
38                 extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
39                 
40                 [DllImport (SecurityLibrary)]
41                 extern static int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
42                 
43                 [DllImport (SecurityLibrary)]
44                 extern static IntPtr SecPolicyCreateSSL (bool server, IntPtr cfStringHostname);
45                 
46                 [DllImport (SecurityLibrary)]
47                 extern static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
48
49                 [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
50                 extern static IntPtr CFStringCreateWithCharacters (IntPtr allocator, string str, int count);
51
52                 [DllImport (CoreFoundationLibrary)]
53                 unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, IntPtr length);
54
55                 [DllImport (CoreFoundationLibrary)]
56                 unsafe extern static void CFRelease (IntPtr handle);
57
58                 [DllImport (CoreFoundationLibrary)]
59                 extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, IntPtr numValues, IntPtr callbacks);
60                 
61                 public enum SecTrustResult {
62                         Invalid,
63                         Proceed,
64                         Confirm,
65                         Deny,
66                         Unspecified,
67                         RecoverableTrustFailure,
68                         FatalTrustFailure,
69                         ResultOtherError,
70                 }
71
72                 static IntPtr MakeCFData (byte [] data)
73                 {
74                         unsafe {
75                                 fixed (byte *ptr = &data [0])
76                                         return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
77                         }
78                 }
79
80                 static unsafe IntPtr FromIntPtrs (IntPtr [] values)
81                 {
82                         fixed (IntPtr* pv = values) {
83                                 return CFArrayCreate (
84                                         IntPtr.Zero, 
85                                         (IntPtr) pv,
86                                         (IntPtr) values.Length,
87                                         IntPtr.Zero);
88                         }
89                 }
90                 
91                 public static SecTrustResult TrustEvaluateSsl (MSX.X509CertificateCollection certificates, string host)
92                 {
93                         if (certificates == null)
94                                 return SecTrustResult.Deny;
95
96                         try {
97                                 return _TrustEvaluateSsl (certificates, host);
98                         } catch {
99                                 return SecTrustResult.Deny;
100                         }
101                 }
102                 
103                 static SecTrustResult _TrustEvaluateSsl (MSX.X509CertificateCollection certificates, string hostName)
104                 {
105                         int certCount = certificates.Count;
106                         IntPtr [] cfDataPtrs = new IntPtr [certCount];
107                         IntPtr [] secCerts = new IntPtr [certCount];
108                         IntPtr certArray = IntPtr.Zero;
109                         IntPtr sslsecpolicy = IntPtr.Zero;
110                         IntPtr host = IntPtr.Zero;
111                         IntPtr sectrust = IntPtr.Zero;
112                         SecTrustResult result = SecTrustResult.Deny;
113
114                         try {
115                                 for (int i = 0; i < certCount; i++)
116                                         cfDataPtrs [i] = MakeCFData (certificates [i].RawData);
117                                 
118                                 for (int i = 0; i < certCount; i++){
119                                         secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
120                                         if (secCerts [i] == IntPtr.Zero)
121                                                 return SecTrustResult.Deny;
122                                 }
123                                 certArray = FromIntPtrs (secCerts);
124                                 host = CFStringCreateWithCharacters (IntPtr.Zero, hostName, hostName.Length);
125                                 sslsecpolicy = SecPolicyCreateSSL (true, host);
126
127                                 int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
128                                 if (code == 0)
129                                         code = SecTrustEvaluate (sectrust, out result);
130                                 return result;
131                         } finally {
132                                 for (int i = 0; i < certCount; i++)
133                                         if (cfDataPtrs [i] != IntPtr.Zero)
134                                                 CFRelease (cfDataPtrs [i]);
135
136                                 if (certArray != IntPtr.Zero)
137                                         CFRelease (certArray);
138                                 
139                                 for (int i = 0; i < certCount; i++)
140                                         if (secCerts [i] != IntPtr.Zero)
141                                                 CFRelease (secCerts [i]);
142
143                                 if (sslsecpolicy != IntPtr.Zero)
144                                         CFRelease (sslsecpolicy);
145                                 if (host != IntPtr.Zero)
146                                         CFRelease (host);
147                                 if (sectrust != IntPtr.Zero)
148                                         CFRelease (sectrust);
149                         }
150                 }
151         }
152 }
153 #endif