1#![deny(missing_docs)]
2
3use foreign_types::{ForeignType, ForeignTypeRef};
28use libc::{c_char, c_int, c_long, time_t};
29use std::cmp::Ordering;
30use std::convert::TryInto;
31use std::ffi::CString;
32use std::fmt;
33use std::ptr;
34use std::str;
35
36use crate::bio::MemBio;
37use crate::bn::{BigNum, BigNumRef};
38use crate::error::ErrorStack;
39use crate::nid::Nid;
40use crate::stack::Stackable;
41use crate::string::OpensslString;
42use crate::{cvt, cvt_p, util};
43use openssl_macros::corresponds;
44
45foreign_type_and_impl_send_sync! {
46 type CType = ffi::ASN1_GENERALIZEDTIME;
47 fn drop = ffi::ASN1_GENERALIZEDTIME_free;
48
49 pub struct Asn1GeneralizedTime;
61 pub struct Asn1GeneralizedTimeRef;
65}
66
67impl fmt::Display for Asn1GeneralizedTimeRef {
68 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
86impl Asn1GeneralizedTime {
87 #[corresponds(ASN1_GENERALIZEDTIME_set_string)]
90 #[allow(clippy::should_implement_trait)]
91 pub fn from_str(s: &str) -> Result<Asn1GeneralizedTime, ErrorStack> {
92 unsafe {
93 ffi::init();
94
95 let time_str = CString::new(s).unwrap();
96 let ptr = cvt_p(ffi::ASN1_GENERALIZEDTIME_new())?;
97 let time = Asn1GeneralizedTime::from_ptr(ptr);
98
99 cvt(ffi::ASN1_GENERALIZEDTIME_set_string(
100 time.as_ptr(),
101 time_str.as_ptr(),
102 ))?;
103
104 Ok(time)
105 }
106 }
107}
108
109#[derive(Debug, Copy, Clone, PartialEq, Eq)]
111pub struct Asn1Type(c_int);
112
113#[allow(missing_docs)] impl Asn1Type {
115 pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC);
116
117 pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN);
118
119 pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER);
120
121 pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING);
122
123 pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING);
124
125 pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL);
126
127 pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT);
128
129 pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR);
130
131 pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL);
132
133 pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL);
134
135 pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED);
136
137 pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING);
138
139 pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE);
140
141 pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET);
142
143 pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING);
144
145 pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING);
146
147 pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING);
148
149 pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING);
150
151 pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING);
152
153 pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING);
154
155 pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME);
156
157 pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME);
158
159 pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING);
160
161 pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING);
162
163 pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING);
164
165 pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING);
166
167 pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING);
168
169 pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING);
170
171 pub fn from_raw(value: c_int) -> Self {
173 Asn1Type(value)
174 }
175
176 pub fn as_raw(&self) -> c_int {
178 self.0
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190pub struct TimeDiff {
191 pub days: c_int,
193 pub secs: c_int,
197}
198
199foreign_type_and_impl_send_sync! {
200 type CType = ffi::ASN1_TIME;
201 fn drop = ffi::ASN1_TIME_free;
202 pub struct Asn1Time;
213 pub struct Asn1TimeRef;
217}
218
219impl Asn1TimeRef {
220 #[corresponds(ASN1_TIME_diff)]
222 pub fn diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack> {
223 let mut days = 0;
224 let mut secs = 0;
225 let other = compare.as_ptr();
226
227 let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut secs, self.as_ptr(), other) };
228
229 match err {
230 0 => Err(ErrorStack::get()),
231 _ => Ok(TimeDiff { days, secs }),
232 }
233 }
234
235 #[corresponds(ASN1_TIME_compare)]
237 pub fn compare(&self, other: &Self) -> Result<Ordering, ErrorStack> {
238 let d = self.diff(other)?;
239 if d.days > 0 || d.secs > 0 {
240 return Ok(Ordering::Less);
241 }
242 if d.days < 0 || d.secs < 0 {
243 return Ok(Ordering::Greater);
244 }
245
246 Ok(Ordering::Equal)
247 }
248}
249
250impl PartialEq for Asn1TimeRef {
251 fn eq(&self, other: &Asn1TimeRef) -> bool {
252 self.diff(other)
253 .map(|t| t.days == 0 && t.secs == 0)
254 .unwrap_or(false)
255 }
256}
257
258impl PartialEq<Asn1Time> for Asn1TimeRef {
259 fn eq(&self, other: &Asn1Time) -> bool {
260 self.diff(other)
261 .map(|t| t.days == 0 && t.secs == 0)
262 .unwrap_or(false)
263 }
264}
265
266impl PartialEq<Asn1Time> for &Asn1TimeRef {
267 fn eq(&self, other: &Asn1Time) -> bool {
268 self.diff(other)
269 .map(|t| t.days == 0 && t.secs == 0)
270 .unwrap_or(false)
271 }
272}
273
274impl PartialOrd for Asn1TimeRef {
275 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
276 self.compare(other).ok()
277 }
278}
279
280impl PartialOrd<Asn1Time> for Asn1TimeRef {
281 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
282 self.compare(other).ok()
283 }
284}
285
286impl PartialOrd<Asn1Time> for &Asn1TimeRef {
287 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
288 self.compare(other).ok()
289 }
290}
291
292impl fmt::Display for Asn1TimeRef {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 unsafe {
295 let mem_bio = match MemBio::new() {
296 Err(_) => return f.write_str("error"),
297 Ok(m) => m,
298 };
299 let print_result = cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()));
300 match print_result {
301 Err(_) => f.write_str("error"),
302 Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
303 }
304 }
305 }
306}
307
308impl fmt::Debug for Asn1TimeRef {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 f.write_str(&self.to_string())
311 }
312}
313
314impl Asn1Time {
315 #[corresponds(ASN1_TIME_new)]
316 fn new() -> Result<Asn1Time, ErrorStack> {
317 ffi::init();
318
319 unsafe {
320 let handle = cvt_p(ffi::ASN1_TIME_new())?;
321 Ok(Asn1Time::from_ptr(handle))
322 }
323 }
324
325 #[corresponds(X509_gmtime_adj)]
326 fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
327 ffi::init();
328
329 unsafe {
330 let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?;
331 Ok(Asn1Time::from_ptr(handle))
332 }
333 }
334
335 pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
337 Asn1Time::from_period(days as c_long * 60 * 60 * 24)
338 }
339
340 #[corresponds(ASN1_TIME_set)]
342 pub fn from_unix(time: time_t) -> Result<Asn1Time, ErrorStack> {
343 ffi::init();
344
345 unsafe {
346 let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?;
347 Ok(Asn1Time::from_ptr(handle))
348 }
349 }
350
351 #[corresponds(ASN1_TIME_set_string)]
353 #[allow(clippy::should_implement_trait)]
354 pub fn from_str(s: &str) -> Result<Asn1Time, ErrorStack> {
355 unsafe {
356 let s = CString::new(s).unwrap();
357
358 let time = Asn1Time::new()?;
359 cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?;
360
361 Ok(time)
362 }
363 }
364
365 #[corresponds(ASN1_TIME_set_string_X509)]
369 #[cfg(any(ossl111, boringssl, libressl360, awslc))]
370 pub fn from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack> {
371 unsafe {
372 let s = CString::new(s).unwrap();
373
374 let time = Asn1Time::new()?;
375 cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?;
376
377 Ok(time)
378 }
379 }
380}
381
382impl PartialEq for Asn1Time {
383 fn eq(&self, other: &Asn1Time) -> bool {
384 self.diff(other)
385 .map(|t| t.days == 0 && t.secs == 0)
386 .unwrap_or(false)
387 }
388}
389
390impl PartialEq<Asn1TimeRef> for Asn1Time {
391 fn eq(&self, other: &Asn1TimeRef) -> bool {
392 self.diff(other)
393 .map(|t| t.days == 0 && t.secs == 0)
394 .unwrap_or(false)
395 }
396}
397
398impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time {
399 fn eq(&self, other: &&'a Asn1TimeRef) -> bool {
400 self.diff(other)
401 .map(|t| t.days == 0 && t.secs == 0)
402 .unwrap_or(false)
403 }
404}
405
406impl PartialOrd for Asn1Time {
407 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
408 self.compare(other).ok()
409 }
410}
411
412impl PartialOrd<Asn1TimeRef> for Asn1Time {
413 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
414 self.compare(other).ok()
415 }
416}
417
418impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time {
419 fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering> {
420 self.compare(other).ok()
421 }
422}
423
424foreign_type_and_impl_send_sync! {
425 type CType = ffi::ASN1_STRING;
426 fn drop = ffi::ASN1_STRING_free;
427 pub struct Asn1String;
435 pub struct Asn1StringRef;
437}
438
439impl Asn1StringRef {
440 #[corresponds(ASN1_STRING_to_UTF8)]
446 pub fn as_utf8(&self) -> Result<OpensslString, ErrorStack> {
447 unsafe {
448 let mut ptr = ptr::null_mut();
449 let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
450 if len < 0 {
451 return Err(ErrorStack::get());
452 }
453
454 Ok(OpensslString::from_ptr(ptr as *mut c_char))
455 }
456 }
457
458 #[corresponds(ASN1_STRING_get0_data)]
465 pub fn as_slice(&self) -> &[u8] {
466 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) }
467 }
468
469 #[corresponds(ASN1_STRING_length)]
471 pub fn len(&self) -> usize {
472 unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize }
473 }
474
475 pub fn is_empty(&self) -> bool {
477 self.len() == 0
478 }
479}
480
481impl fmt::Debug for Asn1StringRef {
482 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
483 match self.as_utf8() {
484 Ok(openssl_string) => openssl_string.fmt(fmt),
485 Err(_) => fmt.write_str("error"),
486 }
487 }
488}
489
490foreign_type_and_impl_send_sync! {
491 type CType = ffi::ASN1_INTEGER;
492 fn drop = ffi::ASN1_INTEGER_free;
493
494 pub struct Asn1Integer;
504 pub struct Asn1IntegerRef;
506}
507
508impl Asn1Integer {
509 pub fn from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack> {
517 bn.to_asn1_integer()
518 }
519}
520
521impl Ord for Asn1Integer {
522 fn cmp(&self, other: &Self) -> Ordering {
523 Asn1IntegerRef::cmp(self, other)
524 }
525}
526impl PartialOrd for Asn1Integer {
527 fn partial_cmp(&self, other: &Asn1Integer) -> Option<Ordering> {
528 Some(self.cmp(other))
529 }
530}
531impl Eq for Asn1Integer {}
532impl PartialEq for Asn1Integer {
533 fn eq(&self, other: &Asn1Integer) -> bool {
534 Asn1IntegerRef::eq(self, other)
535 }
536}
537
538impl Asn1IntegerRef {
539 #[allow(missing_docs, clippy::unnecessary_cast)]
540 #[deprecated(since = "0.10.6", note = "use to_bn instead")]
541 pub fn get(&self) -> i64 {
542 unsafe { ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 }
543 }
544
545 #[corresponds(ASN1_INTEGER_to_BN)]
547 pub fn to_bn(&self) -> Result<BigNum, ErrorStack> {
548 unsafe {
549 cvt_p(ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut()))
550 .map(|p| BigNum::from_ptr(p))
551 }
552 }
553
554 #[corresponds(ASN1_INTEGER_set)]
559 pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> {
560 unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) }
561 }
562
563 #[corresponds(ASN1_INTEGER_dup)]
565 pub fn to_owned(&self) -> Result<Asn1Integer, ErrorStack> {
566 unsafe { cvt_p(ffi::ASN1_INTEGER_dup(self.as_ptr())).map(|p| Asn1Integer::from_ptr(p)) }
567 }
568}
569
570impl Ord for Asn1IntegerRef {
571 fn cmp(&self, other: &Self) -> Ordering {
572 let res = unsafe { ffi::ASN1_INTEGER_cmp(self.as_ptr(), other.as_ptr()) };
573 res.cmp(&0)
574 }
575}
576impl PartialOrd for Asn1IntegerRef {
577 fn partial_cmp(&self, other: &Asn1IntegerRef) -> Option<Ordering> {
578 Some(self.cmp(other))
579 }
580}
581impl Eq for Asn1IntegerRef {}
582impl PartialEq for Asn1IntegerRef {
583 fn eq(&self, other: &Asn1IntegerRef) -> bool {
584 self.cmp(other) == Ordering::Equal
585 }
586}
587
588foreign_type_and_impl_send_sync! {
589 type CType = ffi::ASN1_BIT_STRING;
590 fn drop = ffi::ASN1_BIT_STRING_free;
591 pub struct Asn1BitString;
598 pub struct Asn1BitStringRef;
600}
601
602impl Asn1BitStringRef {
603 #[corresponds(ASN1_STRING_get0_data)]
605 pub fn as_slice(&self) -> &[u8] {
606 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
607 }
608
609 #[corresponds(ASN1_STRING_length)]
611 pub fn len(&self) -> usize {
612 unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize }
613 }
614
615 pub fn is_empty(&self) -> bool {
617 self.len() == 0
618 }
619}
620
621foreign_type_and_impl_send_sync! {
622 type CType = ffi::ASN1_OCTET_STRING;
623 fn drop = ffi::ASN1_OCTET_STRING_free;
624 pub struct Asn1OctetString;
626 pub struct Asn1OctetStringRef;
628}
629
630impl Asn1OctetString {
631 pub fn new_from_bytes(value: &[u8]) -> Result<Self, ErrorStack> {
633 ffi::init();
634 unsafe {
635 let s = cvt_p(ffi::ASN1_OCTET_STRING_new())?;
636 ffi::ASN1_OCTET_STRING_set(s, value.as_ptr(), value.len().try_into().unwrap());
637 Ok(Self::from_ptr(s))
638 }
639 }
640}
641
642impl Asn1OctetStringRef {
643 #[corresponds(ASN1_STRING_get0_data)]
645 pub fn as_slice(&self) -> &[u8] {
646 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) }
647 }
648
649 #[corresponds(ASN1_STRING_length)]
651 pub fn len(&self) -> usize {
652 unsafe { ffi::ASN1_STRING_length(self.as_ptr().cast()) as usize }
653 }
654
655 pub fn is_empty(&self) -> bool {
657 self.len() == 0
658 }
659}
660
661foreign_type_and_impl_send_sync! {
662 type CType = ffi::ASN1_OBJECT;
663 fn drop = ffi::ASN1_OBJECT_free;
664 fn clone = ffi::OBJ_dup;
665
666 pub struct Asn1Object;
680 pub struct Asn1ObjectRef;
682}
683
684impl Stackable for Asn1Object {
685 type StackType = ffi::stack_st_ASN1_OBJECT;
686}
687
688impl Asn1Object {
689 #[corresponds(OBJ_txt2obj)]
691 #[allow(clippy::should_implement_trait)]
692 pub fn from_str(txt: &str) -> Result<Asn1Object, ErrorStack> {
693 unsafe {
694 ffi::init();
695 let txt = CString::new(txt).unwrap();
696 let obj: *mut ffi::ASN1_OBJECT = cvt_p(ffi::OBJ_txt2obj(txt.as_ptr() as *const _, 0))?;
697 Ok(Asn1Object::from_ptr(obj))
698 }
699 }
700
701 #[corresponds(OBJ_get0_data)]
706 #[cfg(ossl111)]
707 pub fn as_slice(&self) -> &[u8] {
708 unsafe {
709 let len = ffi::OBJ_length(self.as_ptr());
710 util::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len)
711 }
712 }
713}
714
715impl Asn1ObjectRef {
716 pub fn nid(&self) -> Nid {
718 unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) }
719 }
720}
721
722impl fmt::Display for Asn1ObjectRef {
723 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
724 unsafe {
725 let mut buf = [0; 80];
726 let len = ffi::OBJ_obj2txt(
727 buf.as_mut_ptr() as *mut _,
728 buf.len() as c_int,
729 self.as_ptr(),
730 0,
731 );
732 match str::from_utf8(&buf[..len as usize]) {
733 Err(_) => fmt.write_str("error"),
734 Ok(s) => fmt.write_str(s),
735 }
736 }
737 }
738}
739
740impl fmt::Debug for Asn1ObjectRef {
741 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
742 fmt.write_str(self.to_string().as_str())
743 }
744}
745
746use ffi::ASN1_STRING_get0_data;
747
748foreign_type_and_impl_send_sync! {
749 type CType = ffi::ASN1_ENUMERATED;
750 fn drop = ffi::ASN1_ENUMERATED_free;
751
752 pub struct Asn1Enumerated;
754 pub struct Asn1EnumeratedRef;
756}
757
758impl Asn1EnumeratedRef {
759 #[corresponds(ASN1_ENUMERATED_get_int64)]
761 #[cfg(ossl110)]
762 pub fn get_i64(&self) -> Result<i64, ErrorStack> {
763 let mut crl_reason = 0;
764 unsafe {
765 cvt(ffi::ASN1_ENUMERATED_get_int64(
766 &mut crl_reason,
767 self.as_ptr(),
768 ))?;
769 }
770 Ok(crl_reason)
771 }
772}
773
774#[cfg(test)]
775mod tests {
776 use super::*;
777
778 use crate::bn::BigNum;
779 use crate::nid::Nid;
780
781 #[test]
783 fn bn_cvt() {
784 fn roundtrip(bn: BigNum) {
785 let large = Asn1Integer::from_bn(&bn).unwrap();
786 assert_eq!(large.to_bn().unwrap(), bn);
787 }
788
789 roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
790 roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
791 roundtrip(BigNum::from_u32(1234).unwrap());
792 roundtrip(-BigNum::from_u32(1234).unwrap());
793 }
794
795 #[test]
796 fn time_from_str() {
797 Asn1Time::from_str("99991231235959Z").unwrap();
798 #[cfg(any(ossl111, boringssl, libressl360, awslc))]
799 Asn1Time::from_str_x509("99991231235959Z").unwrap();
800 }
801
802 #[test]
803 fn generalized_time_from_str() {
804 let time = Asn1GeneralizedTime::from_str("99991231235959Z").unwrap();
805 assert_eq!("Dec 31 23:59:59 9999 GMT", time.to_string());
806 }
807
808 #[test]
809 fn time_from_unix() {
810 let t = Asn1Time::from_unix(0).unwrap();
811 assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string());
812 }
813
814 #[test]
815 fn time_eq() {
816 let a = Asn1Time::from_str("99991231235959Z").unwrap();
817 let b = Asn1Time::from_str("99991231235959Z").unwrap();
818 let c = Asn1Time::from_str("99991231235958Z").unwrap();
819 let a_ref = a.as_ref();
820 let b_ref = b.as_ref();
821 let c_ref = c.as_ref();
822 assert!(a == b);
823 assert!(a != c);
824 assert!(a == b_ref);
825 assert!(a != c_ref);
826 assert!(b_ref == a);
827 assert!(c_ref != a);
828 assert!(a_ref == b_ref);
829 assert!(a_ref != c_ref);
830 }
831
832 #[test]
833 fn time_ord() {
834 let a = Asn1Time::from_str("99991231235959Z").unwrap();
835 let b = Asn1Time::from_str("99991231235959Z").unwrap();
836 let c = Asn1Time::from_str("99991231235958Z").unwrap();
837 let a_ref = a.as_ref();
838 let b_ref = b.as_ref();
839 let c_ref = c.as_ref();
840 assert!(a >= b);
841 assert!(a > c);
842 assert!(b <= a);
843 assert!(c < a);
844
845 assert!(a_ref >= b);
846 assert!(a_ref > c);
847 assert!(b_ref <= a);
848 assert!(c_ref < a);
849
850 assert!(a >= b_ref);
851 assert!(a > c_ref);
852 assert!(b <= a_ref);
853 assert!(c < a_ref);
854
855 assert!(a_ref >= b_ref);
856 assert!(a_ref > c_ref);
857 assert!(b_ref <= a_ref);
858 assert!(c_ref < a_ref);
859 }
860
861 #[test]
862 fn integer_to_owned() {
863 let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
864 let b = a.to_owned().unwrap();
865 assert_eq!(
866 a.to_bn().unwrap().to_dec_str().unwrap().to_string(),
867 b.to_bn().unwrap().to_dec_str().unwrap().to_string(),
868 );
869 assert_ne!(a.as_ptr(), b.as_ptr());
870 }
871
872 #[test]
873 fn integer_cmp() {
874 let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
875 let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
876 let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap();
877 assert!(a == b);
878 assert!(a != c);
879 assert!(a < c);
880 assert!(c > b);
881 }
882
883 #[test]
884 fn object_from_str() {
885 let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
886 assert_eq!(object.nid(), Nid::SHA256);
887 }
888
889 #[test]
890 fn object_from_str_with_invalid_input() {
891 Asn1Object::from_str("NOT AN OID")
892 .map(|object| object.to_string())
893 .expect_err("parsing invalid OID should fail");
894 }
895
896 #[test]
897 #[cfg(ossl111)]
898 fn object_to_slice() {
899 let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
900 assert_eq!(
901 object.as_slice(),
902 &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01],
903 );
904 }
905
906 #[test]
907 fn asn1_octet_string() {
908 let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap();
909 assert_eq!(octet_string.as_slice(), b"hello world");
910 assert_eq!(octet_string.len(), 11);
911 }
912}