1use crate::error::{Error, Result};
13use base64::Engine;
14use serde::{Deserialize, Serialize};
15
16pub mod base64_bytes {
24 use base64::{engine::general_purpose::STANDARD, Engine};
25 use serde::{Deserialize, Deserializer, Serializer};
26
27 pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
28 where
29 S: Serializer,
30 {
31 serializer.serialize_str(&STANDARD.encode(bytes))
32 }
33
34 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
35 where
36 D: Deserializer<'de>,
37 {
38 let s = String::deserialize(deserializer)?;
39 STANDARD.decode(s).map_err(serde::de::Error::custom)
40 }
41}
42
43pub mod base64_bytes_option {
45 use base64::{engine::general_purpose::STANDARD, Engine};
46 use serde::{Deserialize, Deserializer, Serializer};
47
48 pub fn serialize<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
49 where
50 S: Serializer,
51 {
52 match bytes {
53 Some(b) => serializer.serialize_some(&STANDARD.encode(b)),
54 None => serializer.serialize_none(),
55 }
56 }
57
58 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
59 where
60 D: Deserializer<'de>,
61 {
62 let opt: Option<String> = Option::deserialize(deserializer)?;
63 match opt {
64 Some(s) => STANDARD
65 .decode(s)
66 .map(Some)
67 .map_err(serde::de::Error::custom),
68 None => Ok(None),
69 }
70 }
71}
72
73pub mod hex_bytes {
75 use serde::{Deserialize, Deserializer, Serializer};
76
77 pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
78 where
79 S: Serializer,
80 {
81 serializer.serialize_str(&hex::encode(bytes))
82 }
83
84 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
85 where
86 D: Deserializer<'de>,
87 {
88 let s = String::deserialize(deserializer)?;
89 hex::decode(s).map_err(serde::de::Error::custom)
90 }
91}
92
93pub mod string_i64 {
98 use serde::{Deserialize, Deserializer, Serializer};
99
100 pub fn serialize<S>(value: &i64, serializer: S) -> Result<S::Ok, S::Error>
101 where
102 S: Serializer,
103 {
104 serializer.serialize_str(&value.to_string())
105 }
106
107 pub fn deserialize<'de, D>(deserializer: D) -> Result<i64, D::Error>
108 where
109 D: Deserializer<'de>,
110 {
111 let s = String::deserialize(deserializer)?;
112 s.parse::<i64>()
113 .map_err(|_| serde::de::Error::custom(format!("invalid integer: {}", s)))
114 }
115}
116
117macro_rules! base64_newtype {
122 ($(#[$meta:meta])* $name:ident) => {
123 $(#[$meta])*
124 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
125 pub struct $name(Vec<u8>);
126
127 impl $name {
128 pub fn new(bytes: Vec<u8>) -> Self {
130 Self(bytes)
131 }
132
133 pub fn from_bytes(bytes: &[u8]) -> Self {
135 Self(bytes.to_vec())
136 }
137
138 pub fn from_base64(s: &str) -> Result<Self> {
140 let bytes = base64::engine::general_purpose::STANDARD
141 .decode(s)
142 .map_err(|e| Error::InvalidEncoding(format!("invalid base64: {}", e)))?;
143 Ok(Self(bytes))
144 }
145
146 pub fn to_base64(&self) -> String {
148 base64::engine::general_purpose::STANDARD.encode(&self.0)
149 }
150
151 pub fn as_bytes(&self) -> &[u8] {
153 &self.0
154 }
155
156 pub fn into_bytes(self) -> Vec<u8> {
158 self.0
159 }
160
161 pub fn len(&self) -> usize {
163 self.0.len()
164 }
165
166 pub fn is_empty(&self) -> bool {
168 self.0.is_empty()
169 }
170 }
171
172 impl AsRef<[u8]> for $name {
173 fn as_ref(&self) -> &[u8] {
174 &self.0
175 }
176 }
177
178 impl From<Vec<u8>> for $name {
179 fn from(bytes: Vec<u8>) -> Self {
180 Self(bytes)
181 }
182 }
183
184 impl From<&[u8]> for $name {
185 fn from(bytes: &[u8]) -> Self {
186 Self(bytes.to_vec())
187 }
188 }
189
190 impl std::fmt::Display for $name {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 write!(f, "{}", self.to_base64())
193 }
194 }
195
196 impl serde::Serialize for $name {
197 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
198 where
199 S: serde::Serializer,
200 {
201 serializer.serialize_str(&self.to_base64())
202 }
203 }
204
205 impl<'de> serde::Deserialize<'de> for $name {
206 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
207 where
208 D: serde::Deserializer<'de>,
209 {
210 let s = String::deserialize(deserializer)?;
211 Self::from_base64(&s).map_err(serde::de::Error::custom)
212 }
213 }
214 };
215}
216
217base64_newtype!(
222 DerCertificate
239);
240
241impl DerCertificate {
242 pub fn from_pem(pem_str: &str) -> Result<Self> {
247 let parsed = pem::parse(pem_str)
248 .map_err(|e| Error::InvalidEncoding(format!("failed to parse PEM: {}", e)))?;
249
250 if parsed.tag() != "CERTIFICATE" {
251 return Err(Error::InvalidEncoding(format!(
252 "expected CERTIFICATE PEM block, got {}",
253 parsed.tag()
254 )));
255 }
256
257 Ok(Self::new(parsed.contents().to_vec()))
258 }
259
260 pub fn to_pem(&self) -> String {
262 let pem_block = pem::Pem::new("CERTIFICATE", self.as_bytes());
263 pem::encode(&pem_block)
264 }
265}
266
267base64_newtype!(
268 DerPublicKey
285);
286
287impl DerPublicKey {
288 pub fn from_pem(pem_str: &str) -> Result<Self> {
293 let parsed = pem::parse(pem_str)
294 .map_err(|e| Error::InvalidEncoding(format!("failed to parse PEM: {}", e)))?;
295
296 if parsed.tag() != "PUBLIC KEY" {
297 return Err(Error::InvalidEncoding(format!(
298 "expected PUBLIC KEY PEM block, got {}",
299 parsed.tag()
300 )));
301 }
302
303 Ok(Self::new(parsed.contents().to_vec()))
304 }
305
306 pub fn to_pem(&self) -> String {
308 let pem_block = pem::Pem::new("PUBLIC KEY", self.as_bytes());
309 pem::encode(&pem_block)
310 }
311}
312
313base64_newtype!(
314 SignatureBytes
319);
320
321base64_newtype!(
322 PayloadBytes
327);
328
329base64_newtype!(
330 CanonicalizedBody
335);
336
337base64_newtype!(
338 SignedTimestamp
343);
344
345base64_newtype!(
346 TimestampToken
351);
352
353base64_newtype!(
354 PemContent
359);
360
361#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
369#[serde(transparent)]
370pub struct EntryUuid(String);
371
372impl EntryUuid {
373 pub fn new(s: String) -> Self {
374 EntryUuid(s)
375 }
376
377 pub fn as_str(&self) -> &str {
378 &self.0
379 }
380
381 pub fn into_string(self) -> String {
382 self.0
383 }
384
385 pub fn is_empty(&self) -> bool {
386 self.0.is_empty()
387 }
388}
389
390impl From<String> for EntryUuid {
391 fn from(s: String) -> Self {
392 EntryUuid::new(s)
393 }
394}
395
396impl AsRef<str> for EntryUuid {
397 fn as_ref(&self) -> &str {
398 &self.0
399 }
400}
401
402impl std::fmt::Display for EntryUuid {
403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 write!(f, "{}", self.0)
405 }
406}
407
408#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
414pub struct LogIndex(i64);
415
416impl LogIndex {
417 pub fn new(index: i64) -> Self {
418 LogIndex(index)
419 }
420
421 pub fn value(&self) -> i64 {
422 self.0
423 }
424
425 pub fn as_u64(&self) -> Option<u64> {
426 if self.0 >= 0 {
427 Some(self.0 as u64)
428 } else {
429 None
430 }
431 }
432}
433
434impl From<i64> for LogIndex {
435 fn from(index: i64) -> Self {
436 LogIndex::new(index)
437 }
438}
439
440impl From<u64> for LogIndex {
441 fn from(index: u64) -> Self {
442 LogIndex::new(index as i64)
443 }
444}
445
446impl std::fmt::Display for LogIndex {
447 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
448 write!(f, "{}", self.0)
449 }
450}
451
452impl Serialize for LogIndex {
453 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
454 where
455 S: serde::Serializer,
456 {
457 serializer.serialize_str(&self.0.to_string())
459 }
460}
461
462impl<'de> Deserialize<'de> for LogIndex {
463 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
464 where
465 D: serde::Deserializer<'de>,
466 {
467 use serde::de::{self, Visitor};
468
469 struct LogIndexVisitor;
470
471 impl<'de> Visitor<'de> for LogIndexVisitor {
472 type Value = LogIndex;
473
474 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
475 formatter.write_str("an integer or string representing a log index")
476 }
477
478 fn visit_i64<E>(self, value: i64) -> std::result::Result<LogIndex, E>
479 where
480 E: de::Error,
481 {
482 Ok(LogIndex::new(value))
483 }
484
485 fn visit_u64<E>(self, value: u64) -> std::result::Result<LogIndex, E>
486 where
487 E: de::Error,
488 {
489 Ok(LogIndex::new(value as i64))
490 }
491
492 fn visit_str<E>(self, value: &str) -> std::result::Result<LogIndex, E>
493 where
494 E: de::Error,
495 {
496 value
497 .parse::<i64>()
498 .map(LogIndex::new)
499 .map_err(|_| de::Error::custom(format!("invalid log index: {}", value)))
500 }
501 }
502
503 deserializer.deserialize_any(LogIndexVisitor)
504 }
505}
506
507#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
511#[serde(transparent)]
512pub struct LogKeyId(String);
513
514impl LogKeyId {
515 pub fn new(s: String) -> Self {
516 LogKeyId(s)
517 }
518
519 pub fn from_bytes(bytes: &[u8]) -> Self {
521 LogKeyId(base64::engine::general_purpose::STANDARD.encode(bytes))
522 }
523
524 pub fn decode(&self) -> Result<Vec<u8>> {
526 base64::engine::general_purpose::STANDARD
527 .decode(&self.0)
528 .map_err(|e| Error::InvalidEncoding(format!("invalid base64 in log key id: {}", e)))
529 }
530
531 pub fn as_str(&self) -> &str {
532 &self.0
533 }
534
535 pub fn into_string(self) -> String {
536 self.0
537 }
538}
539
540impl From<String> for LogKeyId {
541 fn from(s: String) -> Self {
542 LogKeyId::new(s)
543 }
544}
545
546impl AsRef<str> for LogKeyId {
547 fn as_ref(&self) -> &str {
548 &self.0
549 }
550}
551
552impl std::fmt::Display for LogKeyId {
553 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
554 write!(f, "{}", self.0)
555 }
556}
557
558#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
562#[serde(transparent)]
563pub struct KeyId(String);
564
565impl KeyId {
566 pub fn new(s: String) -> Self {
567 KeyId(s)
568 }
569
570 pub fn as_str(&self) -> &str {
571 &self.0
572 }
573
574 pub fn into_string(self) -> String {
575 self.0
576 }
577
578 pub fn is_empty(&self) -> bool {
579 self.0.is_empty()
580 }
581}
582
583impl From<String> for KeyId {
584 fn from(s: String) -> Self {
585 KeyId::new(s)
586 }
587}
588
589impl AsRef<str> for KeyId {
590 fn as_ref(&self) -> &str {
591 &self.0
592 }
593}
594
595impl std::fmt::Display for KeyId {
596 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
597 write!(f, "{}", self.0)
598 }
599}
600
601#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
610#[serde(transparent)]
611pub struct KeyHint(#[serde(with = "base64_bytes_array4")] [u8; 4]);
612
613impl KeyHint {
614 pub fn new(bytes: [u8; 4]) -> Self {
616 KeyHint(bytes)
617 }
618
619 pub fn try_from_slice(slice: &[u8]) -> crate::error::Result<Self> {
621 if slice.len() != 4 {
622 return Err(crate::error::Error::Validation(format!(
623 "key hint must be exactly 4 bytes, got {}",
624 slice.len()
625 )));
626 }
627 let mut arr = [0u8; 4];
628 arr.copy_from_slice(slice);
629 Ok(KeyHint(arr))
630 }
631
632 pub fn as_bytes(&self) -> &[u8; 4] {
634 &self.0
635 }
636
637 pub fn as_slice(&self) -> &[u8] {
639 &self.0
640 }
641}
642
643impl From<[u8; 4]> for KeyHint {
644 fn from(bytes: [u8; 4]) -> Self {
645 KeyHint::new(bytes)
646 }
647}
648
649impl AsRef<[u8]> for KeyHint {
650 fn as_ref(&self) -> &[u8] {
651 &self.0
652 }
653}
654
655mod base64_bytes_array4 {
657 use base64::{engine::general_purpose::STANDARD, Engine};
658 use serde::{Deserialize, Deserializer, Serializer};
659
660 pub fn serialize<S>(bytes: &[u8; 4], serializer: S) -> Result<S::Ok, S::Error>
661 where
662 S: Serializer,
663 {
664 serializer.serialize_str(&STANDARD.encode(bytes))
665 }
666
667 pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 4], D::Error>
668 where
669 D: Deserializer<'de>,
670 {
671 let s = String::deserialize(deserializer)?;
672 let bytes = STANDARD
673 .decode(&s)
674 .map_err(|e| serde::de::Error::custom(format!("invalid base64: {}", e)))?;
675 if bytes.len() != 4 {
676 return Err(serde::de::Error::custom(format!(
677 "expected 4 bytes, got {}",
678 bytes.len()
679 )));
680 }
681 let mut arr = [0u8; 4];
682 arr.copy_from_slice(&bytes);
683 Ok(arr)
684 }
685}
686
687#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
696pub struct Sha256Hash([u8; 32]);
697
698impl Sha256Hash {
699 pub fn from_bytes(bytes: [u8; 32]) -> Self {
700 Sha256Hash(bytes)
701 }
702
703 pub fn try_from_slice(bytes: &[u8]) -> Result<Self> {
704 if bytes.len() != 32 {
705 return Err(Error::InvalidEncoding(format!(
706 "SHA-256 hash must be 32 bytes, got {}",
707 bytes.len()
708 )));
709 }
710 let mut arr = [0u8; 32];
711 arr.copy_from_slice(bytes);
712 Ok(Sha256Hash(arr))
713 }
714
715 pub fn from_hex(hex_str: &str) -> Result<Self> {
716 let bytes = hex::decode(hex_str)
717 .map_err(|e| Error::InvalidEncoding(format!("invalid hex: {}", e)))?;
718 Self::try_from_slice(&bytes)
719 }
720
721 pub fn from_base64(s: &str) -> Result<Self> {
722 let bytes = base64::engine::general_purpose::STANDARD
723 .decode(s)
724 .map_err(|e| Error::InvalidEncoding(format!("invalid base64: {}", e)))?;
725 Self::try_from_slice(&bytes)
726 }
727
728 pub fn from_hex_or_base64(s: &str) -> Result<Self> {
730 if s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit()) {
731 return Self::from_hex(s);
732 }
733 Self::from_base64(s)
734 }
735
736 pub fn to_hex(&self) -> String {
737 hex::encode(self.0)
738 }
739
740 pub fn to_base64(&self) -> String {
741 base64::engine::general_purpose::STANDARD.encode(self.0)
742 }
743
744 pub fn as_bytes(&self) -> &[u8; 32] {
745 &self.0
746 }
747
748 pub fn as_slice(&self) -> &[u8] {
749 &self.0
750 }
751}
752
753impl AsRef<[u8]> for Sha256Hash {
754 fn as_ref(&self) -> &[u8] {
755 &self.0
756 }
757}
758
759impl From<[u8; 32]> for Sha256Hash {
760 fn from(bytes: [u8; 32]) -> Self {
761 Sha256Hash(bytes)
762 }
763}
764
765impl serde::Serialize for Sha256Hash {
766 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
767 where
768 S: serde::Serializer,
769 {
770 serializer.serialize_str(&self.to_base64())
771 }
772}
773
774impl<'de> serde::Deserialize<'de> for Sha256Hash {
775 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
776 where
777 D: serde::Deserializer<'de>,
778 {
779 let s = String::deserialize(deserializer)?;
780 Sha256Hash::from_hex_or_base64(&s).map_err(serde::de::Error::custom)
781 }
782}
783
784#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
793#[serde(transparent)]
794pub struct HexLogId(String);
795
796impl HexLogId {
797 pub fn new(s: String) -> Self {
798 HexLogId(s)
799 }
800
801 pub fn from_bytes(bytes: &[u8]) -> Self {
803 HexLogId(hex::encode(bytes))
804 }
805
806 pub fn decode(&self) -> Result<Vec<u8>> {
808 hex::decode(&self.0).map_err(|e| Error::InvalidEncoding(format!("invalid hex: {}", e)))
809 }
810
811 pub fn to_base64(&self) -> Result<String> {
813 let bytes = self.decode()?;
814 Ok(base64::engine::general_purpose::STANDARD.encode(&bytes))
815 }
816
817 pub fn as_str(&self) -> &str {
818 &self.0
819 }
820
821 pub fn into_string(self) -> String {
822 self.0
823 }
824}
825
826impl From<String> for HexLogId {
827 fn from(s: String) -> Self {
828 HexLogId::new(s)
829 }
830}
831
832impl AsRef<str> for HexLogId {
833 fn as_ref(&self) -> &str {
834 &self.0
835 }
836}
837
838impl std::fmt::Display for HexLogId {
839 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
840 write!(f, "{}", self.0)
841 }
842}
843
844#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
852#[serde(transparent)]
853pub struct HexHash(String);
854
855impl HexHash {
856 pub fn new(s: String) -> Self {
857 HexHash(s)
858 }
859
860 pub fn from_bytes(bytes: &[u8]) -> Self {
861 HexHash(hex::encode(bytes))
862 }
863
864 pub fn decode(&self) -> Result<Vec<u8>> {
865 hex::decode(&self.0).map_err(|e| Error::InvalidEncoding(format!("invalid hex: {}", e)))
866 }
867
868 pub fn as_str(&self) -> &str {
869 &self.0
870 }
871
872 pub fn into_string(self) -> String {
873 self.0
874 }
875
876 pub fn to_sha256(&self) -> Result<Sha256Hash> {
878 Sha256Hash::from_hex(&self.0)
879 }
880}
881
882impl From<String> for HexHash {
883 fn from(s: String) -> Self {
884 HexHash::new(s)
885 }
886}
887
888impl AsRef<str> for HexHash {
889 fn as_ref(&self) -> &str {
890 &self.0
891 }
892}
893
894impl std::fmt::Display for HexHash {
895 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
896 write!(f, "{}", self.0)
897 }
898}
899
900#[cfg(test)]
901mod tests {
902 use super::*;
903
904 #[test]
905 fn test_der_certificate_roundtrip() {
906 let cert = DerCertificate::from_bytes(b"fake cert data");
907 let json = serde_json::to_string(&cert).unwrap();
908 let decoded: DerCertificate = serde_json::from_str(&json).unwrap();
909 assert_eq!(cert, decoded);
910 }
911
912 #[test]
913 fn test_signature_bytes_roundtrip() {
914 let sig = SignatureBytes::from_bytes(b"fake signature");
915 let json = serde_json::to_string(&sig).unwrap();
916 let decoded: SignatureBytes = serde_json::from_str(&json).unwrap();
917 assert_eq!(sig, decoded);
918 }
919
920 #[test]
921 fn test_sha256_hash() {
922 let hash_hex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
923 let hash = Sha256Hash::from_hex(hash_hex).unwrap();
924 assert_eq!(hash.to_hex(), hash_hex);
925
926 let json_hex = format!("\"{}\"", hash_hex);
928 let from_hex: Sha256Hash = serde_json::from_str(&json_hex).unwrap();
929 assert_eq!(hash, from_hex);
930 }
931
932 #[test]
933 fn test_hex_log_id() {
934 let bytes = vec![1, 2, 3, 4];
935 let log_id = HexLogId::from_bytes(&bytes);
936 assert_eq!(log_id.as_str(), "01020304");
937 assert_eq!(log_id.decode().unwrap(), bytes);
938 assert_eq!(log_id.to_base64().unwrap(), "AQIDBA==");
939 }
940
941 #[test]
942 fn test_log_key_id() {
943 let bytes = vec![1, 2, 3, 4];
944 let key_id = LogKeyId::from_bytes(&bytes);
945 assert_eq!(key_id.decode().unwrap(), bytes);
946 }
947
948 #[test]
949 fn test_certificate_from_pem() {
950 let pem = "-----BEGIN CERTIFICATE-----\nYWJjZA==\n-----END CERTIFICATE-----";
951 let cert = DerCertificate::from_pem(pem).unwrap();
952 assert_eq!(cert.as_bytes(), b"abcd");
953 }
954
955 #[test]
956 fn test_certificate_from_pem_wrong_type() {
957 let pem = "-----BEGIN PRIVATE KEY-----\nYWJjZA==\n-----END PRIVATE KEY-----";
958 let result = DerCertificate::from_pem(pem);
959 assert!(result.is_err());
960 assert!(result
961 .unwrap_err()
962 .to_string()
963 .contains("expected CERTIFICATE"));
964 }
965
966 #[test]
967 fn test_certificate_to_pem() {
968 let cert = DerCertificate::from_bytes(b"abcd");
969 let pem = cert.to_pem();
970 assert!(pem.contains("-----BEGIN CERTIFICATE-----"));
971 assert!(pem.contains("-----END CERTIFICATE-----"));
972
973 let cert2 = DerCertificate::from_pem(&pem).unwrap();
975 assert_eq!(cert, cert2);
976 }
977
978 #[test]
979 fn test_public_key_from_pem() {
980 let pem = "-----BEGIN PUBLIC KEY-----\nYWJjZA==\n-----END PUBLIC KEY-----";
981 let key = DerPublicKey::from_pem(pem).unwrap();
982 assert_eq!(key.as_bytes(), b"abcd");
983 }
984
985 #[test]
986 fn test_public_key_from_pem_wrong_type() {
987 let pem = "-----BEGIN PRIVATE KEY-----\nYWJjZA==\n-----END PRIVATE KEY-----";
988 let result = DerPublicKey::from_pem(pem);
989 assert!(result.is_err());
990 assert!(result
991 .unwrap_err()
992 .to_string()
993 .contains("expected PUBLIC KEY"));
994 }
995
996 #[test]
997 fn test_public_key_to_pem() {
998 let key = DerPublicKey::from_bytes(b"abcd");
999 let pem = key.to_pem();
1000 assert!(pem.contains("-----BEGIN PUBLIC KEY-----"));
1001 assert!(pem.contains("-----END PUBLIC KEY-----"));
1002
1003 let key2 = DerPublicKey::from_pem(&pem).unwrap();
1005 assert_eq!(key, key2);
1006 }
1007}