5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 using System.Threading;
31 using System.Runtime.CompilerServices;
32 using System.Runtime.InteropServices;
33 using System.Security.Cryptography.X509Certificates;
34 using System.Security.Cryptography;
38 class MonoBtlsX509 : MonoBtlsObject
40 internal class BoringX509Handle : MonoBtlsHandle
42 public BoringX509Handle (IntPtr handle)
47 protected override bool ReleaseHandle ()
49 if (handle != IntPtr.Zero)
50 mono_btls_x509_free (handle);
54 public IntPtr StealHandle ()
56 var retval = Interlocked.Exchange (ref handle, IntPtr.Zero);
61 new internal BoringX509Handle Handle {
62 get { return (BoringX509Handle)base.Handle; }
65 internal MonoBtlsX509 (BoringX509Handle handle)
70 [MethodImpl (MethodImplOptions.InternalCall)]
71 extern static IntPtr mono_btls_x509_up_ref (IntPtr handle);
73 [MethodImpl (MethodImplOptions.InternalCall)]
74 extern static IntPtr mono_btls_x509_from_data (IntPtr data, int len, MonoBtlsX509Format format);
76 [MethodImpl (MethodImplOptions.InternalCall)]
77 extern static IntPtr mono_btls_x509_get_subject_name (IntPtr handle);
79 [MethodImpl (MethodImplOptions.InternalCall)]
80 extern static IntPtr mono_btls_x509_get_issuer_name (IntPtr handle);
82 [MethodImpl (MethodImplOptions.InternalCall)]
83 extern static int mono_btls_x509_get_subject_name_string (IntPtr handle, IntPtr buffer, int size);
85 [MethodImpl (MethodImplOptions.InternalCall)]
86 extern static int mono_btls_x509_get_issuer_name_string (IntPtr handle, IntPtr buffer, int size);
88 [MethodImpl (MethodImplOptions.InternalCall)]
89 extern static int mono_btls_x509_get_raw_data (IntPtr handle, IntPtr bio, MonoBtlsX509Format format);
91 [MethodImpl (MethodImplOptions.InternalCall)]
92 extern static int mono_btls_x509_cmp (IntPtr a, IntPtr b);
94 [MethodImpl (MethodImplOptions.InternalCall)]
95 extern static int mono_btls_x509_get_hash (IntPtr handle, out IntPtr data);
97 [MethodImpl (MethodImplOptions.InternalCall)]
98 extern static long mono_btls_x509_get_not_before (IntPtr handle);
100 [MethodImpl (MethodImplOptions.InternalCall)]
101 extern static long mono_btls_x509_get_not_after (IntPtr handle);
103 [MethodImpl (MethodImplOptions.InternalCall)]
104 extern static int mono_btls_x509_get_public_key (IntPtr handle, IntPtr bio);
106 [MethodImpl (MethodImplOptions.InternalCall)]
107 extern static int mono_btls_x509_get_serial_number (IntPtr handle, IntPtr data, int size, int mono_style);
109 [MethodImpl (MethodImplOptions.InternalCall)]
110 extern static int mono_btls_x509_get_version (IntPtr handle);
112 [MethodImpl (MethodImplOptions.InternalCall)]
113 extern static int mono_btls_x509_get_signature_algorithm (IntPtr handle, IntPtr buffer, int size);
115 [MethodImpl (MethodImplOptions.InternalCall)]
116 extern static int mono_btls_x509_get_public_key_asn1 (IntPtr handle, IntPtr oid, int oid_size, out IntPtr data, out int size);
118 [MethodImpl (MethodImplOptions.InternalCall)]
119 extern static int mono_btls_x509_get_public_key_parameters (IntPtr handle, IntPtr oid, int oid_size, out IntPtr data, out int size);
121 [MethodImpl (MethodImplOptions.InternalCall)]
122 extern static IntPtr mono_btls_x509_get_pubkey (IntPtr handle);
124 [MethodImpl (MethodImplOptions.InternalCall)]
125 extern static int mono_btls_x509_get_subject_key_identifier (IntPtr handle, out IntPtr data, out int size);
127 [MethodImpl (MethodImplOptions.InternalCall)]
128 extern static int mono_btls_x509_print (IntPtr handle, IntPtr bio);
130 [MethodImpl (MethodImplOptions.InternalCall)]
131 extern static void mono_btls_x509_free (IntPtr handle);
133 [MethodImpl (MethodImplOptions.InternalCall)]
134 extern static IntPtr mono_btls_x509_dup (IntPtr handle);
136 [MethodImpl (MethodImplOptions.InternalCall)]
137 extern static int mono_btls_x509_add_trust_object (IntPtr handle, MonoBtlsX509Purpose purpose);
139 [MethodImpl (MethodImplOptions.InternalCall)]
140 extern static int mono_btls_x509_add_reject_object (IntPtr handle, MonoBtlsX509Purpose purpose);
142 [MethodImpl (MethodImplOptions.InternalCall)]
143 extern static int mono_btls_x509_add_explicit_trust (IntPtr handle, MonoBtlsX509TrustKind kind);
145 internal MonoBtlsX509 Copy ()
147 var copy = mono_btls_x509_up_ref (Handle.DangerousGetHandle ());
148 CheckError (copy != IntPtr.Zero);
149 return new MonoBtlsX509 (new BoringX509Handle (copy));
152 // This will actually duplicate the underlying 'X509 *' object instead of
153 // simply increasing the reference count.
154 internal MonoBtlsX509 Duplicate ()
156 var copy = mono_btls_x509_dup (Handle.DangerousGetHandle ());
157 CheckError (copy != IntPtr.Zero);
158 return new MonoBtlsX509 (new BoringX509Handle (copy));
161 public static MonoBtlsX509 LoadFromData (byte[] buffer, MonoBtlsX509Format format)
163 var data = Marshal.AllocHGlobal (buffer.Length);
164 if (data == IntPtr.Zero)
165 throw new OutOfMemoryException ();
168 Marshal.Copy (buffer, 0, data, buffer.Length);
169 var x509 = mono_btls_x509_from_data (data, buffer.Length, format);
170 if (x509 == IntPtr.Zero)
171 throw new MonoBtlsException ("Failed to read certificate from data.");
173 return new MonoBtlsX509 (new BoringX509Handle (x509));
175 Marshal.FreeHGlobal (data);
179 public MonoBtlsX509Name GetSubjectName ()
181 var handle = mono_btls_x509_get_subject_name (Handle.DangerousGetHandle ());
182 CheckError (handle != IntPtr.Zero);
183 return new MonoBtlsX509Name (new MonoBtlsX509Name.BoringX509NameHandle (handle, false));
186 public string GetSubjectNameString ()
188 const int size = 4096;
189 var data = Marshal.AllocHGlobal (size);
191 var ret = mono_btls_x509_get_subject_name_string (
192 Handle.DangerousGetHandle (), data, size);
194 return Marshal.PtrToStringAnsi (data);
196 Marshal.FreeHGlobal (data);
200 public long GetSubjectNameHash ()
203 using (var subject = GetSubjectName ())
204 return subject.GetHash ();
207 public MonoBtlsX509Name GetIssuerName ()
209 var handle = mono_btls_x509_get_issuer_name (Handle.DangerousGetHandle ());
210 CheckError (handle != IntPtr.Zero);
211 return new MonoBtlsX509Name (new MonoBtlsX509Name.BoringX509NameHandle (handle, false));
214 public string GetIssuerNameString ()
216 const int size = 4096;
217 var data = Marshal.AllocHGlobal (size);
219 var ret = mono_btls_x509_get_issuer_name_string (
220 Handle.DangerousGetHandle (), data, size);
222 return Marshal.PtrToStringAnsi (data);
224 Marshal.FreeHGlobal (data);
228 public byte[] GetRawData (MonoBtlsX509Format format)
230 using (var bio = new MonoBtlsBioMemory ()) {
231 var ret = mono_btls_x509_get_raw_data (
232 Handle.DangerousGetHandle (),
233 bio.Handle.DangerousGetHandle (),
236 return bio.GetData ();
240 public void GetRawData (MonoBtlsBio bio, MonoBtlsX509Format format)
243 var ret = mono_btls_x509_get_raw_data (
244 Handle.DangerousGetHandle (),
245 bio.Handle.DangerousGetHandle (),
250 public static int Compare (MonoBtlsX509 a, MonoBtlsX509 b)
252 return mono_btls_x509_cmp (
253 a.Handle.DangerousGetHandle (),
254 b.Handle.DangerousGetHandle ());
257 public byte[] GetCertHash ()
260 var ret = mono_btls_x509_get_hash (Handle.DangerousGetHandle (), out data);
261 CheckError (ret > 0);
262 var buffer = new byte [ret];
263 Marshal.Copy (data, buffer, 0, ret);
267 public DateTime GetNotBefore ()
269 var ticks = mono_btls_x509_get_not_before (Handle.DangerousGetHandle ());
270 return new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds (ticks);
273 public DateTime GetNotAfter ()
275 var ticks = mono_btls_x509_get_not_after (Handle.DangerousGetHandle ());
276 return new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds (ticks);
279 public byte[] GetPublicKeyData ()
281 using (var bio = new MonoBtlsBioMemory ()) {
282 var ret = mono_btls_x509_get_public_key (
283 Handle.DangerousGetHandle (),
284 bio.Handle.DangerousGetHandle ());
285 CheckError (ret > 0);
286 return bio.GetData ();
290 public byte[] GetSerialNumber (bool mono_style)
293 IntPtr data = Marshal.AllocHGlobal (size);
295 var ret = mono_btls_x509_get_serial_number (
296 Handle.DangerousGetHandle (), data,
297 size, mono_style ? 1 : 0);
298 CheckError (ret > 0);
299 var buffer = new byte [ret];
300 Marshal.Copy (data, buffer, 0, ret);
303 if (data != IntPtr.Zero)
304 Marshal.FreeHGlobal (data);
308 public int GetVersion ()
310 return mono_btls_x509_get_version (Handle.DangerousGetHandle ());
313 public Oid GetSignatureAlgorithm ()
316 IntPtr data = Marshal.AllocHGlobal (size);
318 var ret = mono_btls_x509_get_signature_algorithm (
319 Handle.DangerousGetHandle (), data, size);
320 CheckError (ret > 0);
321 return new Oid (Marshal.PtrToStringAnsi (data));
323 Marshal.FreeHGlobal (data);
327 public AsnEncodedData GetPublicKeyAsn1 ()
333 var oidData = Marshal.AllocHGlobal (256);
337 var ret = mono_btls_x509_get_public_key_asn1 (
338 Handle.DangerousGetHandle (), oidData, oidSize,
341 oid = Marshal.PtrToStringAnsi (oidData);
343 Marshal.FreeHGlobal (oidData);
347 var buffer = new byte[size];
348 Marshal.Copy (data, buffer, 0, size);
349 return new AsnEncodedData (oid.ToString (), buffer);
351 if (data != IntPtr.Zero)
356 public AsnEncodedData GetPublicKeyParameters ()
362 var oidData = Marshal.AllocHGlobal (256);
366 var ret = mono_btls_x509_get_public_key_parameters (
367 Handle.DangerousGetHandle (), oidData, oidSize,
370 oid = Marshal.PtrToStringAnsi (oidData);
372 Marshal.FreeHGlobal (oidData);
376 var buffer = new byte[size];
377 Marshal.Copy (data, buffer, 0, size);
378 return new AsnEncodedData (oid.ToString (), buffer);
380 if (data != IntPtr.Zero)
385 public byte[] GetSubjectKeyIdentifier ()
388 IntPtr data = IntPtr.Zero;
391 var ret = mono_btls_x509_get_subject_key_identifier (
392 Handle.DangerousGetHandle (), out data, out size);
394 var buffer = new byte[size];
395 Marshal.Copy (data, buffer, 0, size);
398 if (data != IntPtr.Zero)
403 public MonoBtlsKey GetPublicKey ()
405 var handle = mono_btls_x509_get_pubkey (Handle.DangerousGetHandle ());
406 CheckError (handle != IntPtr.Zero);
407 return new MonoBtlsKey (new MonoBtlsKey.BoringKeyHandle (handle));
410 public void Print (MonoBtlsBio bio)
412 var ret = mono_btls_x509_print (
413 Handle.DangerousGetHandle (),
414 bio.Handle.DangerousGetHandle ());
418 public void ExportAsPEM (MonoBtlsBio bio, bool includeHumanReadableForm)
420 GetRawData (bio, MonoBtlsX509Format.PEM);
422 if (!includeHumanReadableForm)
427 var hash = GetCertHash ();
428 var output = new StringBuilder ();
429 output.Append ("SHA1 Fingerprint=");
430 for (int i = 0; i < hash.Length; i++) {
433 output.AppendFormat ("{0:X2}", hash [i]);
435 output.AppendLine ();
436 var outputData = Encoding.ASCII.GetBytes (output.ToString ());
437 bio.Write (outputData, 0, outputData.Length);
440 public void AddTrustObject (MonoBtlsX509Purpose purpose)
443 var ret = mono_btls_x509_add_trust_object (
444 Handle.DangerousGetHandle (), purpose);
448 public void AddRejectObject (MonoBtlsX509Purpose purpose)
451 var ret = mono_btls_x509_add_reject_object (
452 Handle.DangerousGetHandle (), purpose);
456 public void AddExplicitTrust (MonoBtlsX509TrustKind kind)
459 var ret = mono_btls_x509_add_explicit_trust (
460 Handle.DangerousGetHandle (), kind);