1#![deny(missing_docs)]
2
3use cfg_if::cfg_if;
28use foreign_types::{ForeignType, ForeignTypeRef};
29use libc::{c_char, c_int, c_long, time_t};
30use std::cmp::Ordering;
31use std::convert::TryInto;
32use std::ffi::CString;
33use std::fmt;
34use std::ptr;
35use std::str;
36
37use crate::bio::MemBio;
38use crate::bn::{BigNum, BigNumRef};
39use crate::error::ErrorStack;
40use crate::nid::Nid;
41use crate::stack::Stackable;
42use crate::string::OpensslString;
43use crate::{cvt, cvt_p, util};
44use openssl_macros::corresponds;
45
46foreign_type_and_impl_send_sync! {
47 type CType = ffi::ASN1_GENERALIZEDTIME;
48 fn drop = ffi::ASN1_GENERALIZEDTIME_free;
49
50 pub struct Asn1GeneralizedTime;
62 pub struct Asn1GeneralizedTimeRef;
66}
67
68impl fmt::Display for Asn1GeneralizedTimeRef {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 unsafe {
71 let mem_bio = match MemBio::new() {
72 Err(_) => return f.write_str("error"),
73 Ok(m) => m,
74 };
75 let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print(
76 mem_bio.as_ptr(),
77 self.as_ptr(),
78 ));
79 match print_result {
80 Err(_) => f.write_str("error"),
81 Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
82 }
83 }
84 }
85}
86
87#[derive(Debug, Copy, Clone, PartialEq, Eq)]
89pub struct Asn1Type(c_int);
90
91#[allow(missing_docs)] impl Asn1Type {
93 pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC);
94
95 pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN);
96
97 pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER);
98
99 pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING);
100
101 pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING);
102
103 pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL);
104
105 pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT);
106
107 pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR);
108
109 pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL);
110
111 pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL);
112
113 pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED);
114
115 pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING);
116
117 pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE);
118
119 pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET);
120
121 pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING);
122
123 pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING);
124
125 pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING);
126
127 pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING);
128
129 pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING);
130
131 pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING);
132
133 pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME);
134
135 pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME);
136
137 pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING);
138
139 pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING);
140
141 pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING);
142
143 pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING);
144
145 pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING);
146
147 pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING);
148
149 pub fn from_raw(value: c_int) -> Self {
151 Asn1Type(value)
152 }
153
154 pub fn as_raw(&self) -> c_int {
156 self.0
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Hash)]
168pub struct TimeDiff {
169 pub days: c_int,
171 pub secs: c_int,
175}
176
177foreign_type_and_impl_send_sync! {
178 type CType = ffi::ASN1_TIME;
179 fn drop = ffi::ASN1_TIME_free;
180 pub struct Asn1Time;
191 pub struct Asn1TimeRef;
195}
196
197impl Asn1TimeRef {
198 #[corresponds(ASN1_TIME_diff)]
200 pub fn diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack> {
201 let mut days = 0;
202 let mut secs = 0;
203 let other = compare.as_ptr();
204
205 let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut secs, self.as_ptr(), other) };
206
207 match err {
208 0 => Err(ErrorStack::get()),
209 _ => Ok(TimeDiff { days, secs }),
210 }
211 }
212
213 #[corresponds(ASN1_TIME_compare)]
215 pub fn compare(&self, other: &Self) -> Result<Ordering, ErrorStack> {
216 let d = self.diff(other)?;
217 if d.days > 0 || d.secs > 0 {
218 return Ok(Ordering::Less);
219 }
220 if d.days < 0 || d.secs < 0 {
221 return Ok(Ordering::Greater);
222 }
223
224 Ok(Ordering::Equal)
225 }
226}
227
228impl PartialEq for Asn1TimeRef {
229 fn eq(&self, other: &Asn1TimeRef) -> bool {
230 self.diff(other)
231 .map(|t| t.days == 0 && t.secs == 0)
232 .unwrap_or(false)
233 }
234}
235
236impl PartialEq<Asn1Time> for Asn1TimeRef {
237 fn eq(&self, other: &Asn1Time) -> bool {
238 self.diff(other)
239 .map(|t| t.days == 0 && t.secs == 0)
240 .unwrap_or(false)
241 }
242}
243
244impl PartialEq<Asn1Time> for &Asn1TimeRef {
245 fn eq(&self, other: &Asn1Time) -> bool {
246 self.diff(other)
247 .map(|t| t.days == 0 && t.secs == 0)
248 .unwrap_or(false)
249 }
250}
251
252impl PartialOrd for Asn1TimeRef {
253 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
254 self.compare(other).ok()
255 }
256}
257
258impl PartialOrd<Asn1Time> for Asn1TimeRef {
259 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
260 self.compare(other).ok()
261 }
262}
263
264impl PartialOrd<Asn1Time> for &Asn1TimeRef {
265 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
266 self.compare(other).ok()
267 }
268}
269
270impl fmt::Display for Asn1TimeRef {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 unsafe {
273 let mem_bio = match MemBio::new() {
274 Err(_) => return f.write_str("error"),
275 Ok(m) => m,
276 };
277 let print_result = cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()));
278 match print_result {
279 Err(_) => f.write_str("error"),
280 Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
281 }
282 }
283 }
284}
285
286impl fmt::Debug for Asn1TimeRef {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 f.write_str(&self.to_string())
289 }
290}
291
292impl Asn1Time {
293 #[corresponds(ASN1_TIME_new)]
294 fn new() -> Result<Asn1Time, ErrorStack> {
295 ffi::init();
296
297 unsafe {
298 let handle = cvt_p(ffi::ASN1_TIME_new())?;
299 Ok(Asn1Time::from_ptr(handle))
300 }
301 }
302
303 #[corresponds(X509_gmtime_adj)]
304 fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
305 ffi::init();
306
307 unsafe {
308 let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?;
309 Ok(Asn1Time::from_ptr(handle))
310 }
311 }
312
313 pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
315 Asn1Time::from_period(days as c_long * 60 * 60 * 24)
316 }
317
318 #[corresponds(ASN1_TIME_set)]
320 pub fn from_unix(time: time_t) -> Result<Asn1Time, ErrorStack> {
321 ffi::init();
322
323 unsafe {
324 let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?;
325 Ok(Asn1Time::from_ptr(handle))
326 }
327 }
328
329 #[corresponds(ASN1_TIME_set_string)]
331 #[allow(clippy::should_implement_trait)]
332 pub fn from_str(s: &str) -> Result<Asn1Time, ErrorStack> {
333 unsafe {
334 let s = CString::new(s).unwrap();
335
336 let time = Asn1Time::new()?;
337 cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?;
338
339 Ok(time)
340 }
341 }
342
343 #[corresponds(ASN1_TIME_set_string_X509)]
347 #[cfg(any(ossl111, boringssl, awslc))]
348 pub fn from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack> {
349 unsafe {
350 let s = CString::new(s).unwrap();
351
352 let time = Asn1Time::new()?;
353 cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?;
354
355 Ok(time)
356 }
357 }
358}
359
360impl PartialEq for Asn1Time {
361 fn eq(&self, other: &Asn1Time) -> bool {
362 self.diff(other)
363 .map(|t| t.days == 0 && t.secs == 0)
364 .unwrap_or(false)
365 }
366}
367
368impl PartialEq<Asn1TimeRef> for Asn1Time {
369 fn eq(&self, other: &Asn1TimeRef) -> bool {
370 self.diff(other)
371 .map(|t| t.days == 0 && t.secs == 0)
372 .unwrap_or(false)
373 }
374}
375
376impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time {
377 fn eq(&self, other: &&'a Asn1TimeRef) -> bool {
378 self.diff(other)
379 .map(|t| t.days == 0 && t.secs == 0)
380 .unwrap_or(false)
381 }
382}
383
384impl PartialOrd for Asn1Time {
385 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
386 self.compare(other).ok()
387 }
388}
389
390impl PartialOrd<Asn1TimeRef> for Asn1Time {
391 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
392 self.compare(other).ok()
393 }
394}
395
396impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time {
397 fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering> {
398 self.compare(other).ok()
399 }
400}
401
402foreign_type_and_impl_send_sync! {
403 type CType = ffi::ASN1_STRING;
404 fn drop = ffi::ASN1_STRING_free;
405 pub struct Asn1String;
413 pub struct Asn1StringRef;
415}
416
417impl Asn1StringRef {
418 #[corresponds(ASN1_STRING_to_UTF8)]
424 pub fn as_utf8(&self) -> Result<OpensslString, ErrorStack> {
425 unsafe {
426 let mut ptr = ptr::null_mut();
427 let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
428 if len < 0 {
429 return Err(ErrorStack::get());
430 }
431
432 Ok(OpensslString::from_ptr(ptr as *mut c_char))
433 }
434 }
435
436 #[corresponds(ASN1_STRING_get0_data)]
443 pub fn as_slice(&self) -> &[u8] {
444 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) }
445 }
446
447 #[corresponds(ASN1_STRING_length)]
449 pub fn len(&self) -> usize {
450 unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize }
451 }
452
453 pub fn is_empty(&self) -> bool {
455 self.len() == 0
456 }
457}
458
459impl fmt::Debug for Asn1StringRef {
460 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
461 match self.as_utf8() {
462 Ok(openssl_string) => openssl_string.fmt(fmt),
463 Err(_) => fmt.write_str("error"),
464 }
465 }
466}
467
468foreign_type_and_impl_send_sync! {
469 type CType = ffi::ASN1_INTEGER;
470 fn drop = ffi::ASN1_INTEGER_free;
471
472 pub struct Asn1Integer;
482 pub struct Asn1IntegerRef;
484}
485
486impl Asn1Integer {
487 pub fn from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack> {
495 bn.to_asn1_integer()
496 }
497}
498
499impl Ord for Asn1Integer {
500 fn cmp(&self, other: &Self) -> Ordering {
501 Asn1IntegerRef::cmp(self, other)
502 }
503}
504impl PartialOrd for Asn1Integer {
505 fn partial_cmp(&self, other: &Asn1Integer) -> Option<Ordering> {
506 Some(self.cmp(other))
507 }
508}
509impl Eq for Asn1Integer {}
510impl PartialEq for Asn1Integer {
511 fn eq(&self, other: &Asn1Integer) -> bool {
512 Asn1IntegerRef::eq(self, other)
513 }
514}
515
516impl Asn1IntegerRef {
517 #[allow(missing_docs, clippy::unnecessary_cast)]
518 #[deprecated(since = "0.10.6", note = "use to_bn instead")]
519 pub fn get(&self) -> i64 {
520 unsafe { ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 }
521 }
522
523 #[corresponds(ASN1_INTEGER_to_BN)]
525 pub fn to_bn(&self) -> Result<BigNum, ErrorStack> {
526 unsafe {
527 cvt_p(ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut()))
528 .map(|p| BigNum::from_ptr(p))
529 }
530 }
531
532 #[corresponds(ASN1_INTEGER_set)]
537 pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> {
538 unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) }
539 }
540
541 #[corresponds(ASN1_INTEGER_dup)]
543 pub fn to_owned(&self) -> Result<Asn1Integer, ErrorStack> {
544 unsafe { cvt_p(ffi::ASN1_INTEGER_dup(self.as_ptr())).map(|p| Asn1Integer::from_ptr(p)) }
545 }
546}
547
548impl Ord for Asn1IntegerRef {
549 fn cmp(&self, other: &Self) -> Ordering {
550 let res = unsafe { ffi::ASN1_INTEGER_cmp(self.as_ptr(), other.as_ptr()) };
551 res.cmp(&0)
552 }
553}
554impl PartialOrd for Asn1IntegerRef {
555 fn partial_cmp(&self, other: &Asn1IntegerRef) -> Option<Ordering> {
556 Some(self.cmp(other))
557 }
558}
559impl Eq for Asn1IntegerRef {}
560impl PartialEq for Asn1IntegerRef {
561 fn eq(&self, other: &Asn1IntegerRef) -> bool {
562 self.cmp(other) == Ordering::Equal
563 }
564}
565
566foreign_type_and_impl_send_sync! {
567 type CType = ffi::ASN1_BIT_STRING;
568 fn drop = ffi::ASN1_BIT_STRING_free;
569 pub struct Asn1BitString;
576 pub struct Asn1BitStringRef;
578}
579
580impl Asn1BitStringRef {
581 #[corresponds(ASN1_STRING_get0_data)]
583 pub fn as_slice(&self) -> &[u8] {
584 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
585 }
586
587 #[corresponds(ASN1_STRING_length)]
589 pub fn len(&self) -> usize {
590 unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize }
591 }
592
593 pub fn is_empty(&self) -> bool {
595 self.len() == 0
596 }
597}
598
599foreign_type_and_impl_send_sync! {
600 type CType = ffi::ASN1_OCTET_STRING;
601 fn drop = ffi::ASN1_OCTET_STRING_free;
602 pub struct Asn1OctetString;
604 pub struct Asn1OctetStringRef;
606}
607
608impl Asn1OctetString {
609 pub fn new_from_bytes(value: &[u8]) -> Result<Self, ErrorStack> {
611 ffi::init();
612 unsafe {
613 let s = cvt_p(ffi::ASN1_OCTET_STRING_new())?;
614 ffi::ASN1_OCTET_STRING_set(s, value.as_ptr(), value.len().try_into().unwrap());
615 Ok(Self::from_ptr(s))
616 }
617 }
618}
619
620impl Asn1OctetStringRef {
621 #[corresponds(ASN1_STRING_get0_data)]
623 pub fn as_slice(&self) -> &[u8] {
624 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) }
625 }
626
627 #[corresponds(ASN1_STRING_length)]
629 pub fn len(&self) -> usize {
630 unsafe { ffi::ASN1_STRING_length(self.as_ptr().cast()) as usize }
631 }
632
633 pub fn is_empty(&self) -> bool {
635 self.len() == 0
636 }
637}
638
639foreign_type_and_impl_send_sync! {
640 type CType = ffi::ASN1_OBJECT;
641 fn drop = ffi::ASN1_OBJECT_free;
642 fn clone = ffi::OBJ_dup;
643
644 pub struct Asn1Object;
658 pub struct Asn1ObjectRef;
660}
661
662impl Stackable for Asn1Object {
663 type StackType = ffi::stack_st_ASN1_OBJECT;
664}
665
666impl Asn1Object {
667 #[corresponds(OBJ_txt2obj)]
669 #[allow(clippy::should_implement_trait)]
670 pub fn from_str(txt: &str) -> Result<Asn1Object, ErrorStack> {
671 unsafe {
672 ffi::init();
673 let txt = CString::new(txt).unwrap();
674 let obj: *mut ffi::ASN1_OBJECT = cvt_p(ffi::OBJ_txt2obj(txt.as_ptr() as *const _, 0))?;
675 Ok(Asn1Object::from_ptr(obj))
676 }
677 }
678
679 #[corresponds(OBJ_get0_data)]
684 #[cfg(ossl111)]
685 pub fn as_slice(&self) -> &[u8] {
686 unsafe {
687 let len = ffi::OBJ_length(self.as_ptr());
688 util::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len)
689 }
690 }
691}
692
693impl Asn1ObjectRef {
694 pub fn nid(&self) -> Nid {
696 unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) }
697 }
698}
699
700impl fmt::Display for Asn1ObjectRef {
701 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
702 unsafe {
703 let mut buf = [0; 80];
704 let len = ffi::OBJ_obj2txt(
705 buf.as_mut_ptr() as *mut _,
706 buf.len() as c_int,
707 self.as_ptr(),
708 0,
709 );
710 match str::from_utf8(&buf[..len as usize]) {
711 Err(_) => fmt.write_str("error"),
712 Ok(s) => fmt.write_str(s),
713 }
714 }
715 }
716}
717
718impl fmt::Debug for Asn1ObjectRef {
719 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
720 fmt.write_str(self.to_string().as_str())
721 }
722}
723
724cfg_if! {
725 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
726 use ffi::ASN1_STRING_get0_data;
727 } else {
728 #[allow(bad_style)]
729 unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar {
730 ffi::ASN1_STRING_data(s)
731 }
732 }
733}
734
735foreign_type_and_impl_send_sync! {
736 type CType = ffi::ASN1_ENUMERATED;
737 fn drop = ffi::ASN1_ENUMERATED_free;
738
739 pub struct Asn1Enumerated;
741 pub struct Asn1EnumeratedRef;
743}
744
745impl Asn1EnumeratedRef {
746 #[corresponds(ASN1_ENUMERATED_get_int64)]
748 #[cfg(ossl110)]
749 pub fn get_i64(&self) -> Result<i64, ErrorStack> {
750 let mut crl_reason = 0;
751 unsafe {
752 cvt(ffi::ASN1_ENUMERATED_get_int64(
753 &mut crl_reason,
754 self.as_ptr(),
755 ))?;
756 }
757 Ok(crl_reason)
758 }
759}
760
761#[cfg(test)]
762mod tests {
763 use super::*;
764
765 use crate::bn::BigNum;
766 use crate::nid::Nid;
767
768 #[test]
770 fn bn_cvt() {
771 fn roundtrip(bn: BigNum) {
772 let large = Asn1Integer::from_bn(&bn).unwrap();
773 assert_eq!(large.to_bn().unwrap(), bn);
774 }
775
776 roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
777 roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
778 roundtrip(BigNum::from_u32(1234).unwrap());
779 roundtrip(-BigNum::from_u32(1234).unwrap());
780 }
781
782 #[test]
783 fn time_from_str() {
784 Asn1Time::from_str("99991231235959Z").unwrap();
785 #[cfg(ossl111)]
786 Asn1Time::from_str_x509("99991231235959Z").unwrap();
787 }
788
789 #[test]
790 fn time_from_unix() {
791 let t = Asn1Time::from_unix(0).unwrap();
792 assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string());
793 }
794
795 #[test]
796 fn time_eq() {
797 let a = Asn1Time::from_str("99991231235959Z").unwrap();
798 let b = Asn1Time::from_str("99991231235959Z").unwrap();
799 let c = Asn1Time::from_str("99991231235958Z").unwrap();
800 let a_ref = a.as_ref();
801 let b_ref = b.as_ref();
802 let c_ref = c.as_ref();
803 assert!(a == b);
804 assert!(a != c);
805 assert!(a == b_ref);
806 assert!(a != c_ref);
807 assert!(b_ref == a);
808 assert!(c_ref != a);
809 assert!(a_ref == b_ref);
810 assert!(a_ref != c_ref);
811 }
812
813 #[test]
814 fn time_ord() {
815 let a = Asn1Time::from_str("99991231235959Z").unwrap();
816 let b = Asn1Time::from_str("99991231235959Z").unwrap();
817 let c = Asn1Time::from_str("99991231235958Z").unwrap();
818 let a_ref = a.as_ref();
819 let b_ref = b.as_ref();
820 let c_ref = c.as_ref();
821 assert!(a >= b);
822 assert!(a > c);
823 assert!(b <= a);
824 assert!(c < a);
825
826 assert!(a_ref >= b);
827 assert!(a_ref > c);
828 assert!(b_ref <= a);
829 assert!(c_ref < a);
830
831 assert!(a >= b_ref);
832 assert!(a > c_ref);
833 assert!(b <= a_ref);
834 assert!(c < a_ref);
835
836 assert!(a_ref >= b_ref);
837 assert!(a_ref > c_ref);
838 assert!(b_ref <= a_ref);
839 assert!(c_ref < a_ref);
840 }
841
842 #[test]
843 fn integer_to_owned() {
844 let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
845 let b = a.to_owned().unwrap();
846 assert_eq!(
847 a.to_bn().unwrap().to_dec_str().unwrap().to_string(),
848 b.to_bn().unwrap().to_dec_str().unwrap().to_string(),
849 );
850 assert_ne!(a.as_ptr(), b.as_ptr());
851 }
852
853 #[test]
854 fn integer_cmp() {
855 let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
856 let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
857 let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap();
858 assert!(a == b);
859 assert!(a != c);
860 assert!(a < c);
861 assert!(c > b);
862 }
863
864 #[test]
865 fn object_from_str() {
866 let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
867 assert_eq!(object.nid(), Nid::SHA256);
868 }
869
870 #[test]
871 fn object_from_str_with_invalid_input() {
872 Asn1Object::from_str("NOT AN OID")
873 .map(|object| object.to_string())
874 .expect_err("parsing invalid OID should fail");
875 }
876
877 #[test]
878 #[cfg(ossl111)]
879 fn object_to_slice() {
880 let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
881 assert_eq!(
882 object.as_slice(),
883 &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01],
884 );
885 }
886
887 #[test]
888 fn asn1_octet_string() {
889 let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap();
890 assert_eq!(octet_string.as_slice(), b"hello world");
891 assert_eq!(octet_string.len(), 11);
892 }
893}