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