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, 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 B64::from(bytes.as_ref()).to_string()
97 }
98}
99
100impl SignedPublicKey {
101 pub fn verify_and_unwrap(self, verifying_key: &VerifyingKey) -> Result<PublicKey, CryptoError> {
104 let public_key_message: SignedPublicKeyMessage = self
105 .0
106 .verify_and_unwrap(verifying_key, &SigningNamespace::SignedPublicKey)?;
107 match (
108 public_key_message.algorithm,
109 public_key_message.content_format,
110 ) {
111 (PublicKeyEncryptionAlgorithm::RsaOaepSha1, PublicKeyFormat::Spki) => {
112 Ok(PublicKey::from_der(&SpkiPublicKeyBytes::from(
113 public_key_message.public_key.into_vec(),
114 ))
115 .map_err(|_| EncodingError::InvalidValue("public key"))?)
116 }
117 }
118 }
119}
120
121impl FromStr for SignedPublicKey {
122 type Err = EncodingError;
123
124 fn from_str(s: &str) -> Result<Self, Self::Err> {
125 let bytes = B64::try_from(s).map_err(|_| EncodingError::InvalidCborSerialization)?;
126 Self::try_from(CoseSign1Bytes::from(&bytes))
127 }
128}
129
130impl<'de> Deserialize<'de> for SignedPublicKey {
131 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
132 where
133 D: serde::Deserializer<'de>,
134 {
135 deserializer.deserialize_str(FromStrVisitor::new())
136 }
137}
138
139impl serde::Serialize for SignedPublicKey {
140 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
141 where
142 S: serde::Serializer,
143 {
144 let b64_serialized_signed_public_key: String = self.clone().into();
145 serializer.serialize_str(&b64_serialized_signed_public_key)
146 }
147}
148
149impl schemars::JsonSchema for SignedPublicKey {
150 fn schema_name() -> Cow<'static, str> {
151 "SignedPublicKey".into()
152 }
153
154 fn json_schema(generator: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
155 generator.subschema_for::<String>()
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::{PrivateKey, PublicKeyEncryptionAlgorithm, SignatureAlgorithm};
163
164 #[test]
165 fn test_signed_asymmetric_public_key() {
166 let public_key =
167 PrivateKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1).to_public_key();
168 let signing_key = SigningKey::make(SignatureAlgorithm::Ed25519);
169 let message = SignedPublicKeyMessage::from_public_key(&public_key).unwrap();
170 let signed_public_key = message.sign(&signing_key).unwrap();
171 let verifying_key = signing_key.to_verifying_key();
172 let verified_public_key = signed_public_key.verify_and_unwrap(&verifying_key).unwrap();
173 assert_eq!(
174 public_key.to_der().unwrap(),
175 verified_public_key.to_der().unwrap()
176 );
177 }
178}