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 = MemBio::new()?; 71 cvt(ffi::ASN1_GENERALIZEDTIME_print( 72 mem_bio.as_ptr(), 73 self.as_ptr(), 74 ))?; 75 write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) 76 } 77 } 78 } 79 80 /// Difference between two ASN1 times. 81 /// 82 /// This `struct` is created by the [`diff`] method on [`Asn1TimeRef`]. See its 83 /// documentation for more. 84 /// 85 /// [`diff`]: struct.Asn1TimeRef.html#method.diff 86 /// [`Asn1TimeRef`]: struct.Asn1TimeRef.html 87 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 88 #[cfg(ossl102)] 89 pub struct TimeDiff { 90 /// Difference in days 91 pub days: c_int, 92 /// Difference in seconds. 93 /// 94 /// This is always less than the number of seconds in a day. 95 pub secs: c_int, 96 } 97 98 foreign_type_and_impl_send_sync! { 99 type CType = ffi::ASN1_TIME; 100 fn drop = ffi::ASN1_TIME_free; 101 /// Time storage and comparison 102 /// 103 /// Asn1Time should be used to store and share time information 104 /// using certificates. If Asn1Time is set using a string, it must 105 /// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format. 106 /// 107 /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementaiton 108 /// used by OpenSSL. 109 /// 110 /// [ASN_TIME_set]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_set.html 111 pub struct Asn1Time; 112 /// Reference to an [`Asn1Time`] 113 /// 114 /// [`Asn1Time`]: struct.Asn1Time.html 115 pub struct Asn1TimeRef; 116 } 117 118 impl Asn1TimeRef { 119 /// Find difference between two times 120 /// 121 /// This corresponds to [`ASN1_TIME_diff`]. 122 /// 123 /// [`ASN1_TIME_diff`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_diff.html 124 #[cfg(ossl102)] diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack>125 pub fn diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack> { 126 let mut days = 0; 127 let mut seconds = 0; 128 let other = compare.as_ptr(); 129 130 let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut seconds, self.as_ptr(), other) }; 131 132 match err { 133 0 => Err(ErrorStack::get()), 134 _ => Ok(TimeDiff { 135 days: days, 136 secs: seconds, 137 }), 138 } 139 } 140 141 /// Compare two times 142 /// 143 /// This corresponds to [`ASN1_TIME_compare`] but is implemented using [`diff`] so that it is 144 /// also supported on older versions of OpenSSL. 145 /// 146 /// [`ASN1_TIME_compare`]: https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_compare.html 147 /// [`diff`]: struct.Asn1TimeRef.html#method.diff 148 #[cfg(ossl102)] compare(&self, other: &Self) -> Result<Ordering, ErrorStack>149 pub fn compare(&self, other: &Self) -> Result<Ordering, ErrorStack> { 150 let d = self.diff(other)?; 151 if d.days > 0 || d.secs > 0 { 152 return Ok(Ordering::Less); 153 } 154 if d.days < 0 || d.secs < 0 { 155 return Ok(Ordering::Greater); 156 } 157 158 Ok(Ordering::Equal) 159 } 160 } 161 162 #[cfg(ossl102)] 163 impl PartialEq for Asn1TimeRef { eq(&self, other: &Asn1TimeRef) -> bool164 fn eq(&self, other: &Asn1TimeRef) -> bool { 165 self.diff(other) 166 .map(|t| t.days == 0 && t.secs == 0) 167 .unwrap_or(false) 168 } 169 } 170 171 #[cfg(ossl102)] 172 impl PartialEq<Asn1Time> for Asn1TimeRef { eq(&self, other: &Asn1Time) -> bool173 fn eq(&self, other: &Asn1Time) -> bool { 174 self.diff(other) 175 .map(|t| t.days == 0 && t.secs == 0) 176 .unwrap_or(false) 177 } 178 } 179 180 #[cfg(ossl102)] 181 impl<'a> PartialEq<Asn1Time> for &'a Asn1TimeRef { eq(&self, other: &Asn1Time) -> bool182 fn eq(&self, other: &Asn1Time) -> bool { 183 self.diff(other) 184 .map(|t| t.days == 0 && t.secs == 0) 185 .unwrap_or(false) 186 } 187 } 188 189 #[cfg(ossl102)] 190 impl PartialOrd for Asn1TimeRef { partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering>191 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> { 192 self.compare(other).ok() 193 } 194 } 195 196 #[cfg(ossl102)] 197 impl PartialOrd<Asn1Time> for Asn1TimeRef { partial_cmp(&self, other: &Asn1Time) -> Option<Ordering>198 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> { 199 self.compare(other).ok() 200 } 201 } 202 203 #[cfg(ossl102)] 204 impl<'a> PartialOrd<Asn1Time> for &'a Asn1TimeRef { partial_cmp(&self, other: &Asn1Time) -> Option<Ordering>205 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> { 206 self.compare(other).ok() 207 } 208 } 209 210 impl fmt::Display for Asn1TimeRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 212 unsafe { 213 let mem_bio = MemBio::new()?; 214 cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()))?; 215 write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) 216 } 217 } 218 } 219 220 impl Asn1Time { new() -> Result<Asn1Time, ErrorStack>221 fn new() -> Result<Asn1Time, ErrorStack> { 222 ffi::init(); 223 224 unsafe { 225 let handle = cvt_p(ffi::ASN1_TIME_new())?; 226 Ok(Asn1Time::from_ptr(handle)) 227 } 228 } 229 from_period(period: c_long) -> Result<Asn1Time, ErrorStack>230 fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> { 231 ffi::init(); 232 233 unsafe { 234 let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?; 235 Ok(Asn1Time::from_ptr(handle)) 236 } 237 } 238 239 /// Creates a new time on specified interval in days from now days_from_now(days: u32) -> Result<Asn1Time, ErrorStack>240 pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> { 241 Asn1Time::from_period(days as c_long * 60 * 60 * 24) 242 } 243 244 /// Creates a new time from the specified `time_t` value from_unix(time: time_t) -> Result<Asn1Time, ErrorStack>245 pub fn from_unix(time: time_t) -> Result<Asn1Time, ErrorStack> { 246 ffi::init(); 247 248 unsafe { 249 let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?; 250 Ok(Asn1Time::from_ptr(handle)) 251 } 252 } 253 254 /// Creates a new time corresponding to the specified ASN1 time string. 255 /// 256 /// This corresponds to [`ASN1_TIME_set_string`]. 257 /// 258 /// [`ASN1_TIME_set_string`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html from_str(s: &str) -> Result<Asn1Time, ErrorStack>259 pub fn from_str(s: &str) -> Result<Asn1Time, ErrorStack> { 260 unsafe { 261 let s = CString::new(s).unwrap(); 262 263 let time = Asn1Time::new()?; 264 cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?; 265 266 Ok(time) 267 } 268 } 269 270 /// Creates a new time corresponding to the specified X509 time string. 271 /// 272 /// This corresponds to [`ASN1_TIME_set_string_X509`]. 273 /// 274 /// Requires OpenSSL 1.1.1 or newer. 275 /// 276 /// [`ASN1_TIME_set_string_X509`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html 277 #[cfg(ossl111)] from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack>278 pub fn from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack> { 279 unsafe { 280 let s = CString::new(s).unwrap(); 281 282 let time = Asn1Time::new()?; 283 cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?; 284 285 Ok(time) 286 } 287 } 288 } 289 290 #[cfg(ossl102)] 291 impl PartialEq for Asn1Time { eq(&self, other: &Asn1Time) -> bool292 fn eq(&self, other: &Asn1Time) -> bool { 293 self.diff(other) 294 .map(|t| t.days == 0 && t.secs == 0) 295 .unwrap_or(false) 296 } 297 } 298 299 #[cfg(ossl102)] 300 impl PartialEq<Asn1TimeRef> for Asn1Time { eq(&self, other: &Asn1TimeRef) -> bool301 fn eq(&self, other: &Asn1TimeRef) -> bool { 302 self.diff(other) 303 .map(|t| t.days == 0 && t.secs == 0) 304 .unwrap_or(false) 305 } 306 } 307 308 #[cfg(ossl102)] 309 impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time { eq(&self, other: &&'a Asn1TimeRef) -> bool310 fn eq(&self, other: &&'a Asn1TimeRef) -> bool { 311 self.diff(other) 312 .map(|t| t.days == 0 && t.secs == 0) 313 .unwrap_or(false) 314 } 315 } 316 317 #[cfg(ossl102)] 318 impl PartialOrd for Asn1Time { partial_cmp(&self, other: &Asn1Time) -> Option<Ordering>319 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> { 320 self.compare(other).ok() 321 } 322 } 323 324 #[cfg(ossl102)] 325 impl PartialOrd<Asn1TimeRef> for Asn1Time { partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering>326 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> { 327 self.compare(other).ok() 328 } 329 } 330 331 #[cfg(ossl102)] 332 impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time { partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering>333 fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering> { 334 self.compare(other).ok() 335 } 336 } 337 338 foreign_type_and_impl_send_sync! { 339 type CType = ffi::ASN1_STRING; 340 fn drop = ffi::ASN1_STRING_free; 341 /// Primary ASN.1 type used by OpenSSL 342 /// 343 /// Almost all ASN.1 types in OpenSSL are represented by ASN1_STRING 344 /// structures. This implementation uses [ASN1_STRING-to_UTF8] to preserve 345 /// compatibility with Rust's String. 346 /// 347 /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_STRING_to_UTF8.html 348 pub struct Asn1String; 349 /// Reference to [`Asn1String`] 350 /// 351 /// [`Asn1String`]: struct.Asn1String.html 352 pub struct Asn1StringRef; 353 } 354 355 impl Asn1StringRef { 356 /// Converts the ASN.1 underlying format to UTF8 357 /// 358 /// ASN.1 strings may utilize UTF-16, ASCII, BMP, or UTF8. This is important to 359 /// consume the string in a meaningful way without knowing the underlying 360 /// format. as_utf8(&self) -> Result<OpensslString, ErrorStack>361 pub fn as_utf8(&self) -> Result<OpensslString, ErrorStack> { 362 unsafe { 363 let mut ptr = ptr::null_mut(); 364 let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr()); 365 if len < 0 { 366 return Err(ErrorStack::get()); 367 } 368 369 Ok(OpensslString::from_ptr(ptr as *mut c_char)) 370 } 371 } 372 373 /// Return the string as an array of bytes 374 /// 375 /// The bytes do not directly corespond to UTF-8 encoding. To interact with 376 /// strings in rust, it is preferable to use [`as_utf8`] 377 /// 378 /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 as_slice(&self) -> &[u8]379 pub fn as_slice(&self) -> &[u8] { 380 unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } 381 } 382 383 /// Return the length of the Asn1String (number of bytes) len(&self) -> usize384 pub fn len(&self) -> usize { 385 unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } 386 } 387 } 388 389 foreign_type_and_impl_send_sync! { 390 type CType = ffi::ASN1_INTEGER; 391 fn drop = ffi::ASN1_INTEGER_free; 392 393 /// Numeric representation 394 /// 395 /// Integers in ASN.1 may include BigNum, int64 or uint64. BigNum implementation 396 /// can be found within [`bn`] module. 397 /// 398 /// OpenSSL documentation includes [`ASN1_INTEGER_set`]. 399 /// 400 /// [`bn`]: ../bn/index.html 401 /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html 402 pub struct Asn1Integer; 403 /// Reference to [`Asn1Integer`] 404 /// 405 /// [`Asn1Integer`]: struct.Asn1Integer.html 406 pub struct Asn1IntegerRef; 407 } 408 409 impl Asn1Integer { 410 /// Converts a bignum to an `Asn1Integer`. 411 /// 412 /// Corresponds to [`BN_to_ASN1_INTEGER`]. Also see 413 /// [`BigNumRef::to_asn1_integer`]. 414 /// 415 /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_to_ASN1_INTEGER.html 416 /// [`BigNumRef::to_asn1_integer`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack>417 pub fn from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack> { 418 bn.to_asn1_integer() 419 } 420 } 421 422 impl Asn1IntegerRef { 423 #[allow(missing_docs)] 424 #[deprecated(since = "0.10.6", note = "use to_bn instead")] get(&self) -> i64425 pub fn get(&self) -> i64 { 426 unsafe { ::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } 427 } 428 429 /// Converts the integer to a `BigNum`. 430 /// 431 /// This corresponds to [`ASN1_INTEGER_to_BN`]. 432 /// 433 /// [`ASN1_INTEGER_to_BN`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_get.html to_bn(&self) -> Result<BigNum, ErrorStack>434 pub fn to_bn(&self) -> Result<BigNum, ErrorStack> { 435 unsafe { 436 cvt_p(::ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut())) 437 .map(|p| BigNum::from_ptr(p)) 438 } 439 } 440 441 /// Sets the ASN.1 value to the value of a signed 32-bit integer, for larger numbers 442 /// see [`bn`]. 443 /// 444 /// OpenSSL documentation at [`ASN1_INTEGER_set`] 445 /// 446 /// [`bn`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer 447 /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html set(&mut self, value: i32) -> Result<(), ErrorStack>448 pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { 449 unsafe { cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } 450 } 451 } 452 453 foreign_type_and_impl_send_sync! { 454 type CType = ffi::ASN1_BIT_STRING; 455 fn drop = ffi::ASN1_BIT_STRING_free; 456 /// Sequence of bytes 457 /// 458 /// Asn1BitString is used in [`x509`] certificates for the signature. 459 /// The bit string acts as a collection of bytes. 460 /// 461 /// [`x509`]: ../x509/struct.X509.html#method.signature 462 pub struct Asn1BitString; 463 /// Reference to [`Asn1BitString`] 464 /// 465 /// [`Asn1BitString`]: struct.Asn1BitString.html 466 pub struct Asn1BitStringRef; 467 } 468 469 impl Asn1BitStringRef { 470 /// Returns the Asn1BitString as a slice as_slice(&self) -> &[u8]471 pub fn as_slice(&self) -> &[u8] { 472 unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } 473 } 474 /// Length of Asn1BitString in number of bytes. len(&self) -> usize475 pub fn len(&self) -> usize { 476 unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } 477 } 478 } 479 480 foreign_type_and_impl_send_sync! { 481 type CType = ffi::ASN1_OBJECT; 482 fn drop = ffi::ASN1_OBJECT_free; 483 484 /// Object Identifier 485 /// 486 /// Represents an ASN.1 Object. Typically, NIDs, or numeric identifiers 487 /// are stored as a table within the [`Nid`] module. These constants are 488 /// used to determine attributes of a certificate, such as mapping the 489 /// attribute "CommonName" to "CN" which is represented as the OID of 13. 490 /// This attribute is a constant in the [`nid::COMMONNAME`]. 491 /// 492 /// OpenSSL documentation at [`OBJ_nid2obj`] 493 /// 494 /// [`Nid`]: ../nid/index.html 495 /// [`nid::COMMONNAME`]: ../nid/constant.COMMONNAME.html 496 /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_obj2nid.html 497 pub struct Asn1Object; 498 /// Reference to [`Asn1Object`] 499 /// 500 /// [`Asn1Object`]: struct.Asn1Object.html 501 pub struct Asn1ObjectRef; 502 } 503 504 impl Asn1ObjectRef { 505 /// Returns the NID associated with this OID. nid(&self) -> Nid506 pub fn nid(&self) -> Nid { 507 unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) } 508 } 509 } 510 511 impl fmt::Display for Asn1ObjectRef { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result512 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 513 unsafe { 514 let mut buf = [0; 80]; 515 let len = ffi::OBJ_obj2txt( 516 buf.as_mut_ptr() as *mut _, 517 buf.len() as c_int, 518 self.as_ptr(), 519 0, 520 ); 521 let s = str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error)?; 522 fmt.write_str(s) 523 } 524 } 525 } 526 527 cfg_if! { 528 if #[cfg(any(ossl110, libressl273))] { 529 use ffi::ASN1_STRING_get0_data; 530 } else { 531 #[allow(bad_style)] 532 unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar { 533 ffi::ASN1_STRING_data(s) 534 } 535 } 536 } 537 538 #[cfg(test)] 539 mod tests { 540 use super::*; 541 542 use bn::BigNum; 543 544 /// Tests conversion between BigNum and Asn1Integer. 545 #[test] bn_cvt()546 fn bn_cvt() { 547 fn roundtrip(bn: BigNum) { 548 let large = Asn1Integer::from_bn(&bn).unwrap(); 549 assert_eq!(large.to_bn().unwrap(), bn); 550 } 551 552 roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); 553 roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); 554 roundtrip(BigNum::from_u32(1234).unwrap()); 555 roundtrip(-BigNum::from_u32(1234).unwrap()); 556 } 557 558 #[test] time_from_str()559 fn time_from_str() { 560 Asn1Time::from_str("99991231235959Z").unwrap(); 561 #[cfg(ossl111)] 562 Asn1Time::from_str_x509("99991231235959Z").unwrap(); 563 } 564 565 #[test] time_from_unix()566 fn time_from_unix() { 567 let t = Asn1Time::from_unix(0).unwrap(); 568 assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string()); 569 } 570 571 #[test] 572 #[cfg(ossl102)] time_eq()573 fn time_eq() { 574 let a = Asn1Time::from_str("99991231235959Z").unwrap(); 575 let b = Asn1Time::from_str("99991231235959Z").unwrap(); 576 let c = Asn1Time::from_str("99991231235958Z").unwrap(); 577 let a_ref = a.as_ref(); 578 let b_ref = b.as_ref(); 579 let c_ref = c.as_ref(); 580 assert!(a == b); 581 assert!(a != c); 582 assert!(a == b_ref); 583 assert!(a != c_ref); 584 assert!(b_ref == a); 585 assert!(c_ref != a); 586 assert!(a_ref == b_ref); 587 assert!(a_ref != c_ref); 588 } 589 590 #[test] 591 #[cfg(ossl102)] time_ord()592 fn time_ord() { 593 let a = Asn1Time::from_str("99991231235959Z").unwrap(); 594 let b = Asn1Time::from_str("99991231235959Z").unwrap(); 595 let c = Asn1Time::from_str("99991231235958Z").unwrap(); 596 let a_ref = a.as_ref(); 597 let b_ref = b.as_ref(); 598 let c_ref = c.as_ref(); 599 assert!(a >= b); 600 assert!(a > c); 601 assert!(b <= a); 602 assert!(c < a); 603 604 assert!(a_ref >= b); 605 assert!(a_ref > c); 606 assert!(b_ref <= a); 607 assert!(c_ref < a); 608 609 assert!(a >= b_ref); 610 assert!(a > c_ref); 611 assert!(b <= a_ref); 612 assert!(c < a_ref); 613 614 assert!(a_ref >= b_ref); 615 assert!(a_ref > c_ref); 616 assert!(b_ref <= a_ref); 617 assert!(c_ref < a_ref); 618 } 619 } 620