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
26 #if SECURITY_DEP && MONO_FEATURE_BTLS
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 [DllImport (BTLS_DYLIB
)]
71 extern static IntPtr
mono_btls_x509_up_ref (IntPtr handle
);
73 [DllImport (BTLS_DYLIB
)]
74 extern static IntPtr
mono_btls_x509_from_data (IntPtr data
, int len
, MonoBtlsX509Format format
);
76 [DllImport (BTLS_DYLIB
)]
77 extern static IntPtr
mono_btls_x509_get_subject_name (IntPtr handle
);
79 [DllImport (BTLS_DYLIB
)]
80 extern static IntPtr
mono_btls_x509_get_issuer_name (IntPtr handle
);
82 [DllImport (BTLS_DYLIB
)]
83 extern static int mono_btls_x509_get_subject_name_string (IntPtr handle
, IntPtr buffer
, int size
);
85 [DllImport (BTLS_DYLIB
)]
86 extern static int mono_btls_x509_get_issuer_name_string (IntPtr handle
, IntPtr buffer
, int size
);
88 [DllImport (BTLS_DYLIB
)]
89 extern static int mono_btls_x509_get_raw_data (IntPtr handle
, IntPtr bio
, MonoBtlsX509Format format
);
91 [DllImport (BTLS_DYLIB
)]
92 extern static int mono_btls_x509_cmp (IntPtr a
, IntPtr b
);
94 [DllImport (BTLS_DYLIB
)]
95 extern static int mono_btls_x509_get_hash (IntPtr handle
, out IntPtr data
);
97 [DllImport (BTLS_DYLIB
)]
98 extern static long mono_btls_x509_get_not_before (IntPtr handle
);
100 [DllImport (BTLS_DYLIB
)]
101 extern static long mono_btls_x509_get_not_after (IntPtr handle
);
103 [DllImport (BTLS_DYLIB
)]
104 extern static int mono_btls_x509_get_public_key (IntPtr handle
, IntPtr bio
);
106 [DllImport (BTLS_DYLIB
)]
107 extern static int mono_btls_x509_get_serial_number (IntPtr handle
, IntPtr data
, int size
, int mono_style
);
109 [DllImport (BTLS_DYLIB
)]
110 extern static int mono_btls_x509_get_version (IntPtr handle
);
112 [DllImport (BTLS_DYLIB
)]
113 extern static int mono_btls_x509_get_signature_algorithm (IntPtr handle
, IntPtr buffer
, int size
);
115 [DllImport (BTLS_DYLIB
)]
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 [DllImport (BTLS_DYLIB
)]
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 [DllImport (BTLS_DYLIB
)]
122 extern static IntPtr
mono_btls_x509_get_pubkey (IntPtr handle
);
124 [DllImport (BTLS_DYLIB
)]
125 extern static int mono_btls_x509_get_subject_key_identifier (IntPtr handle
, out IntPtr data
, out int size
);
127 [DllImport (BTLS_DYLIB
)]
128 extern static int mono_btls_x509_print (IntPtr handle
, IntPtr bio
);
130 [DllImport (BTLS_DYLIB
)]
131 extern static void mono_btls_x509_free (IntPtr handle
);
133 [DllImport (BTLS_DYLIB
)]
134 extern static IntPtr
mono_btls_x509_dup (IntPtr handle
);
136 [DllImport (BTLS_DYLIB
)]
137 extern static int mono_btls_x509_add_trust_object (IntPtr handle
, MonoBtlsX509Purpose purpose
);
139 [DllImport (BTLS_DYLIB
)]
140 extern static int mono_btls_x509_add_reject_object (IntPtr handle
, MonoBtlsX509Purpose purpose
);
142 [DllImport (BTLS_DYLIB
)]
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 string 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 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
);