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, CoseSign1Bytes,
15 CryptoError, PublicKeyEncryptionAlgorithm, RawPublicKey, SignedObject, SigningKey,
16 SigningNamespace, SpkiPublicKeyBytes, 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()?.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, Debug)]
78pub struct SignedPublicKey(pub(crate) SignedObject);
79
80impl From<SignedPublicKey> for CoseSign1Bytes {
81 fn from(val: SignedPublicKey) -> Self {
82 val.0.to_cose()
83 }
84}
85
86impl TryFrom<CoseSign1Bytes> for SignedPublicKey {
87 type Error = EncodingError;
88 fn try_from(bytes: CoseSign1Bytes) -> 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: CoseSign1Bytes = 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(&SpkiPublicKeyBytes::from(
116 public_key_message.public_key.into_vec(),
117 ))
118 .map_err(|_| EncodingError::InvalidValue("public key"))?,
119 ),
120 }
121 }
122}
123
124impl FromStr for SignedPublicKey {
125 type Err = EncodingError;
126
127 fn from_str(s: &str) -> Result<Self, Self::Err> {
128 let bytes = STANDARD
129 .decode(s)
130 .map_err(|_| EncodingError::InvalidCborSerialization)?;
131 Self::try_from(CoseSign1Bytes::from(bytes))
132 }
133}
134
135impl<'de> Deserialize<'de> for SignedPublicKey {
136 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
137 where
138 D: serde::Deserializer<'de>,
139 {
140 deserializer.deserialize_str(FromStrVisitor::new())
141 }
142}
143
144impl serde::Serialize for SignedPublicKey {
145 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
146 where
147 S: serde::Serializer,
148 {
149 let b64_serialized_signed_public_key: String = self.clone().into();
150 serializer.serialize_str(&b64_serialized_signed_public_key)
151 }
152}
153
154impl schemars::JsonSchema for SignedPublicKey {
155 fn schema_name() -> String {
156 "SignedPublicKey".to_string()
157 }
158
159 fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
160 generator.subschema_for::<String>()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::{AsymmetricCryptoKey, PublicKeyEncryptionAlgorithm, SignatureAlgorithm};
168
169 #[test]
170 fn test_signed_asymmetric_public_key() {
171 let public_key =
172 AsymmetricCryptoKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1).to_public_key();
173 let signing_key = SigningKey::make(SignatureAlgorithm::Ed25519);
174 let message = SignedPublicKeyMessage::from_public_key(&public_key).unwrap();
175 let signed_public_key = message.sign(&signing_key).unwrap();
176 let verifying_key = signing_key.to_verifying_key();
177 let verified_public_key = signed_public_key.verify_and_unwrap(&verifying_key).unwrap();
178 assert_eq!(
179 public_key.to_der().unwrap(),
180 verified_public_key.to_der().unwrap()
181 );
182 }
183}