warg_crypto/signing/
public_key.rs1use super::{Signature, SignatureAlgorithm, SignatureAlgorithmParseError};
2use base64::{engine::general_purpose::STANDARD, Engine};
3use core::fmt;
4use serde::{Deserialize, Serialize};
5use signature::{Error as SignatureError, Verifier};
6use std::str::FromStr;
7use thiserror::Error;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
10pub enum PublicKey {
11 EcdsaP256(p256::ecdsa::VerifyingKey),
12}
13
14impl PublicKey {
15 pub fn signature_algorithm(&self) -> SignatureAlgorithm {
17 match self {
18 PublicKey::EcdsaP256(_) => SignatureAlgorithm::EcdsaP256,
19 }
20 }
21
22 pub fn bytes(&self) -> Vec<u8> {
24 match self {
25 PublicKey::EcdsaP256(key) => key.to_encoded_point(true).as_bytes().to_vec(),
26 }
27 }
28
29 pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), SignatureError> {
31 match (self, signature) {
32 (PublicKey::EcdsaP256(key), Signature::P256(signature)) => key.verify(msg, signature),
33 }
34 }
35
36 pub fn fingerprint(&self) -> KeyID {
38 let key_hash = self
39 .signature_algorithm()
40 .digest_algorithm()
41 .digest(format!("{}", self).as_bytes());
42
43 KeyID(format!("{}", key_hash))
44 }
45}
46
47impl fmt::Display for PublicKey {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(
50 f,
51 "{}:{}",
52 self.signature_algorithm(),
53 STANDARD.encode(self.bytes())
54 )
55 }
56}
57
58impl FromStr for PublicKey {
59 type Err = PublicKeyParseError;
60
61 fn from_str(s: &str) -> Result<Self, Self::Err> {
62 let parts: Vec<&str> = s.split(|c| c == ':').collect();
63 if parts.len() != 2 {
64 return Err(PublicKeyParseError::IncorrectStructure(parts.len()));
65 }
66 let algo = parts[0].parse::<SignatureAlgorithm>()?;
67 let bytes = STANDARD.decode(parts[1])?;
68
69 let key = match algo {
70 SignatureAlgorithm::EcdsaP256 => {
71 PublicKey::EcdsaP256(p256::ecdsa::VerifyingKey::from_sec1_bytes(&bytes)?)
72 }
73 };
74
75 Ok(key)
76 }
77}
78
79impl Serialize for PublicKey {
80 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81 where
82 S: serde::Serializer,
83 {
84 serializer.serialize_str(&format!("{}", self))
85 }
86}
87
88impl<'de> Deserialize<'de> for PublicKey {
89 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
90 where
91 D: serde::Deserializer<'de>,
92 {
93 Self::from_str(&String::deserialize(deserializer)?).map_err(serde::de::Error::custom)
94 }
95}
96
97#[derive(Error, Debug)]
98pub enum PublicKeyParseError {
99 #[error("expected 2 parts, found {0}")]
100 IncorrectStructure(usize),
101
102 #[error("unable to parse signature algorithm")]
103 SignatureAlgorithmParseError(#[from] SignatureAlgorithmParseError),
104
105 #[error("base64 decode failed")]
106 Base64DecodeError(#[from] base64::DecodeError),
107
108 #[error("public key could not be constructed from bytes")]
109 SignatureError(#[from] SignatureError),
110}
111
112impl From<p256::ecdsa::VerifyingKey> for PublicKey {
113 fn from(key: p256::ecdsa::VerifyingKey) -> Self {
114 PublicKey::EcdsaP256(key)
115 }
116}
117
118#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
119#[serde(transparent)]
120pub struct KeyID(String);
121
122impl fmt::Display for KeyID {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "{}", self.0)
125 }
126}
127
128impl From<String> for KeyID {
129 fn from(s: String) -> Self {
130 KeyID(s)
131 }
132}
133
134impl From<KeyID> for String {
135 fn from(id: KeyID) -> Self {
136 id.0
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use pretty_assertions::assert_eq;
144
145 #[test]
146 fn test_roundtrip_alice() {
147 let key_str = "ecdsa-p256:A1OfZz5Y9Ny7VKPVwroCTQPAr9tmlI4U/UTYHZHA87AF";
148 let pub_key: PublicKey = key_str.parse().unwrap();
149 assert_eq!(key_str, &format!("{pub_key}"));
150 }
151
152 #[test]
153 fn test_roundtrip_bob() {
154 let key_str = "ecdsa-p256:A5qc6uBi070EBb4GihGzpx6Cm5+oZnv4dWpBhhuZVagu";
155 let pub_key: PublicKey = key_str.parse().unwrap();
156 assert_eq!(key_str, &format!("{pub_key}"));
157 }
158}