bitwarden_crypto/keys/
signed_public_key.rs1use std::str::FromStr;
6
7use base64::{engine::general_purpose::STANDARD, Engine};
8use serde::{Deserialize, Serialize};
9use serde_bytes::ByteBuf;
10use serde_repr::{Deserialize_repr, Serialize_repr};
11
12use super::AsymmetricPublicCryptoKey;
13use crate::{
14 cose::CoseSerializable, error::EncodingError, util::FromStrVisitor, CryptoError,
15 PublicKeyEncryptionAlgorithm, RawPublicKey, SignedObject, SigningKey, SigningNamespace,
16 VerifyingKey,
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 = string;
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: &AsymmetricPublicCryptoKey) -> 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()?),
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, Debug)]
78pub struct SignedPublicKey(pub(crate) SignedObject);
79
80impl From<SignedPublicKey> for Vec<u8> {
81 fn from(val: SignedPublicKey) -> Self {
82 val.0.to_cose()
83 }
84}
85
86impl TryFrom<Vec<u8>> for SignedPublicKey {
87 type Error = EncodingError;
88 fn try_from(bytes: Vec<u8>) -> Result<Self, EncodingError> {
89 Ok(SignedPublicKey(SignedObject::from_cose(&bytes)?))
90 }
91}
92
93impl From<SignedPublicKey> for String {
94 fn from(val: SignedPublicKey) -> Self {
95 let bytes: Vec<u8> = val.into();
96 STANDARD.encode(&bytes)
97 }
98}
99
100impl SignedPublicKey {
101 pub fn verify_and_unwrap(
104 self,
105 verifying_key: &VerifyingKey,
106 ) -> Result<AsymmetricPublicCryptoKey, CryptoError> {
107 let public_key_message: SignedPublicKeyMessage = self
108 .0
109 .verify_and_unwrap(verifying_key, &SigningNamespace::SignedPublicKey)?;
110 match (
111 public_key_message.algorithm,
112 public_key_message.content_format,
113 ) {
114 (PublicKeyEncryptionAlgorithm::RsaOaepSha1, PublicKeyFormat::Spki) => Ok(
115 AsymmetricPublicCryptoKey::from_der(&public_key_message.public_key.into_vec())
116 .map_err(|_| EncodingError::InvalidValue("public key"))?,
117 ),
118 }
119 }
120}
121
122impl FromStr for SignedPublicKey {
123 type Err = EncodingError;
124
125 fn from_str(s: &str) -> Result<Self, Self::Err> {
126 let bytes = STANDARD
127 .decode(s)
128 .map_err(|_| EncodingError::InvalidCborSerialization)?;
129 Self::try_from(bytes)
130 }
131}
132
133impl<'de> Deserialize<'de> for SignedPublicKey {
134 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
135 where
136 D: serde::Deserializer<'de>,
137 {
138 deserializer.deserialize_str(FromStrVisitor::new())
139 }
140}
141
142impl serde::Serialize for SignedPublicKey {
143 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
144 where
145 S: serde::Serializer,
146 {
147 let b64_serialized_signed_public_key: String = self.clone().into();
148 serializer.serialize_str(&b64_serialized_signed_public_key)
149 }
150}
151
152impl schemars::JsonSchema for SignedPublicKey {
153 fn schema_name() -> String {
154 "SignedPublicKey".to_string()
155 }
156
157 fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
158 generator.subschema_for::<String>()
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use crate::{AsymmetricCryptoKey, PublicKeyEncryptionAlgorithm, SignatureAlgorithm};
166
167 #[test]
168 fn test_signed_asymmetric_public_key() {
169 let public_key =
170 AsymmetricCryptoKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1).to_public_key();
171 let signing_key = SigningKey::make(SignatureAlgorithm::Ed25519);
172 let message = SignedPublicKeyMessage::from_public_key(&public_key).unwrap();
173 let signed_public_key = message.sign(&signing_key).unwrap();
174 let verifying_key = signing_key.to_verifying_key();
175 let verified_public_key = signed_public_key.verify_and_unwrap(&verifying_key).unwrap();
176 assert_eq!(
177 public_key.to_der().unwrap(),
178 verified_public_key.to_der().unwrap()
179 );
180 }
181}