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)]
168#[cfg(any(ossl102, boringssl, awslc))]
169pub struct TimeDiff {
170 pub days: c_int,
172 pub secs: c_int,
176}
177
178foreign_type_and_impl_send_sync! {
179 type CType = ffi::ASN1_TIME;
180 fn drop = ffi::ASN1_TIME_free;
181 pub struct Asn1Time;
192 pub struct Asn1TimeRef;
196}
197
198impl Asn1TimeRef {
199 #[corresponds(ASN1_TIME_diff)]
201 #[cfg(any(ossl102, boringssl, awslc))]
202 pub fn diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack> {
203 let mut days = 0;
204 let mut secs = 0;
205 let other = compare.as_ptr();
206
207 let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut secs, self.as_ptr(), other) };
208
209 match err {
210 0 => Err(ErrorStack::get()),
211 _ => Ok(TimeDiff { days, secs }),
212 }
213 }
214
215 #[corresponds(ASN1_TIME_compare)]
217 #[cfg(any(ossl102, boringssl, awslc))]
218 pub fn compare(&self, other: &Self) -> Result<Ordering, ErrorStack> {
219 let d = self.diff(other)?;
220 if d.days > 0 || d.secs > 0 {
221 return Ok(Ordering::Less);
222 }
223 if d.days < 0 || d.secs < 0 {
224 return Ok(Ordering::Greater);
225 }
226
227 Ok(Ordering::Equal)
228 }
229}
230
231#[cfg(any(ossl102, boringssl, awslc))]
232impl PartialEq for Asn1TimeRef {
233 fn eq(&self, other: &Asn1TimeRef) -> bool {
234 self.diff(other)
235 .map(|t| t.days == 0 && t.secs == 0)
236 .unwrap_or(false)
237 }
238}
239
240#[cfg(any(ossl102, boringssl, awslc))]
241impl PartialEq<Asn1Time> for Asn1TimeRef {
242 fn eq(&self, other: &Asn1Time) -> bool {
243 self.diff(other)
244 .map(|t| t.days == 0 && t.secs == 0)
245 .unwrap_or(false)
246 }
247}
248
249#[cfg(any(ossl102, boringssl, awslc))]
250impl PartialEq<Asn1Time> for &Asn1TimeRef {
251 fn eq(&self, other: &Asn1Time) -> bool {
252 self.diff(other)
253 .map(|t| t.days == 0 && t.secs == 0)
254 .unwrap_or(false)
255 }
256}
257
258#[cfg(any(ossl102, boringssl, awslc))]
259impl PartialOrd for Asn1TimeRef {
260 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
261 self.compare(other).ok()
262 }
263}
264
265#[cfg(any(ossl102, boringssl, awslc))]
266impl PartialOrd<Asn1Time> for Asn1TimeRef {
267 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
268 self.compare(other).ok()
269 }
270}
271
272#[cfg(any(ossl102, boringssl, awslc))]
273impl PartialOrd<Asn1Time> for &Asn1TimeRef {
274 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
275 self.compare(other).ok()
276 }
277}
278
279impl fmt::Display for Asn1TimeRef {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 unsafe {
282 let mem_bio = match MemBio::new() {
283 Err(_) => return f.write_str("error"),
284 Ok(m) => m,
285 };
286 let print_result = cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()));
287 match print_result {
288 Err(_) => f.write_str("error"),
289 Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
290 }
291 }
292 }
293}
294
295impl fmt::Debug for Asn1TimeRef {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 f.write_str(&self.to_string())
298 }
299}
300
301impl Asn1Time {
302 #[corresponds(ASN1_TIME_new)]
303 fn new() -> Result<Asn1Time, ErrorStack> {
304 ffi::init();
305
306 unsafe {
307 let handle = cvt_p(ffi::ASN1_TIME_new())?;
308 Ok(Asn1Time::from_ptr(handle))
309 }
310 }
311
312 #[corresponds(X509_gmtime_adj)]
313 fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
314 ffi::init();
315
316 unsafe {
317 let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?;
318 Ok(Asn1Time::from_ptr(handle))
319 }
320 }
321
322 pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
324 Asn1Time::from_period(days as c_long * 60 * 60 * 24)
325 }
326
327 #[corresponds(ASN1_TIME_set)]
329 pub fn from_unix(time: time_t) -> Result<Asn1Time, ErrorStack> {
330 ffi::init();
331
332 unsafe {
333 let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?;
334 Ok(Asn1Time::from_ptr(handle))
335 }
336 }
337
338 #[corresponds(ASN1_TIME_set_string)]
340 #[allow(clippy::should_implement_trait)]
341 pub fn from_str(s: &str) -> Result<Asn1Time, ErrorStack> {
342 unsafe {
343 let s = CString::new(s).unwrap();
344
345 let time = Asn1Time::new()?;
346 cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?;
347
348 Ok(time)
349 }
350 }
351
352 #[corresponds(ASN1_TIME_set_string_X509)]
356 #[cfg(any(ossl111, boringssl, awslc))]
357 pub fn from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack> {
358 unsafe {
359 let s = CString::new(s).unwrap();
360
361 let time = Asn1Time::new()?;
362 cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?;
363
364 Ok(time)
365 }
366 }
367}
368
369#[cfg(any(ossl102, boringssl, awslc))]
370impl PartialEq for Asn1Time {
371 fn eq(&self, other: &Asn1Time) -> bool {
372 self.diff(other)
373 .map(|t| t.days == 0 && t.secs == 0)
374 .unwrap_or(false)
375 }
376}
377
378#[cfg(any(ossl102, boringssl, awslc))]
379impl PartialEq<Asn1TimeRef> for Asn1Time {
380 fn eq(&self, other: &Asn1TimeRef) -> bool {
381 self.diff(other)
382 .map(|t| t.days == 0 && t.secs == 0)
383 .unwrap_or(false)
384 }
385}
386
387#[cfg(any(ossl102, boringssl, awslc))]
388impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time {
389 fn eq(&self, other: &&'a Asn1TimeRef) -> bool {
390 self.diff(other)
391 .map(|t| t.days == 0 && t.secs == 0)
392 .unwrap_or(false)
393 }
394}
395
396#[cfg(any(ossl102, boringssl, awslc))]
397impl PartialOrd for Asn1Time {
398 fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
399 self.compare(other).ok()
400 }
401}
402
403#[cfg(any(ossl102, boringssl, awslc))]
404impl PartialOrd<Asn1TimeRef> for Asn1Time {
405 fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
406 self.compare(other).ok()
407 }
408}
409
410#[cfg(any(ossl102, boringssl, awslc))]
411impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time {
412 fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering> {
413 self.compare(other).ok()
414 }
415}
416
417foreign_type_and_impl_send_sync! {
418 type CType = ffi::ASN1_STRING;
419 fn drop = ffi::ASN1_STRING_free;
420 pub struct Asn1String;
428 pub struct Asn1StringRef;
430}
431
432impl Asn1StringRef {
433 #[corresponds(ASN1_STRING_to_UTF8)]
439 pub fn as_utf8(&self) -> Result<OpensslString, ErrorStack> {
440 unsafe {
441 let mut ptr = ptr::null_mut();
442 let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
443 if len < 0 {
444 return Err(ErrorStack::get());
445 }
446
447 Ok(OpensslString::from_ptr(ptr as *mut c_char))
448 }
449 }
450
451 #[corresponds(ASN1_STRING_get0_data)]
458 pub fn as_slice(&self) -> &[u8] {
459 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) }
460 }
461
462 #[corresponds(ASN1_STRING_length)]
464 pub fn len(&self) -> usize {
465 unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize }
466 }
467
468 pub fn is_empty(&self) -> bool {
470 self.len() == 0
471 }
472}
473
474impl fmt::Debug for Asn1StringRef {
475 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
476 match self.as_utf8() {
477 Ok(openssl_string) => openssl_string.fmt(fmt),
478 Err(_) => fmt.write_str("error"),
479 }
480 }
481}
482
483foreign_type_and_impl_send_sync! {
484 type CType = ffi::ASN1_INTEGER;
485 fn drop = ffi::ASN1_INTEGER_free;
486
487 pub struct Asn1Integer;
497 pub struct Asn1IntegerRef;
499}
500
501impl Asn1Integer {
502 pub fn from_bn(bn: &BigNumRef) -> Result<Self, ErrorStack> {
510 bn.to_asn1_integer()
511 }
512}
513
514impl Ord for Asn1Integer {
515 fn cmp(&self, other: &Self) -> Ordering {
516 Asn1IntegerRef::cmp(self, other)
517 }
518}
519impl PartialOrd for Asn1Integer {
520 fn partial_cmp(&self, other: &Asn1Integer) -> Option<Ordering> {
521 Some(self.cmp(other))
522 }
523}
524impl Eq for Asn1Integer {}
525impl PartialEq for Asn1Integer {
526 fn eq(&self, other: &Asn1Integer) -> bool {
527 Asn1IntegerRef::eq(self, other)
528 }
529}
530
531impl Asn1IntegerRef {
532 #[allow(missing_docs, clippy::unnecessary_cast)]
533 #[deprecated(since = "0.10.6", note = "use to_bn instead")]
534 pub fn get(&self) -> i64 {
535 unsafe { ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 }
536 }
537
538 #[corresponds(ASN1_INTEGER_to_BN)]
540 pub fn to_bn(&self) -> Result<BigNum, ErrorStack> {
541 unsafe {
542 cvt_p(ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut()))
543 .map(|p| BigNum::from_ptr(p))
544 }
545 }
546
547 #[corresponds(ASN1_INTEGER_set)]
552 pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> {
553 unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) }
554 }
555
556 #[corresponds(ASN1_INTEGER_dup)]
558 pub fn to_owned(&self) -> Result<Asn1Integer, ErrorStack> {
559 unsafe { cvt_p(ffi::ASN1_INTEGER_dup(self.as_ptr())).map(|p| Asn1Integer::from_ptr(p)) }
560 }
561}
562
563impl Ord for Asn1IntegerRef {
564 fn cmp(&self, other: &Self) -> Ordering {
565 let res = unsafe { ffi::ASN1_INTEGER_cmp(self.as_ptr(), other.as_ptr()) };
566 res.cmp(&0)
567 }
568}
569impl PartialOrd for Asn1IntegerRef {
570 fn partial_cmp(&self, other: &Asn1IntegerRef) -> Option<Ordering> {
571 Some(self.cmp(other))
572 }
573}
574impl Eq for Asn1IntegerRef {}
575impl PartialEq for Asn1IntegerRef {
576 fn eq(&self, other: &Asn1IntegerRef) -> bool {
577 self.cmp(other) == Ordering::Equal
578 }
579}
580
581foreign_type_and_impl_send_sync! {
582 type CType = ffi::ASN1_BIT_STRING;
583 fn drop = ffi::ASN1_BIT_STRING_free;
584 pub struct Asn1BitString;
591 pub struct Asn1BitStringRef;
593}
594
595impl Asn1BitStringRef {
596 #[corresponds(ASN1_STRING_get0_data)]
598 pub fn as_slice(&self) -> &[u8] {
599 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
600 }
601
602 #[corresponds(ASN1_STRING_length)]
604 pub fn len(&self) -> usize {
605 unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize }
606 }
607
608 pub fn is_empty(&self) -> bool {
610 self.len() == 0
611 }
612}
613
614foreign_type_and_impl_send_sync! {
615 type CType = ffi::ASN1_OCTET_STRING;
616 fn drop = ffi::ASN1_OCTET_STRING_free;
617 pub struct Asn1OctetString;
619 pub struct Asn1OctetStringRef;
621}
622
623impl Asn1OctetString {
624 pub fn new_from_bytes(value: &[u8]) -> Result<Self, ErrorStack> {
626 ffi::init();
627 unsafe {
628 let s = cvt_p(ffi::ASN1_OCTET_STRING_new())?;
629 ffi::ASN1_OCTET_STRING_set(s, value.as_ptr(), value.len().try_into().unwrap());
630 Ok(Self::from_ptr(s))
631 }
632 }
633}
634
635impl Asn1OctetStringRef {
636 #[corresponds(ASN1_STRING_get0_data)]
638 pub fn as_slice(&self) -> &[u8] {
639 unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) }
640 }
641
642 #[corresponds(ASN1_STRING_length)]
644 pub fn len(&self) -> usize {
645 unsafe { ffi::ASN1_STRING_length(self.as_ptr().cast()) as usize }
646 }
647
648 pub fn is_empty(&self) -> bool {
650 self.len() == 0
651 }
652}
653
654foreign_type_and_impl_send_sync! {
655 type CType = ffi::ASN1_OBJECT;
656 fn drop = ffi::ASN1_OBJECT_free;
657 fn clone = ffi::OBJ_dup;
658
659 pub struct Asn1Object;
673 pub struct Asn1ObjectRef;
675}
676
677impl Stackable for Asn1Object {
678 type StackType = ffi::stack_st_ASN1_OBJECT;
679}
680
681impl Asn1Object {
682 #[corresponds(OBJ_txt2obj)]
684 #[allow(clippy::should_implement_trait)]
685 pub fn from_str(txt: &str) -> Result<Asn1Object, ErrorStack> {
686 unsafe {
687 ffi::init();
688 let txt = CString::new(txt).unwrap();
689 let obj: *mut ffi::ASN1_OBJECT = cvt_p(ffi::OBJ_txt2obj(txt.as_ptr() as *const _, 0))?;
690 Ok(Asn1Object::from_ptr(obj))
691 }
692 }
693
694 #[corresponds(OBJ_get0_data)]
699 #[cfg(ossl111)]
700 pub fn as_slice(&self) -> &[u8] {
701 unsafe {
702 let len = ffi::OBJ_length(self.as_ptr());
703 util::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len)
704 }
705 }
706}
707
708impl Asn1ObjectRef {
709 pub fn nid(&self) -> Nid {
711 unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) }
712 }
713}
714
715impl fmt::Display for Asn1ObjectRef {
716 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
717 unsafe {
718 let mut buf = [0; 80];
719 let len = ffi::OBJ_obj2txt(
720 buf.as_mut_ptr() as *mut _,
721 buf.len() as c_int,
722 self.as_ptr(),
723 0,
724 );
725 match str::from_utf8(&buf[..len as usize]) {
726 Err(_) => fmt.write_str("error"),
727 Ok(s) => fmt.write_str(s),
728 }
729 }
730 }
731}
732
733impl fmt::Debug for Asn1ObjectRef {
734 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
735 fmt.write_str(self.to_string().as_str())
736 }
737}
738
739cfg_if! {
740 if #[cfg(any(ossl110, libressl273, boringssl, awslc))] {
741 use ffi::ASN1_STRING_get0_data;
742 } else {
743 #[allow(bad_style)]
744 unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar {
745 ffi::ASN1_STRING_data(s)
746 }
747 }
748}
749
750foreign_type_and_impl_send_sync! {
751 type CType = ffi::ASN1_ENUMERATED;
752 fn drop = ffi::ASN1_ENUMERATED_free;
753
754 pub struct Asn1Enumerated;
756 pub struct Asn1EnumeratedRef;
758}
759
760impl Asn1EnumeratedRef {
761 #[corresponds(ASN1_ENUMERATED_get_int64)]
763 #[cfg(ossl110)]
764 pub fn get_i64(&self) -> Result<i64, ErrorStack> {
765 let mut crl_reason = 0;
766 unsafe {
767 cvt(ffi::ASN1_ENUMERATED_get_int64(
768 &mut crl_reason,
769 self.as_ptr(),
770 ))?;
771 }
772 Ok(crl_reason)
773 }
774}
775
776#[cfg(test)]
777mod tests {
778 use super::*;
779
780 use crate::bn::BigNum;
781 use crate::nid::Nid;
782
783 #[test]
785 fn bn_cvt() {
786 fn roundtrip(bn: BigNum) {
787 let large = Asn1Integer::from_bn(&bn).unwrap();
788 assert_eq!(large.to_bn().unwrap(), bn);
789 }
790
791 roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
792 roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap());
793 roundtrip(BigNum::from_u32(1234).unwrap());
794 roundtrip(-BigNum::from_u32(1234).unwrap());
795 }
796
797 #[test]
798 fn time_from_str() {
799 Asn1Time::from_str("99991231235959Z").unwrap();
800 #[cfg(ossl111)]
801 Asn1Time::from_str_x509("99991231235959Z").unwrap();
802 }
803
804 #[test]
805 fn time_from_unix() {
806 let t = Asn1Time::from_unix(0).unwrap();
807 assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string());
808 }
809
810 #[test]
811 #[cfg(any(ossl102, boringssl, awslc))]
812 fn time_eq() {
813 let a = Asn1Time::from_str("99991231235959Z").unwrap();
814 let b = Asn1Time::from_str("99991231235959Z").unwrap();
815 let c = Asn1Time::from_str("99991231235958Z").unwrap();
816 let a_ref = a.as_ref();
817 let b_ref = b.as_ref();
818 let c_ref = c.as_ref();
819 assert!(a == b);
820 assert!(a != c);
821 assert!(a == b_ref);
822 assert!(a != c_ref);
823 assert!(b_ref == a);
824 assert!(c_ref != a);
825 assert!(a_ref == b_ref);
826 assert!(a_ref != c_ref);
827 }
828
829 #[test]
830 #[cfg(any(ossl102, boringssl, awslc))]
831 fn time_ord() {
832 let a = Asn1Time::from_str("99991231235959Z").unwrap();
833 let b = Asn1Time::from_str("99991231235959Z").unwrap();
834 let c = Asn1Time::from_str("99991231235958Z").unwrap();
835 let a_ref = a.as_ref();
836 let b_ref = b.as_ref();
837 let c_ref = c.as_ref();
838 assert!(a >= b);
839 assert!(a > c);
840 assert!(b <= a);
841 assert!(c < a);
842
843 assert!(a_ref >= b);
844 assert!(a_ref > c);
845 assert!(b_ref <= a);
846 assert!(c_ref < a);
847
848 assert!(a >= b_ref);
849 assert!(a > c_ref);
850 assert!(b <= a_ref);
851 assert!(c < a_ref);
852
853 assert!(a_ref >= b_ref);
854 assert!(a_ref > c_ref);
855 assert!(b_ref <= a_ref);
856 assert!(c_ref < a_ref);
857 }
858
859 #[test]
860 fn integer_to_owned() {
861 let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
862 let b = a.to_owned().unwrap();
863 assert_eq!(
864 a.to_bn().unwrap().to_dec_str().unwrap().to_string(),
865 b.to_bn().unwrap().to_dec_str().unwrap().to_string(),
866 );
867 assert_ne!(a.as_ptr(), b.as_ptr());
868 }
869
870 #[test]
871 fn integer_cmp() {
872 let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
873 let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
874 let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap();
875 assert!(a == b);
876 assert!(a != c);
877 assert!(a < c);
878 assert!(c > b);
879 }
880
881 #[test]
882 fn object_from_str() {
883 let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
884 assert_eq!(object.nid(), Nid::SHA256);
885 }
886
887 #[test]
888 fn object_from_str_with_invalid_input() {
889 Asn1Object::from_str("NOT AN OID")
890 .map(|object| object.to_string())
891 .expect_err("parsing invalid OID should fail");
892 }
893
894 #[test]
895 #[cfg(ossl111)]
896 fn object_to_slice() {
897 let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
898 assert_eq!(
899 object.as_slice(),
900 &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01],
901 );
902 }
903
904 #[test]
905 fn asn1_octet_string() {
906 let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap();
907 assert_eq!(octet_string.as_slice(), b"hello world");
908 assert_eq!(octet_string.len(), 11);
909 }
910}