Merge pull request #3800 from madewokherd/mingwbuild
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / X509Helper2.cs
1 //
2 // X509Helper2.cs
3 //
4 // Authors:
5 //      Martin Baulig  <martin.baulig@xamarin.com>
6 //
7 // Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if SECURITY_DEP
30 #if MONO_SECURITY_ALIAS
31 extern alias MonoSecurity;
32 #endif
33
34 #if MONO_SECURITY_ALIAS
35 using MonoSecurity::Mono.Security.Interface;
36 using MX = MonoSecurity::Mono.Security.X509;
37 #else
38 #if MONO_FEATURE_BTLS
39 using Mono.Security.Interface;
40 #endif
41 using MX = Mono.Security.X509;
42 #endif
43
44 #if MONO_FEATURE_BTLS
45 using Mono.Btls;
46 #endif
47 #endif
48
49 using System.IO;
50 using System.Text;
51
52 namespace System.Security.Cryptography.X509Certificates
53 {
54         internal static class X509Helper2
55         {
56                 internal static long GetSubjectNameHash (X509Certificate certificate)
57                 {
58                         return GetSubjectNameHash (certificate.Impl);
59                 }
60
61                 internal static long GetSubjectNameHash (X509CertificateImpl impl)
62                 {
63 #if SECURITY_DEP
64                         using (var x509 = GetNativeInstance (impl))
65                                 return GetSubjectNameHash (x509);
66 #else
67                         throw new NotSupportedException ();
68 #endif
69                 }
70
71                 internal static void ExportAsPEM (X509Certificate certificate, Stream stream, bool includeHumanReadableForm)
72                 {
73                         ExportAsPEM (certificate.Impl, stream, includeHumanReadableForm);
74                 }
75
76                 internal static void ExportAsPEM (X509CertificateImpl impl, Stream stream, bool includeHumanReadableForm)
77                 {
78 #if SECURITY_DEP
79                         using (var x509 = GetNativeInstance (impl))
80                                 ExportAsPEM (x509, stream, includeHumanReadableForm);
81 #else
82                         throw new NotSupportedException ();
83 #endif
84                 }
85
86 #if SECURITY_DEP
87                 internal static void Initialize ()
88                 {
89                         X509Helper.InstallNativeHelper (new MyNativeHelper ());
90                 }
91
92                 internal static void ThrowIfContextInvalid (X509CertificateImpl impl)
93                 {
94                         X509Helper.ThrowIfContextInvalid (impl);
95                 }
96
97 #if !MONO_FEATURE_BTLS
98                 static X509Certificate GetNativeInstance (X509CertificateImpl impl)
99                 {
100                         throw new PlatformNotSupportedException ();
101                 }
102 #else
103                 static MonoBtlsX509 GetNativeInstance (X509CertificateImpl impl)
104                 {
105                         ThrowIfContextInvalid (impl);
106                         var btlsImpl = impl as X509CertificateImplBtls;
107                         if (btlsImpl != null)
108                                 return btlsImpl.X509.Copy ();
109                         else
110                                 return MonoBtlsX509.LoadFromData (impl.GetRawCertData (), MonoBtlsX509Format.DER);
111                 }
112
113                 internal static long GetSubjectNameHash (MonoBtlsX509 x509)
114                 {
115                         using (var subject = x509.GetSubjectName ())
116                                 return subject.GetHash ();
117                 }
118
119                 internal static void ExportAsPEM (MonoBtlsX509 x509, Stream stream, bool includeHumanReadableForm)
120                 {
121                         using (var bio = MonoBtlsBio.CreateMonoStream (stream)) {
122                                 x509.ExportAsPEM (bio, includeHumanReadableForm);
123                         }
124                 }
125 #endif // !MONO_FEATURE_BTLS
126
127                 internal static X509Certificate2Impl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags, bool disableProvider = false)
128                 {
129 #if MONO_FEATURE_BTLS
130                         if (!disableProvider) {
131                                 var provider = MonoTlsProviderFactory.GetProvider ();
132                                 if (provider.HasNativeCertificates) {
133                                         var impl = provider.GetNativeCertificate (rawData, password, keyStorageFlags);
134                                         return impl;
135                                 }
136                         }
137 #endif // MONO_FEATURE_BTLS
138                         var impl2 = new X509Certificate2ImplMono ();
139                         impl2.Import (rawData, password, keyStorageFlags);
140                         return impl2;
141                 }
142
143                 internal static X509Certificate2Impl Import (X509Certificate cert, bool disableProvider = false)
144                 {
145 #if MONO_FEATURE_BTLS
146                         if (!disableProvider) {
147                                 var provider = MonoTlsProviderFactory.GetProvider ();
148                                 if (provider.HasNativeCertificates) {
149                                         var impl = provider.GetNativeCertificate (cert);
150                                         return impl;
151                                 }
152                         }
153 #endif // MONO_FEATURE_BTLS
154                         var impl2 = cert.Impl as X509Certificate2Impl;
155                         if (impl2 != null)
156                                 return (X509Certificate2Impl)impl2.Clone ();
157                         return Import (cert.GetRawCertData (), null, X509KeyStorageFlags.DefaultKeySet);
158                 }
159
160                 /*
161                  * This is used by X509ChainImplMono
162                  * 
163                  * Some of the missing APIs such as X509v3 extensions can be added to the native
164                  * BTLS implementation.
165                  * 
166                  * We should also consider replacing X509ChainImplMono with a new X509ChainImplBtls
167                  * at some point.
168                  */
169                 [MonoTODO ("Investigate replacement; see comments in source.")]
170                 internal static MX.X509Certificate GetMonoCertificate (X509Certificate2 certificate)
171                 {
172                         var impl2 = certificate.Impl as X509Certificate2Impl;
173                         if (impl2 == null)
174                                 impl2 = Import (certificate, true);
175                         var fallbackImpl = impl2.FallbackImpl as X509Certificate2ImplMono;
176                         if (fallbackImpl == null)
177                                 throw new NotSupportedException ();
178                         return fallbackImpl.MonoCertificate;
179                 }
180
181                 internal static X509ChainImpl CreateChainImpl (bool useMachineContext)
182                 {
183                         return new X509ChainImplMono (useMachineContext);
184                 }
185
186                 public static bool IsValid (X509ChainImpl impl)
187                 {
188                         return impl != null && impl.IsValid;
189                 }
190
191                 internal static void ThrowIfContextInvalid (X509ChainImpl impl)
192                 {
193                         if (!IsValid (impl))
194                                 throw GetInvalidChainContextException ();
195                 }
196
197                 internal static Exception GetInvalidChainContextException ()
198                 {
199                         return new CryptographicException (Locale.GetText ("Chain instance is empty."));
200                 }
201
202                 class MyNativeHelper : INativeCertificateHelper
203                 {
204                         public X509CertificateImpl Import (
205                                 byte[] data, string password, X509KeyStorageFlags flags)
206                         {
207                                 return X509Helper2.Import (data, password, flags);
208                         }
209
210                         public X509CertificateImpl Import (X509Certificate cert)
211                         {
212                                 return X509Helper2.Import (cert);
213                         }
214                 }
215 #endif
216         }
217 }