bitwarden_crypto/keys/
signed_public_key.rs1use std::{borrow::Cow, str::FromStr};
6
7use bitwarden_encoding::{B64, FromStrVisitor};
8use serde::{Deserialize, Serialize};
9use serde_bytes::ByteBuf;
10use serde_repr::{Deserialize_repr, Serialize_repr};
11
12use super::PublicKey;
13use crate::{
14 CoseSign1Bytes, CryptoError, PublicKeyEncryptionAlgorithm, RawPublicKey, SignedObject,
15 SigningKey, SigningNamespace, SpkiPublicKeyBytes, VerifyingKey, cose::CoseSerializable,
16 error::EncodingError,
17};
18
19#[cfg(feature = "wasm")]
20#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
21const TS_CUSTOM_TYPES: &'static str = r#"
22export type SignedPublicKey = Tagged<string, "SignedPublicKey">;
23"#;
24
25#[derive(Serialize_repr, Deserialize_repr)]
29#[repr(u8)]
30enum PublicKeyFormat {
31 Spki = 0,
32}
33
34#[derive(Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub struct SignedPublicKeyMessage {
39 algorithm: PublicKeyEncryptionAlgorithm,
41 content_format: PublicKeyFormat,
43 public_key: ByteBuf,
50}
51
52impl SignedPublicKeyMessage {
53 pub fn from_public_key(public_key: &PublicKey) -> Result<Self, CryptoError> {
56 match public_key.inner() {
57 RawPublicKey::RsaOaepSha1(_) => Ok(SignedPublicKeyMessage {
58 algorithm: PublicKeyEncryptionAlgorithm::RsaOaepSha1,
59 content_format: PublicKeyFormat::Spki,
60 public_key: ByteBuf::from(public_key.to_der()?.as_ref()),
61 }),
62 }
63 }
64
65 pub fn sign(&self, signing_key: &SigningKey) -> Result<SignedPublicKey, CryptoError> {
68 Ok(SignedPublicKey(
69 signing_key.sign(self, &SigningNamespace::SignedPublicKey)?,
70 ))
71 }
72}
73
74#[derive(Clone, PartialEq)]
78pub struct SignedPublicKey(pub(crate) SignedObject);
79
80impl std::fmt::Debug for SignedPublicKey {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 let mut debug_struct = f.debug_struct("SignedPublicKey");
83
84 if let Ok(key_id) = self.0.signed_by_id() {
85 debug_struct.field("signed_by", &key_id);
86 }
87
88 if let Some(msg) = self
89 .0
90 .dangerous_unverified_decode_do_not_use_except_for_debug_logs::<SignedPublicKeyMessage>(
91 )
92 {
93 debug_struct.field("algorithm", &msg.algorithm);
94 debug_struct.field("public_key", &hex::encode(&msg.public_key));
95 }
96
97 debug_struct.finish()
98 }
99}
100
101impl From<SignedPublicKey> for CoseSign1Bytes {
102 fn from(val: SignedPublicKey) -> Self {
103 val.0.to_cose()
104 }
105}
106
107impl TryFrom<CoseSign1Bytes> for SignedPublicKey {
108 type Error = EncodingError;
109 fn try_from(bytes: CoseSign1Bytes) -> Result<Self, EncodingError> {
110 Ok(SignedPublicKey(SignedObject::from_cose(&bytes)?))
111 }
112}
113
114impl From<SignedPublicKey> for String {
115 fn from(val: SignedPublicKey) -> Self {
116 let bytes: CoseSign1Bytes = val.into();
117 B64::from(bytes.as_ref()).to_string()
118 }
119}
120
121impl SignedPublicKey {
122 pub fn verify_and_unwrap(self, verifying_key: &VerifyingKey) -> Result<PublicKey, CryptoError> {
125 let public_key_message: SignedPublicKeyMessage = self
126 .0
127 .verify_and_unwrap(verifying_key, &SigningNamespace::SignedPublicKey)?;
128 match (
129 public_key_message.algorithm,
130 public_key_message.content_format,
131 ) {
132 (PublicKeyEncryptionAlgorithm::RsaOaepSha1, PublicKeyFormat::Spki) => {
133 Ok(PublicKey::from_der(&SpkiPublicKeyBytes::from(
134 public_key_message.public_key.into_vec(),
135 ))
136 .map_err(|_| EncodingError::InvalidValue("public key"))?)
137 }
138 }
139 }
140}
141
142impl FromStr for SignedPublicKey {
143 type Err = EncodingError;
144
145 fn from_str(s: &str) -> Result<Self, Self::Err> {
146 let bytes = B64::try_from(s).map_err(|_| EncodingError::InvalidCborSerialization)?;
147 Self::try_from(CoseSign1Bytes::from(&bytes))
148 }
149}
150
151impl<'de> Deserialize<'de> for SignedPublicKey {
152 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153 where
154 D: serde::Deserializer<'de>,
155 {
156 deserializer.deserialize_str(FromStrVisitor::new())
157 }
158}
159
160impl serde::Serialize for SignedPublicKey {
161 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
162 where
163 S: serde::Serializer,
164 {
165 let b64_serialized_signed_public_key: String = self.clone().into();
166 serializer.serialize_str(&b64_serialized_signed_public_key)
167 }
168}
169
170impl schemars::JsonSchema for SignedPublicKey {
171 fn schema_name() -> Cow<'static, str> {
172 "SignedPublicKey".into()
173 }
174
175 fn json_schema(generator: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
176 generator.subschema_for::<String>()
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::{PrivateKey, PublicKeyEncryptionAlgorithm, SignatureAlgorithm};
184
185 #[test]
186 #[ignore = "Manual test to verify debug format"]
187 fn test_debug() {
188 let public_key =
189 PrivateKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1).to_public_key();
190 let signing_key = SigningKey::make(SignatureAlgorithm::Ed25519);
191 let message = SignedPublicKeyMessage::from_public_key(&public_key).unwrap();
192 let signed_public_key = message.sign(&signing_key).unwrap();
193 println!("{:?}", signed_public_key);
194 }
195
196 #[test]
197 fn test_signed_asymmetric_public_key() {
198 let public_key =
199 PrivateKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1).to_public_key();
200 let signing_key = SigningKey::make(SignatureAlgorithm::Ed25519);
201 let message = SignedPublicKeyMessage::from_public_key(&public_key).unwrap();
202 let signed_public_key = message.sign(&signing_key).unwrap();
203 let verifying_key = signing_key.to_verifying_key();
204 let verified_public_key = signed_public_key.verify_and_unwrap(&verifying_key).unwrap();
205 assert_eq!(
206 public_key.to_der().unwrap(),
207 verified_public_key.to_der().unwrap()
208 );
209 }
210}