1 #![deny(missing_docs)]
2 
3 //! Defines the format of certificiates
4 //!
5 //! This module is used by [`x509`] and other certificate building functions
6 //! to describe time, strings, and objects.
7 //!
8 //! Abstract Syntax Notation One is an interface description language.
9 //! The specification comes from [X.208] by OSI, and rewritten in X.680.
10 //! ASN.1 describes properties of an object with a type set.  Those types
11 //! can be atomic, structured, choice, and other (CHOICE and ANY).  These
12 //! types are expressed as a number and the assignment operator ::=  gives
13 //! the type a name.
14 //!
15 //! The implementation here provides a subset of the ASN.1 types that OpenSSL
16 //! uses, especially in the properties of a certificate used in HTTPS.
17 //!
18 //! [X.208]: https://www.itu.int/rec/T-REC-X.208-198811-W/en
19 //! [`x509`]: ../x509/struct.X509Builder.html
20 //!
21 //! ## Examples
22 //!
23 //! ```
24 //! use openssl::asn1::Asn1Time;
25 //! let tomorrow = Asn1Time::days_from_now(1);
26 //! ```
27 use ffi;
28 use foreign_types::{ForeignType, ForeignTypeRef};
29 use libc::{c_char, c_int, c_long, time_t};
30 #[cfg(ossl102)]
31 use std::cmp::Ordering;
32 use std::ffi::CString;
33 use std::fmt;
34 use std::ptr;
35 use std::slice;
36 use std::str;
37 
38 use bio::MemBio;
39 use bn::{BigNum, BigNumRef};
40 use error::ErrorStack;
41 use nid::Nid;
42 use string::OpensslString;
43 use {cvt, cvt_p};
44 
45 foreign_type_and_impl_send_sync! {
46     type CType = ffi::ASN1_GENERALIZEDTIME;
47     fn drop = ffi::ASN1_GENERALIZEDTIME_free;
48 
49     /// Non-UTC representation of time
50     ///
51     /// If a time can be represented by UTCTime, UTCTime is used
52     /// otherwise, ASN1_GENERALIZEDTIME is used.  This would be, for
53     /// example outside the year range of 1950-2049.
54     ///
55     /// [ASN1_GENERALIZEDTIME_set] documentation from OpenSSL provides
56     /// further details of implmentation.  Note: these docs are from the master
57     /// branch as documentation on the 1.1.0 branch did not include this page.
58     ///
59     /// [ASN1_GENERALIZEDTIME_set]: https://www.openssl.org/docs/manmaster/man3/ASN1_GENERALIZEDTIME_set.html
60     pub struct Asn1GeneralizedTime;
61     /// Reference to a [`Asn1GeneralizedTime`]
62     ///
63     /// [`Asn1GeneralizedTime`]: struct.Asn1GeneralizedTime.html
64     pub struct Asn1GeneralizedTimeRef;
65 }
66 
67 impl fmt::Display for Asn1GeneralizedTimeRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result68     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69         unsafe {
70             let mem_bio = match MemBio::new() {
71                 Err(_) => return f.write_str("error"),
72                 Ok(m) => m,
73             };
74             let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print(
75                 mem_bio.as_ptr(),
76                 self.as_ptr(),
77             ));
78             match print_result {
79                 Err(_) => f.write_str("error"),
80                 Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
81             }
82         }
83     }
84 }
85 
86 /// Difference between two ASN1 times.
87 ///
88 /// This `struct` is created by the [`diff`] method on [`Asn1TimeRef`]. See its
89 /// documentation for more.
90 ///
91 /// [`diff`]: struct.Asn1TimeRef.html#method.diff
92 /// [`Asn1TimeRef`]: struct.Asn1TimeRef.html
93 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
94 #[cfg(ossl102)]
95 pub struct TimeDiff {
96     /// Difference in days
97     pub days: c_int,
98     /// Difference in seconds.
99     ///
100     /// This is always less than the number of seconds in a day.
101     pub secs: c_int,
102 }
103 
104 foreign_type_and_impl_send_sync! {
105     type CType = ffi::ASN1_TIME;
106     fn drop = ffi::ASN1_TIME_free;
107     /// Time storage and comparison
108     ///
109     /// Asn1Time should be used to store and share time information
110     /// using certificates.  If Asn1Time is set using a string, it must
111     /// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format.
112     ///
113     /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementation
114     /// used by OpenSSL.
115     ///
116     /// [ASN_TIME_set]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_set.html
117     pub struct Asn1Time;
118     /// Reference to an [`Asn1Time`]
119     ///
120     /// [`Asn1Time`]: struct.Asn1Time.html
121     pub struct Asn1TimeRef;
122 }
123 
124 impl Asn1TimeRef {
125     /// Find difference between two times
126     ///
127     /// This corresponds to [`ASN1_TIME_diff`].
128     ///
129     /// [`ASN1_TIME_diff`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_diff.html
130     #[cfg(ossl102)]
diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack>131     pub fn diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack> {
132         let mut days = 0;
133         let mut secs = 0;
134         let other = compare.as_ptr();
135 
136         let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut secs, self.as_ptr(), other) };
137 
138         match err {
139             0 => Err(ErrorStack::get()),
140             _ => Ok(TimeDiff { days, secs }),
141         }
142     }
143 
144     /// Compare two times
145     ///
146     /// This corresponds to [`ASN1_TIME_compare`] but is implemented using [`diff`] so that it is
147     /// also supported on older versions of OpenSSL.
148     ///
149     /// [`ASN1_TIME_compare`]: https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_compare.html
150     /// [`diff`]: struct.Asn1TimeRef.html#method.diff
151     #[cfg(ossl102)]
compare(&self, other: &Self) -> Result<Ordering, ErrorStack>152     pub fn compare(&self, other: &Self) -> Result<Ordering, ErrorStack> {
153         let d = self.diff(other)?;
154         if d.days > 0 || d.secs > 0 {
155             return Ok(Ordering::Less);
156         }
157         if d.days < 0 || d.secs < 0 {
158             return Ok(Ordering::Greater);
159         }
160 
161         Ok(Ordering::Equal)
162     }
163 }
164 
165 #[cfg(ossl102)]
166 impl PartialEq for Asn1TimeRef {
eq(&self, other: &Asn1TimeRef) -> bool167     fn eq(&self, other: &Asn1TimeRef) -> bool {
168         self.diff(other)
169             .map(|t| t.days == 0 && t.secs == 0)
170             .unwrap_or(false)
171     }
172 }
173 
174 #[cfg(ossl102)]
175 impl PartialEq<Asn1Time> for Asn1TimeRef {
eq(&self, other: &Asn1Time) -> bool176     fn eq(&self, other: &Asn1Time) -> bool {
177         self.diff(other)
178             .map(|t| t.days == 0 && t.secs == 0)
179             .unwrap_or(false)
180     }
181 }
182 
183 #[cfg(ossl102)]
184 impl<'a> PartialEq<Asn1Time> for &'a Asn1TimeRef {
eq(&self, other: &Asn1Time) -> bool185     fn eq(&self, other: &Asn1Time) -> bool {
186         self.diff(other)
187             .map(|t| t.days == 0 && t.secs == 0)
188             .unwrap_or(false)
189     }
190 }
191 
192 #[cfg(ossl102)]
193 impl PartialOrd for Asn1TimeRef {
partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering>194     fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
195         self.compare(other).ok()
196     }
197 }
198 
199 #[cfg(ossl102)]
200 impl PartialOrd<Asn1Time> for Asn1TimeRef {
partial_cmp(&self, other: &Asn1Time) -> Option<Ordering>201     fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
202         self.compare(other).ok()
203     }
204 }
205 
206 #[cfg(ossl102)]
207 impl<'a> PartialOrd<Asn1Time> for &'a Asn1TimeRef {
partial_cmp(&self, other: &Asn1Time) -> Option<Ordering>208     fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
209         self.compare(other).ok()
210     }
211 }
212 
213 impl fmt::Display for Asn1TimeRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result214     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215         unsafe {
216             let mem_bio = match MemBio::new() {
217                 Err(_) => return f.write_str("error"),
218                 Ok(m) => m,
219             };
220             let print_result = cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()));
221             match print_result {
222                 Err(_) => f.write_str("error"),
223                 Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
224             }
225         }
226     }
227 }
228 
229 impl fmt::Debug for Asn1TimeRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result230     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231         f.write_str(&self.to_string())
232     }
233 }
234 
235 impl Asn1Time {
new() -> Result<Asn1Time, ErrorStack>236     fn new() -> Result<Asn1Time, ErrorStack> {
237         ffi::init();
238 
239         unsafe {
240             let handle = cvt_p(ffi::ASN1_TIME_new())?;
241             Ok(Asn1Time::from_ptr(handle))
242         }
243     }
244 
from_period(period: c_long) -> Result<Asn1Time, ErrorStack>245     fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
246         ffi::init();
247 
248         unsafe {
249             let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?;
250             Ok(Asn1Time::from_ptr(handle))
251         }
252     }
253 
254     /// Creates a new time on specified interval in days from now
days_from_now(days: u32) -> Result<Asn1Time, ErrorStack>255     pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
256         Asn1Time::from_period(days as c_long * 60 * 60 * 24)
257     }
258 
259     /// Creates a new time from the specified `time_t` value
from_unix(time: time_t) -> Result<Asn1Time, ErrorStack>260     pub fn from_unix(time: time_t) -> Result<Asn1Time, ErrorStack> {
261         ffi::init();
262 
263         unsafe {
264             let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?;
265             Ok(Asn1Time::from_ptr(handle))
266         }
267     }
268 
269     /// Creates a new time corresponding to the specified ASN1 time string.
270     ///
271     /// This corresponds to [`ASN1_TIME_set_string`].
272     ///
273     /// [`ASN1_TIME_set_string`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html
274     #[allow(clippy::should_implement_trait)]
from_str(s: &str) -> Result<Asn1Time, ErrorStack>275     pub fn from_str(s: &str) -> Result<Asn1Time, ErrorStack> {
276         unsafe {
277             let s = CString::new(s).unwrap();
278 
279             let time = Asn1Time::new()?;
280             cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?;
281 
282             Ok(time)
283         }
284     }
285 
286     /// Creates a new time corresponding to the specified X509 time string.
287     ///
288     /// This corresponds to [`ASN1_TIME_set_string_X509`].
289     ///
290     /// Requires OpenSSL 1.1.1 or newer.
291     ///
292     /// [`ASN1_TIME_set_string_X509`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html
293     #[cfg(ossl111)]
from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack>294     pub fn from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack> {
295         unsafe {
296             let s = CString::new(s).unwrap();
297 
298             let time = Asn1Time::new()?;
299             cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?;
300 
301             Ok(time)
302         }
303     }
304 }
305 
306 #[cfg(ossl102)]
307 impl PartialEq for Asn1Time {
eq(&self, other: &Asn1Time) -> bool308     fn eq(&self, other: &Asn1Time) -> bool {
309         self.diff(other)
310             .map(|t| t.days == 0 && t.secs == 0)
311             .unwrap_or(false)
312     }
313 }
314 
315 #[cfg(ossl102)]
316 impl PartialEq<Asn1TimeRef> for Asn1Time {
eq(&self, other: &Asn1TimeRef) -> bool317     fn eq(&self, other: &Asn1TimeRef) -> bool {
318         self.diff(other)
319             .map(|t| t.days == 0 && t.secs == 0)
320             .unwrap_or(false)
321     }
322 }
323 
324 #[cfg(ossl102)]
325 impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time {
eq(&self, other: &&'a Asn1TimeRef) -> bool326     fn eq(&self, other: &&'a Asn1TimeRef) -> bool {
327         self.diff(other)
328             .map(|t| t.days == 0 && t.secs == 0)
329             .unwrap_or(false)
330     }
331 }
332 
333 #[cfg(ossl102)]
334 impl PartialOrd for Asn1Time {
partial_cmp(&self, other: &Asn1Time) -> Option<Ordering>335     fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
336         self.compare(other).ok()
337     }
338 }
339 
340 #[cfg(ossl102)]
341 impl PartialOrd<Asn1TimeRef> for Asn1Time {
partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering>342     fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
343         self.compare(other).ok()
344     }
345 }
346 
347 #[cfg(ossl102)]
348 impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time {
partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering>349     fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering> {
350         self.compare(other).ok()
351     }
352 }
353 
354 foreign_type_and_impl_send_sync! {
355     type CType = ffi::ASN1_STRING;
356     fn drop = ffi::ASN1_STRING_free;
357     /// Primary ASN.1 type used by OpenSSL
358     ///
359     /// Almost all ASN.1 types in OpenSSL are represented by ASN1_STRING
360     /// structures.  This implementation uses [ASN1_STRING-to_UTF8] to preserve
361     /// compatibility with Rust's String.
362     ///
363     /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_STRING_to_UTF8.html
364     pub struct Asn1String;
365     /// Reference to [`Asn1String`]
366     ///
367     /// [`Asn1String`]: struct.Asn1String.html
368     pub struct Asn1StringRef;
369 }
370 
371 impl Asn1StringRef {
372     /// Converts the ASN.1 underlying format to UTF8
373     ///
374     /// ASN.1 strings may utilize UTF-16, ASCII, BMP, or UTF8.  This is important to
375     /// consume the string in a meaningful way without knowing the underlying
376     /// format.
as_utf8(&self) -> Result<OpensslString, ErrorStack>377     pub fn as_utf8(&self) -> Result<OpensslString, ErrorStack> {
378         unsafe {
379             let mut ptr = ptr::null_mut();
380             let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
381             if len < 0 {
382                 return Err(ErrorStack::get());
383             }
384 
385             Ok(OpensslString::from_ptr(ptr as *mut c_char))
386         }
387     }
388 
389     /// Return the string as an array of bytes.
390     ///
391     /// The bytes do not directly correspond to UTF-8 encoding.  To interact with
392     /// strings in rust, it is preferable to use [`as_utf8`]
393     ///
394     /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8
as_slice(&self) -> &[u8]395     pub fn as_slice(&self) -> &[u8] {
396         unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) }
397     }
398 
399     /// Returns the number of bytes in the string.
len(&self) -> usize400     pub fn len(&self) -> usize {
401         unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize }
402     }
403 
404     /// Determines if the string is empty.
is_empty(&self) -> bool405     pub fn is_empty(&self) -> bool {
406         self.len() == 0
407     }
408 }
409 
410 impl fmt::Debug for Asn1StringRef {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result411     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
412         match self.as_utf8() {
413             Ok(openssl_string) => openssl_string.fmt(fmt),
414             Err(_) => fmt.write_str("error"),
415         }
416     }
417 }
418 
419 foreign_type_and_impl_send_sync! {
420     type CType = ffi::ASN1_INTEGER;
421     fn drop = ffi::ASN1_INTEGER_free;
422 
423     /// Numeric representation
424     ///
425     /// Integers in ASN.1 may include BigNum, int64 or uint64.  BigNum implementation
426     /// can be found within [`bn`] module.
427     ///
428     /// OpenSSL documentation includes [`ASN1_INTEGER_set`].
429     ///
430     /// [`bn`]: ../bn/index.html
431     /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html
432     pub struct Asn1Integer;
433     /// Reference to [`Asn1Integer`]
434     ///
435     /// [`Asn1Integer`]: struct.Asn1Integer.html
436     pub struct Asn1IntegerRef;
437 }
438 
439 impl Asn1Integer {
440     /// Converts a bignum to an `Asn1Integer`.
441     ///
442     /// Corresponds to [`BN_to_ASN1_INTEGER`]. Also see
443     /// [`BigNumRef::to_asn1_integer`].
444     ///
445     /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_to_ASN1_INTEGER.html
446     /// [`BigNumRef::to_asn1_integer`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer
from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack>447     pub fn from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack> {
448         bn.to_asn1_integer()
449     }
450 }
451 
452 impl Asn1IntegerRef {
453     #[allow(missing_docs)]
454     #[deprecated(since = "0.10.6", note = "use to_bn instead")]
get(&self) -> i64455     pub fn get(&self) -> i64 {
456         unsafe { ::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 }
457     }
458 
459     /// Converts the integer to a `BigNum`.
460     ///
461     /// This corresponds to [`ASN1_INTEGER_to_BN`].
462     ///
463     /// [`ASN1_INTEGER_to_BN`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_get.html
to_bn(&self) -> Result<BigNum, ErrorStack>464     pub fn to_bn(&self) -> Result<BigNum, ErrorStack> {
465         unsafe {
466             cvt_p(::ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut()))
467                 .map(|p| BigNum::from_ptr(p))
468         }
469     }
470 
471     /// Sets the ASN.1 value to the value of a signed 32-bit integer, for larger numbers
472     /// see [`bn`].
473     ///
474     /// OpenSSL documentation at [`ASN1_INTEGER_set`]
475     ///
476     /// [`bn`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer
477     /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html
set(&mut self, value: i32) -> Result<(), ErrorStack>478     pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> {
479         unsafe { cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) }
480     }
481 }
482 
483 foreign_type_and_impl_send_sync! {
484     type CType = ffi::ASN1_BIT_STRING;
485     fn drop = ffi::ASN1_BIT_STRING_free;
486     /// Sequence of bytes
487     ///
488     /// Asn1BitString is used in [`x509`] certificates for the signature.
489     /// The bit string acts as a collection of bytes.
490     ///
491     /// [`x509`]: ../x509/struct.X509.html#method.signature
492     pub struct Asn1BitString;
493     /// Reference to [`Asn1BitString`]
494     ///
495     /// [`Asn1BitString`]: struct.Asn1BitString.html
496     pub struct Asn1BitStringRef;
497 }
498 
499 impl Asn1BitStringRef {
500     /// Returns the Asn1BitString as a slice.
as_slice(&self) -> &[u8]501     pub fn as_slice(&self) -> &[u8] {
502         unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
503     }
504 
505     /// Returns the number of bytes in the string.
len(&self) -> usize506     pub fn len(&self) -> usize {
507         unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize }
508     }
509 
510     /// Determines if the string is empty.
is_empty(&self) -> bool511     pub fn is_empty(&self) -> bool {
512         self.len() == 0
513     }
514 }
515 
516 foreign_type_and_impl_send_sync! {
517     type CType = ffi::ASN1_OBJECT;
518     fn drop = ffi::ASN1_OBJECT_free;
519 
520     /// Object Identifier
521     ///
522     /// Represents an ASN.1 Object.  Typically, NIDs, or numeric identifiers
523     /// are stored as a table within the [`Nid`] module.  These constants are
524     /// used to determine attributes of a certificate, such as mapping the
525     /// attribute "CommonName" to "CN" which is represented as the OID of 13.
526     /// This attribute is a constant in the [`nid::COMMONNAME`].
527     ///
528     /// OpenSSL documentation at [`OBJ_nid2obj`]
529     ///
530     /// [`Nid`]: ../nid/index.html
531     /// [`nid::COMMONNAME`]: ../nid/constant.COMMONNAME.html
532     /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_obj2nid.html
533     pub struct Asn1Object;
534     /// Reference to [`Asn1Object`]
535     ///
536     /// [`Asn1Object`]: struct.Asn1Object.html
537     pub struct Asn1ObjectRef;
538 }
539 
540 impl Asn1ObjectRef {
541     /// Returns the NID associated with this OID.
nid(&self) -> Nid542     pub fn nid(&self) -> Nid {
543         unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) }
544     }
545 }
546 
547 impl fmt::Display for Asn1ObjectRef {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result548     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
549         unsafe {
550             let mut buf = [0; 80];
551             let len = ffi::OBJ_obj2txt(
552                 buf.as_mut_ptr() as *mut _,
553                 buf.len() as c_int,
554                 self.as_ptr(),
555                 0,
556             );
557             match str::from_utf8(&buf[..len as usize]) {
558                 Err(_) => fmt.write_str("error"),
559                 Ok(s) => fmt.write_str(s),
560             }
561         }
562     }
563 }
564 
565 impl fmt::Debug for Asn1ObjectRef {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result566     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
567         fmt.write_str(self.to_string().as_str())
568     }
569 }
570 
571 cfg_if! {
572     if #[cfg(any(ossl110, libressl273))] {
573         use ffi::ASN1_STRING_get0_data;
574     } else {
575         #[allow(bad_style)]
576         unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar {
577             ffi::ASN1_STRING_data(s)
578         }
579     }
580 }
581 
582 #[cfg(test)]
583 mod tests {
584     use super::*;
585 
586     use bn::BigNum;
587 
588     /// Tests conversion between BigNum and Asn1Integer.
589     #[test]
bn_cvt()590     fn bn_cvt() {
591         fn roundtrip(bn: BigNum) {
592             let large = Asn1Integer::from_bn(&bn).unwrap();
593             assert_eq!(large.to_bn().unwrap(), bn);
594         }
595 
596         roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
597         roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
598         roundtrip(BigNum::from_u32(1234).unwrap());
599         roundtrip(-BigNum::from_u32(1234).unwrap());
600     }
601 
602     #[test]
time_from_str()603     fn time_from_str() {
604         Asn1Time::from_str("99991231235959Z").unwrap();
605         #[cfg(ossl111)]
606         Asn1Time::from_str_x509("99991231235959Z").unwrap();
607     }
608 
609     #[test]
time_from_unix()610     fn time_from_unix() {
611         let t = Asn1Time::from_unix(0).unwrap();
612         assert_eq!("Jan  1 00:00:00 1970 GMT", t.to_string());
613     }
614 
615     #[test]
616     #[cfg(ossl102)]
time_eq()617     fn time_eq() {
618         let a = Asn1Time::from_str("99991231235959Z").unwrap();
619         let b = Asn1Time::from_str("99991231235959Z").unwrap();
620         let c = Asn1Time::from_str("99991231235958Z").unwrap();
621         let a_ref = a.as_ref();
622         let b_ref = b.as_ref();
623         let c_ref = c.as_ref();
624         assert!(a == b);
625         assert!(a != c);
626         assert!(a == b_ref);
627         assert!(a != c_ref);
628         assert!(b_ref == a);
629         assert!(c_ref != a);
630         assert!(a_ref == b_ref);
631         assert!(a_ref != c_ref);
632     }
633 
634     #[test]
635     #[cfg(ossl102)]
time_ord()636     fn time_ord() {
637         let a = Asn1Time::from_str("99991231235959Z").unwrap();
638         let b = Asn1Time::from_str("99991231235959Z").unwrap();
639         let c = Asn1Time::from_str("99991231235958Z").unwrap();
640         let a_ref = a.as_ref();
641         let b_ref = b.as_ref();
642         let c_ref = c.as_ref();
643         assert!(a >= b);
644         assert!(a > c);
645         assert!(b <= a);
646         assert!(c < a);
647 
648         assert!(a_ref >= b);
649         assert!(a_ref > c);
650         assert!(b_ref <= a);
651         assert!(c_ref < a);
652 
653         assert!(a >= b_ref);
654         assert!(a > c_ref);
655         assert!(b <= a_ref);
656         assert!(c < a_ref);
657 
658         assert!(a_ref >= b_ref);
659         assert!(a_ref > c_ref);
660         assert!(b_ref <= a_ref);
661         assert!(c_ref < a_ref);
662     }
663 }
664