Use the right socket for the data stream
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / OSX509Certificates.cs
1 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
10 // 
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 // 
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 #if SECURITY_DEP
23 using System;
24 using System.Runtime.InteropServices;
25 using Mono.Security.X509;
26 using Mono.Security.X509.Extensions;
27
28 namespace Mono.Security.X509 {
29
30         internal class OSX509Certificates {
31                 public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
32                 public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
33         
34                 [DllImport (SecurityLibrary)]
35                 extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
36                 
37                 [DllImport (SecurityLibrary)]
38                 extern static int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
39                 
40                 [DllImport (SecurityLibrary)]
41                 extern static IntPtr SecPolicyCreateSSL (int server, IntPtr cfStringHostname);
42                 
43                 [DllImport (SecurityLibrary)]
44                 extern static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
45
46                 [DllImport (CoreFoundationLibrary)]
47                 unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, IntPtr length);
48
49                 [DllImport (CoreFoundationLibrary)]
50                 unsafe extern static void CFRelease (IntPtr handle);
51
52                 [DllImport (CoreFoundationLibrary)]
53                 extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, IntPtr numValues, IntPtr callbacks);
54                 
55                 public enum SecTrustResult {
56                         Invalid,
57                         Proceed,
58                         Confirm,
59                         Deny,
60                         Unspecified,
61                         RecoverableTrustFailure,
62                         FatalTrustFailure,
63                         ResultOtherError,
64                 }
65
66                 static IntPtr sslsecpolicy = SecPolicyCreateSSL (0, IntPtr.Zero);
67
68                 static IntPtr MakeCFData (byte [] data)
69                 {
70                         unsafe {
71                                 fixed (byte *ptr = &data [0])
72                                         return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
73                         }
74                 }
75
76                 static unsafe IntPtr FromIntPtrs (IntPtr [] values)
77                 {
78                         fixed (IntPtr* pv = values) {
79                                 return CFArrayCreate (
80                                         IntPtr.Zero, 
81                                         (IntPtr) pv,
82                                         (IntPtr) values.Length,
83                                         IntPtr.Zero);
84                         }
85                 }
86                 
87                 public static SecTrustResult TrustEvaluateSsl (X509CertificateCollection certificates)
88                 {
89                         try {
90                                 return _TrustEvaluateSsl (certificates);
91                         } catch {
92                                 return SecTrustResult.Deny;
93                         }
94                 }
95                 
96                 static SecTrustResult _TrustEvaluateSsl (X509CertificateCollection certificates)
97                 {
98                         if (certificates == null)
99                                 throw new ArgumentNullException ("certificates");
100
101                         int certCount = certificates.Count;
102                         IntPtr [] cfDataPtrs = new IntPtr [certCount];
103                         IntPtr [] secCerts = new IntPtr [certCount];
104                         IntPtr certArray = IntPtr.Zero;
105                         
106                         try {
107                                 for (int i = 0; i < certCount; i++)
108                                         cfDataPtrs [i] = MakeCFData (certificates [i].RawData);
109                                 
110                                 for (int i = 0; i < certCount; i++){
111                                         secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
112                                         if (secCerts [i] == IntPtr.Zero)
113                                                 return SecTrustResult.Deny;
114                                 }
115                                 certArray = FromIntPtrs (secCerts);
116                                 IntPtr sectrust;
117                                 int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
118                                 if (code == 0){
119                                         SecTrustResult result;
120                                         code = SecTrustEvaluate (sectrust, out result);
121                                         if (code != 0)
122                                                 return SecTrustResult.Deny;
123
124                                         CFRelease (sectrust);
125                                         
126                                         return result;
127                                 }
128                                 return SecTrustResult.Deny;
129                         } finally {
130                                 for (int i = 0; i < certCount; i++)
131                                         if (cfDataPtrs [i] != IntPtr.Zero)
132                                                 CFRelease (cfDataPtrs [i]);
133
134                                 if (certArray != IntPtr.Zero)
135                                         CFRelease (certArray);
136                                 else
137                                         for (int i = 0; i < certCount; i++)
138                                                 if (secCerts [i] != IntPtr.Zero)
139                                                         CFRelease (secCerts [i]);
140                         }
141                 }
142         }
143 }
144 #endif