matrix_sdk_crypto/types/signatures/
signature.rs1use as_variant::as_variant;
17use ruma::DeviceKeyAlgorithm;
18use vodozemac::Ed25519Signature;
19
20use crate::types::InvalidSignature;
21#[cfg(feature = "experimental-x509-identity-verification")]
22use crate::types::{X509_SIGNATURE_ALGORITHM, X509Signature};
23
24#[derive(Clone, Debug, PartialEq, Eq)]
35pub enum Signature {
36 Ed25519(Ed25519Signature),
38 #[cfg(feature = "experimental-x509-identity-verification")]
40 X509(X509Signature),
41 Other(String),
44}
45
46impl Signature {
47 pub fn ed25519(&self) -> Option<Ed25519Signature> {
49 as_variant!(self, Self::Ed25519).copied()
50 }
51
52 pub fn from_base64(algorithm: DeviceKeyAlgorithm, s: String) -> Result<Self, InvalidSignature> {
55 match algorithm {
56 DeviceKeyAlgorithm::Ed25519 => Ed25519Signature::from_base64(&s)
57 .map(|s| s.into())
58 .map_err(|_| InvalidSignature { source: s }),
59
60 #[cfg(feature = "experimental-x509-identity-verification")]
61 custom if custom.as_str() == X509_SIGNATURE_ALGORITHM => {
62 X509Signature::from_cms_pem(&s)
63 .map(Into::into)
64 .map_err(|_| InvalidSignature { source: s })
65 }
66
67 _ => Ok(Signature::Other(s)),
68 }
69 }
70
71 pub fn to_base64(&self) -> String {
73 match self {
74 Signature::Ed25519(s) => s.to_base64(),
75 #[cfg(feature = "experimental-x509-identity-verification")]
76 Signature::X509(s) => s.to_cms_pem(),
77 Signature::Other(s) => s.to_owned(),
78 }
79 }
80}
81
82impl From<Ed25519Signature> for Signature {
83 fn from(signature: Ed25519Signature) -> Self {
84 Self::Ed25519(signature)
85 }
86}
87
88#[cfg(feature = "experimental-x509-identity-verification")]
89impl From<X509Signature> for Signature {
90 fn from(signature: X509Signature) -> Self {
91 Self::X509(signature)
92 }
93}
94
95#[cfg(test)]
96mod test {
97 use super::*;
98
99 #[test]
100 fn roundtrip_ed25519_signature() {
101 const BASE64_SIG: &str = "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ";
102
103 let parsed = Signature::from_base64(DeviceKeyAlgorithm::Ed25519, BASE64_SIG.to_owned())
104 .expect("Failed to parse");
105
106 let ed25519 = parsed.ed25519().expect("Not parsed as Ed25519");
107 assert_eq!(ed25519.to_base64(), BASE64_SIG);
108
109 let encoded = parsed.to_base64();
110 assert_eq!(encoded, BASE64_SIG)
111 }
112
113 #[test]
114 fn parse_invalid_ed25519_signature() {
115 const BASE64_SIG: &str = "XXXX";
116
117 let parsed = Signature::from_base64(DeviceKeyAlgorithm::Ed25519, BASE64_SIG.to_owned())
118 .expect_err("Expected an invalid signature");
119 assert_eq!(parsed.source, BASE64_SIG);
120 }
121
122 #[test]
123 fn roundtrip_other_signature() {
124 const TEXT: &str = "abcd";
125
126 let parsed = Signature::from_base64(DeviceKeyAlgorithm::from("foo"), TEXT.to_owned())
127 .expect("Failed to parse");
128
129 let other = as_variant!(&parsed, Signature::Other).expect("Not parsed as Other");
130 assert_eq!(other, TEXT);
131
132 let encoded = parsed.to_base64();
133 assert_eq!(encoded, TEXT)
134 }
135}