xref: /aosp_15_r20/tools/security/remote_provisioning/hwtrust/src/publickey.rs (revision d9ecfb0f4d734c9ce41cde8ac4d585b094fd4222)
1*d9ecfb0fSAndroid Build Coastguard Worker //! This module describes a public key that is restricted to one of the supported algorithms.
2*d9ecfb0fSAndroid Build Coastguard Worker 
3*d9ecfb0fSAndroid Build Coastguard Worker use anyhow::{ensure, Context, Result};
4*d9ecfb0fSAndroid Build Coastguard Worker use openssl::hash::MessageDigest;
5*d9ecfb0fSAndroid Build Coastguard Worker use openssl::nid::Nid;
6*d9ecfb0fSAndroid Build Coastguard Worker use openssl::pkey::{HasParams, Id, PKey, PKeyRef, Public};
7*d9ecfb0fSAndroid Build Coastguard Worker use openssl::sign::Verifier;
8*d9ecfb0fSAndroid Build Coastguard Worker use std::error::Error;
9*d9ecfb0fSAndroid Build Coastguard Worker use std::fmt;
10*d9ecfb0fSAndroid Build Coastguard Worker 
11*d9ecfb0fSAndroid Build Coastguard Worker /// The kinds of digital signature keys that are supported.
12*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq)]
13*d9ecfb0fSAndroid Build Coastguard Worker pub(crate) enum SignatureKind {
14*d9ecfb0fSAndroid Build Coastguard Worker     Ed25519,
15*d9ecfb0fSAndroid Build Coastguard Worker     Ec(EcKind),
16*d9ecfb0fSAndroid Build Coastguard Worker }
17*d9ecfb0fSAndroid Build Coastguard Worker 
18*d9ecfb0fSAndroid Build Coastguard Worker /// The kinds of key agreement keys that are supported.
19*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq)]
20*d9ecfb0fSAndroid Build Coastguard Worker pub(crate) enum KeyAgreementKind {
21*d9ecfb0fSAndroid Build Coastguard Worker     X25519,
22*d9ecfb0fSAndroid Build Coastguard Worker     Ec(EcKind),
23*d9ecfb0fSAndroid Build Coastguard Worker }
24*d9ecfb0fSAndroid Build Coastguard Worker 
25*d9ecfb0fSAndroid Build Coastguard Worker /// Enumeration of the kinds of elliptic curve keys that are supported.
26*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27*d9ecfb0fSAndroid Build Coastguard Worker pub(crate) enum EcKind {
28*d9ecfb0fSAndroid Build Coastguard Worker     P256,
29*d9ecfb0fSAndroid Build Coastguard Worker     P384,
30*d9ecfb0fSAndroid Build Coastguard Worker }
31*d9ecfb0fSAndroid Build Coastguard Worker 
32*d9ecfb0fSAndroid Build Coastguard Worker // Wraps PKey<Public> so we can implement some traits around it, allowing for derived traits on
33*d9ecfb0fSAndroid Build Coastguard Worker // types that include a PKey<Public>.
34*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Clone)]
35*d9ecfb0fSAndroid Build Coastguard Worker struct PKeyPublicWrapper(PKey<Public>);
36*d9ecfb0fSAndroid Build Coastguard Worker 
37*d9ecfb0fSAndroid Build Coastguard Worker /// Public key used for signature validation.
38*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)]
39*d9ecfb0fSAndroid Build Coastguard Worker pub struct PublicKey {
40*d9ecfb0fSAndroid Build Coastguard Worker     kind: SignatureKind,
41*d9ecfb0fSAndroid Build Coastguard Worker     pkey: PKeyPublicWrapper,
42*d9ecfb0fSAndroid Build Coastguard Worker }
43*d9ecfb0fSAndroid Build Coastguard Worker 
44*d9ecfb0fSAndroid Build Coastguard Worker /// Public key used for key agreement.
45*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)]
46*d9ecfb0fSAndroid Build Coastguard Worker pub struct KeyAgreementPublicKey {
47*d9ecfb0fSAndroid Build Coastguard Worker     kind: KeyAgreementKind,
48*d9ecfb0fSAndroid Build Coastguard Worker     pkey: PKeyPublicWrapper,
49*d9ecfb0fSAndroid Build Coastguard Worker }
50*d9ecfb0fSAndroid Build Coastguard Worker 
51*d9ecfb0fSAndroid Build Coastguard Worker impl PublicKey {
kind(&self) -> SignatureKind52*d9ecfb0fSAndroid Build Coastguard Worker     pub(crate) fn kind(&self) -> SignatureKind {
53*d9ecfb0fSAndroid Build Coastguard Worker         self.kind
54*d9ecfb0fSAndroid Build Coastguard Worker     }
55*d9ecfb0fSAndroid Build Coastguard Worker 
pkey(&self) -> &PKeyRef<Public>56*d9ecfb0fSAndroid Build Coastguard Worker     pub(crate) fn pkey(&self) -> &PKeyRef<Public> {
57*d9ecfb0fSAndroid Build Coastguard Worker         &self.pkey.0
58*d9ecfb0fSAndroid Build Coastguard Worker     }
59*d9ecfb0fSAndroid Build Coastguard Worker 
60*d9ecfb0fSAndroid Build Coastguard Worker     /// Verify that the signature obtained from signing the given message
61*d9ecfb0fSAndroid Build Coastguard Worker     /// with the PublicKey matches the signature provided.
verify(&self, signature: &[u8], message: &[u8]) -> Result<()>62*d9ecfb0fSAndroid Build Coastguard Worker     pub fn verify(&self, signature: &[u8], message: &[u8]) -> Result<()> {
63*d9ecfb0fSAndroid Build Coastguard Worker         let mut verifier = match self.kind {
64*d9ecfb0fSAndroid Build Coastguard Worker             SignatureKind::Ed25519 => Verifier::new_without_digest(&self.pkey.0),
65*d9ecfb0fSAndroid Build Coastguard Worker             SignatureKind::Ec(ec) => Verifier::new(digest_for_ec(ec), &self.pkey.0),
66*d9ecfb0fSAndroid Build Coastguard Worker         }
67*d9ecfb0fSAndroid Build Coastguard Worker         .with_context(|| format!("Failed to create verifier {:?}", self.kind))?;
68*d9ecfb0fSAndroid Build Coastguard Worker         let verified =
69*d9ecfb0fSAndroid Build Coastguard Worker             verifier.verify_oneshot(signature, message).context("Failed to verify signature")?;
70*d9ecfb0fSAndroid Build Coastguard Worker         ensure!(verified, "Signature verification failed.");
71*d9ecfb0fSAndroid Build Coastguard Worker         Ok(())
72*d9ecfb0fSAndroid Build Coastguard Worker     }
73*d9ecfb0fSAndroid Build Coastguard Worker 
74*d9ecfb0fSAndroid Build Coastguard Worker     /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
to_pem(&self) -> String75*d9ecfb0fSAndroid Build Coastguard Worker     pub fn to_pem(&self) -> String {
76*d9ecfb0fSAndroid Build Coastguard Worker         self.pkey.to_pem()
77*d9ecfb0fSAndroid Build Coastguard Worker     }
78*d9ecfb0fSAndroid Build Coastguard Worker 
pkey_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<SignatureKind>79*d9ecfb0fSAndroid Build Coastguard Worker     fn pkey_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<SignatureKind> {
80*d9ecfb0fSAndroid Build Coastguard Worker         match pkey.id() {
81*d9ecfb0fSAndroid Build Coastguard Worker             Id::ED25519 => Some(SignatureKind::Ed25519),
82*d9ecfb0fSAndroid Build Coastguard Worker             Id::EC => pkey_ec_kind(pkey).map(SignatureKind::Ec),
83*d9ecfb0fSAndroid Build Coastguard Worker             _ => None,
84*d9ecfb0fSAndroid Build Coastguard Worker         }
85*d9ecfb0fSAndroid Build Coastguard Worker     }
86*d9ecfb0fSAndroid Build Coastguard Worker }
87*d9ecfb0fSAndroid Build Coastguard Worker 
88*d9ecfb0fSAndroid Build Coastguard Worker impl KeyAgreementPublicKey {
pkey(&self) -> &PKeyRef<Public>89*d9ecfb0fSAndroid Build Coastguard Worker     pub(crate) fn pkey(&self) -> &PKeyRef<Public> {
90*d9ecfb0fSAndroid Build Coastguard Worker         &self.pkey.0
91*d9ecfb0fSAndroid Build Coastguard Worker     }
92*d9ecfb0fSAndroid Build Coastguard Worker 
93*d9ecfb0fSAndroid Build Coastguard Worker     /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
to_pem(&self) -> String94*d9ecfb0fSAndroid Build Coastguard Worker     pub fn to_pem(&self) -> String {
95*d9ecfb0fSAndroid Build Coastguard Worker         self.pkey.to_pem()
96*d9ecfb0fSAndroid Build Coastguard Worker     }
97*d9ecfb0fSAndroid Build Coastguard Worker 
pkey_kind(pkey: &PKeyRef<Public>) -> Option<KeyAgreementKind>98*d9ecfb0fSAndroid Build Coastguard Worker     fn pkey_kind(pkey: &PKeyRef<Public>) -> Option<KeyAgreementKind> {
99*d9ecfb0fSAndroid Build Coastguard Worker         match pkey.id() {
100*d9ecfb0fSAndroid Build Coastguard Worker             Id::X25519 => Some(KeyAgreementKind::X25519),
101*d9ecfb0fSAndroid Build Coastguard Worker             Id::EC => pkey_ec_kind(pkey).map(KeyAgreementKind::Ec),
102*d9ecfb0fSAndroid Build Coastguard Worker             _ => None,
103*d9ecfb0fSAndroid Build Coastguard Worker         }
104*d9ecfb0fSAndroid Build Coastguard Worker     }
105*d9ecfb0fSAndroid Build Coastguard Worker }
106*d9ecfb0fSAndroid Build Coastguard Worker 
107*d9ecfb0fSAndroid Build Coastguard Worker impl Eq for PKeyPublicWrapper {}
108*d9ecfb0fSAndroid Build Coastguard Worker 
109*d9ecfb0fSAndroid Build Coastguard Worker impl PartialEq for PKeyPublicWrapper {
eq(&self, rhs: &PKeyPublicWrapper) -> bool110*d9ecfb0fSAndroid Build Coastguard Worker     fn eq(&self, rhs: &PKeyPublicWrapper) -> bool {
111*d9ecfb0fSAndroid Build Coastguard Worker         self.0.public_eq(&rhs.0)
112*d9ecfb0fSAndroid Build Coastguard Worker     }
113*d9ecfb0fSAndroid Build Coastguard Worker }
114*d9ecfb0fSAndroid Build Coastguard Worker 
115*d9ecfb0fSAndroid Build Coastguard Worker impl PKeyPublicWrapper {
to_pem(&self) -> String116*d9ecfb0fSAndroid Build Coastguard Worker     fn to_pem(&self) -> String {
117*d9ecfb0fSAndroid Build Coastguard Worker         String::from_utf8(self.0.public_key_to_pem().unwrap()).unwrap()
118*d9ecfb0fSAndroid Build Coastguard Worker     }
119*d9ecfb0fSAndroid Build Coastguard Worker }
120*d9ecfb0fSAndroid Build Coastguard Worker 
121*d9ecfb0fSAndroid Build Coastguard Worker impl fmt::Debug for PKeyPublicWrapper {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result122*d9ecfb0fSAndroid Build Coastguard Worker     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
123*d9ecfb0fSAndroid Build Coastguard Worker         fmt.write_str(&self.to_pem())
124*d9ecfb0fSAndroid Build Coastguard Worker     }
125*d9ecfb0fSAndroid Build Coastguard Worker }
126*d9ecfb0fSAndroid Build Coastguard Worker 
127*d9ecfb0fSAndroid Build Coastguard Worker /// The error type returned when converting from [`PKey'] to [`PublicKey`] fails.
128*d9ecfb0fSAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)]
129*d9ecfb0fSAndroid Build Coastguard Worker pub struct TryFromPKeyError(());
130*d9ecfb0fSAndroid Build Coastguard Worker 
131*d9ecfb0fSAndroid Build Coastguard Worker impl fmt::Display for TryFromPKeyError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result132*d9ecfb0fSAndroid Build Coastguard Worker     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
133*d9ecfb0fSAndroid Build Coastguard Worker         write!(fmt, "unsupported public key conversion attempted")
134*d9ecfb0fSAndroid Build Coastguard Worker     }
135*d9ecfb0fSAndroid Build Coastguard Worker }
136*d9ecfb0fSAndroid Build Coastguard Worker 
137*d9ecfb0fSAndroid Build Coastguard Worker impl Error for TryFromPKeyError {}
138*d9ecfb0fSAndroid Build Coastguard Worker 
139*d9ecfb0fSAndroid Build Coastguard Worker impl TryFrom<PKey<Public>> for PublicKey {
140*d9ecfb0fSAndroid Build Coastguard Worker     type Error = TryFromPKeyError;
141*d9ecfb0fSAndroid Build Coastguard Worker 
try_from(pkey: PKey<Public>) -> Result<Self, Self::Error>142*d9ecfb0fSAndroid Build Coastguard Worker     fn try_from(pkey: PKey<Public>) -> Result<Self, Self::Error> {
143*d9ecfb0fSAndroid Build Coastguard Worker         let kind = PublicKey::pkey_kind(&pkey).ok_or(TryFromPKeyError(()))?;
144*d9ecfb0fSAndroid Build Coastguard Worker         Ok(Self { kind, pkey: PKeyPublicWrapper(pkey) })
145*d9ecfb0fSAndroid Build Coastguard Worker     }
146*d9ecfb0fSAndroid Build Coastguard Worker }
147*d9ecfb0fSAndroid Build Coastguard Worker 
148*d9ecfb0fSAndroid Build Coastguard Worker impl TryFrom<PKey<Public>> for KeyAgreementPublicKey {
149*d9ecfb0fSAndroid Build Coastguard Worker     type Error = TryFromPKeyError;
150*d9ecfb0fSAndroid Build Coastguard Worker 
try_from(pkey: PKey<Public>) -> Result<Self, Self::Error>151*d9ecfb0fSAndroid Build Coastguard Worker     fn try_from(pkey: PKey<Public>) -> Result<Self, Self::Error> {
152*d9ecfb0fSAndroid Build Coastguard Worker         let kind = KeyAgreementPublicKey::pkey_kind(&pkey).ok_or(TryFromPKeyError(()))?;
153*d9ecfb0fSAndroid Build Coastguard Worker         Ok(Self { kind, pkey: PKeyPublicWrapper(pkey) })
154*d9ecfb0fSAndroid Build Coastguard Worker     }
155*d9ecfb0fSAndroid Build Coastguard Worker }
156*d9ecfb0fSAndroid Build Coastguard Worker 
pkey_ec_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<EcKind>157*d9ecfb0fSAndroid Build Coastguard Worker fn pkey_ec_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<EcKind> {
158*d9ecfb0fSAndroid Build Coastguard Worker     match pkey.id() {
159*d9ecfb0fSAndroid Build Coastguard Worker         Id::EC => match pkey.ec_key().unwrap().group().curve_name() {
160*d9ecfb0fSAndroid Build Coastguard Worker             Some(Nid::X9_62_PRIME256V1) => Some(EcKind::P256),
161*d9ecfb0fSAndroid Build Coastguard Worker             Some(Nid::SECP384R1) => Some(EcKind::P384),
162*d9ecfb0fSAndroid Build Coastguard Worker             _ => None,
163*d9ecfb0fSAndroid Build Coastguard Worker         },
164*d9ecfb0fSAndroid Build Coastguard Worker         _ => None,
165*d9ecfb0fSAndroid Build Coastguard Worker     }
166*d9ecfb0fSAndroid Build Coastguard Worker }
167*d9ecfb0fSAndroid Build Coastguard Worker 
digest_for_ec(ec: EcKind) -> MessageDigest168*d9ecfb0fSAndroid Build Coastguard Worker fn digest_for_ec(ec: EcKind) -> MessageDigest {
169*d9ecfb0fSAndroid Build Coastguard Worker     match ec {
170*d9ecfb0fSAndroid Build Coastguard Worker         EcKind::P256 => MessageDigest::sha256(),
171*d9ecfb0fSAndroid Build Coastguard Worker         EcKind::P384 => MessageDigest::sha384(),
172*d9ecfb0fSAndroid Build Coastguard Worker     }
173*d9ecfb0fSAndroid Build Coastguard Worker }
174*d9ecfb0fSAndroid Build Coastguard Worker 
175*d9ecfb0fSAndroid Build Coastguard Worker #[cfg(test)]
176*d9ecfb0fSAndroid Build Coastguard Worker mod tests {
177*d9ecfb0fSAndroid Build Coastguard Worker     use super::*;
178*d9ecfb0fSAndroid Build Coastguard Worker 
179*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
from_ed25519_pkey()180*d9ecfb0fSAndroid Build Coastguard Worker     fn from_ed25519_pkey() {
181*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::ED25519_KEY_PEM[0]);
182*d9ecfb0fSAndroid Build Coastguard Worker         let key: PublicKey = pkey.clone().try_into().unwrap();
183*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.kind, SignatureKind::Ed25519);
184*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
185*d9ecfb0fSAndroid Build Coastguard Worker     }
186*d9ecfb0fSAndroid Build Coastguard Worker 
187*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
from_p256_pkey()188*d9ecfb0fSAndroid Build Coastguard Worker     fn from_p256_pkey() {
189*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::P256_KEY_PEM[0]);
190*d9ecfb0fSAndroid Build Coastguard Worker         let key: PublicKey = pkey.clone().try_into().unwrap();
191*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.kind, SignatureKind::Ec(EcKind::P256));
192*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
193*d9ecfb0fSAndroid Build Coastguard Worker     }
194*d9ecfb0fSAndroid Build Coastguard Worker 
195*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
from_p384_pkey()196*d9ecfb0fSAndroid Build Coastguard Worker     fn from_p384_pkey() {
197*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::P384_KEY_PEM[0]);
198*d9ecfb0fSAndroid Build Coastguard Worker         let key: PublicKey = pkey.clone().try_into().unwrap();
199*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.kind, SignatureKind::Ec(EcKind::P384));
200*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
201*d9ecfb0fSAndroid Build Coastguard Worker     }
202*d9ecfb0fSAndroid Build Coastguard Worker 
203*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
from_p521_pkey_not_supported()204*d9ecfb0fSAndroid Build Coastguard Worker     fn from_p521_pkey_not_supported() {
205*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::P521_KEY_PEM[0]);
206*d9ecfb0fSAndroid Build Coastguard Worker         assert!(PublicKey::try_from(pkey).is_err());
207*d9ecfb0fSAndroid Build Coastguard Worker     }
208*d9ecfb0fSAndroid Build Coastguard Worker 
209*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
from_rsa2048_pkey_not_supported()210*d9ecfb0fSAndroid Build Coastguard Worker     fn from_rsa2048_pkey_not_supported() {
211*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::RSA2048_KEY_PEM[0]);
212*d9ecfb0fSAndroid Build Coastguard Worker         assert!(PublicKey::try_from(pkey).is_err());
213*d9ecfb0fSAndroid Build Coastguard Worker     }
214*d9ecfb0fSAndroid Build Coastguard Worker 
215*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
from_x25519_pkey_not_supported()216*d9ecfb0fSAndroid Build Coastguard Worker     fn from_x25519_pkey_not_supported() {
217*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::X25519_KEY_PEM[0]);
218*d9ecfb0fSAndroid Build Coastguard Worker         assert!(PublicKey::try_from(pkey).is_err());
219*d9ecfb0fSAndroid Build Coastguard Worker     }
220*d9ecfb0fSAndroid Build Coastguard Worker 
221*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
key_agreement_key_from_x25519_pkey()222*d9ecfb0fSAndroid Build Coastguard Worker     fn key_agreement_key_from_x25519_pkey() {
223*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::X25519_KEY_PEM[0]);
224*d9ecfb0fSAndroid Build Coastguard Worker         let key: KeyAgreementPublicKey = pkey.clone().try_into().unwrap();
225*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.kind, KeyAgreementKind::X25519);
226*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
227*d9ecfb0fSAndroid Build Coastguard Worker     }
228*d9ecfb0fSAndroid Build Coastguard Worker 
229*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
key_agreement_key_from_p256_pkey()230*d9ecfb0fSAndroid Build Coastguard Worker     fn key_agreement_key_from_p256_pkey() {
231*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::P256_KEY_PEM[0]);
232*d9ecfb0fSAndroid Build Coastguard Worker         let key: KeyAgreementPublicKey = pkey.clone().try_into().unwrap();
233*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.kind, KeyAgreementKind::Ec(EcKind::P256));
234*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
235*d9ecfb0fSAndroid Build Coastguard Worker     }
236*d9ecfb0fSAndroid Build Coastguard Worker 
237*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
key_agreement_key_from_p384_pkey()238*d9ecfb0fSAndroid Build Coastguard Worker     fn key_agreement_key_from_p384_pkey() {
239*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::P384_KEY_PEM[0]);
240*d9ecfb0fSAndroid Build Coastguard Worker         let key: KeyAgreementPublicKey = pkey.clone().try_into().unwrap();
241*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.kind, KeyAgreementKind::Ec(EcKind::P384));
242*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
243*d9ecfb0fSAndroid Build Coastguard Worker     }
244*d9ecfb0fSAndroid Build Coastguard Worker 
245*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
key_agreement_key_from_ed25519_pkey_not_supported()246*d9ecfb0fSAndroid Build Coastguard Worker     fn key_agreement_key_from_ed25519_pkey_not_supported() {
247*d9ecfb0fSAndroid Build Coastguard Worker         let pkey = load_public_pkey(testkeys::ED25519_KEY_PEM[0]);
248*d9ecfb0fSAndroid Build Coastguard Worker         assert!(KeyAgreementPublicKey::try_from(pkey).is_err());
249*d9ecfb0fSAndroid Build Coastguard Worker     }
250*d9ecfb0fSAndroid Build Coastguard Worker 
load_public_pkey(pem: &str) -> PKey<Public>251*d9ecfb0fSAndroid Build Coastguard Worker     pub fn load_public_pkey(pem: &str) -> PKey<Public> {
252*d9ecfb0fSAndroid Build Coastguard Worker         testkeys::public_from_private(&PKey::private_key_from_pem(pem.as_bytes()).unwrap())
253*d9ecfb0fSAndroid Build Coastguard Worker     }
254*d9ecfb0fSAndroid Build Coastguard Worker 
255*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
verify_pkey_equality()256*d9ecfb0fSAndroid Build Coastguard Worker     fn verify_pkey_equality() {
257*d9ecfb0fSAndroid Build Coastguard Worker         let first = PKeyPublicWrapper(load_public_pkey(testkeys::ED25519_KEY_PEM[0]));
258*d9ecfb0fSAndroid Build Coastguard Worker         let second = PKeyPublicWrapper(load_public_pkey(testkeys::ED25519_KEY_PEM[0]));
259*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(&first, &first);
260*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(&first, &second);
261*d9ecfb0fSAndroid Build Coastguard Worker         assert_eq!(&second, &first);
262*d9ecfb0fSAndroid Build Coastguard Worker     }
263*d9ecfb0fSAndroid Build Coastguard Worker 
264*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
verify_key_kind_inequality()265*d9ecfb0fSAndroid Build Coastguard Worker     fn verify_key_kind_inequality() {
266*d9ecfb0fSAndroid Build Coastguard Worker         let ed25519 = PKeyPublicWrapper(load_public_pkey(testkeys::ED25519_KEY_PEM[0]));
267*d9ecfb0fSAndroid Build Coastguard Worker         let p256 = PKeyPublicWrapper(load_public_pkey(testkeys::P256_KEY_PEM[0]));
268*d9ecfb0fSAndroid Build Coastguard Worker         assert_ne!(&ed25519, &p256);
269*d9ecfb0fSAndroid Build Coastguard Worker         assert_ne!(&p256, &ed25519);
270*d9ecfb0fSAndroid Build Coastguard Worker     }
271*d9ecfb0fSAndroid Build Coastguard Worker 
272*d9ecfb0fSAndroid Build Coastguard Worker     #[test]
verify_key_bits_inequality()273*d9ecfb0fSAndroid Build Coastguard Worker     fn verify_key_bits_inequality() {
274*d9ecfb0fSAndroid Build Coastguard Worker         let first = PKeyPublicWrapper(load_public_pkey(testkeys::P256_KEY_PEM[0]));
275*d9ecfb0fSAndroid Build Coastguard Worker         let second = PKeyPublicWrapper(load_public_pkey(testkeys::P256_KEY_PEM[1]));
276*d9ecfb0fSAndroid Build Coastguard Worker         assert_ne!(&first, &second);
277*d9ecfb0fSAndroid Build Coastguard Worker         assert_ne!(&second, &first);
278*d9ecfb0fSAndroid Build Coastguard Worker     }
279*d9ecfb0fSAndroid Build Coastguard Worker }
280*d9ecfb0fSAndroid Build Coastguard Worker 
281*d9ecfb0fSAndroid Build Coastguard Worker /// Keys and key handling utilities for use in tests.
282*d9ecfb0fSAndroid Build Coastguard Worker #[cfg(test)]
283*d9ecfb0fSAndroid Build Coastguard Worker pub(crate) mod testkeys {
284*d9ecfb0fSAndroid Build Coastguard Worker     use super::*;
285*d9ecfb0fSAndroid Build Coastguard Worker     use openssl::pkey::Private;
286*d9ecfb0fSAndroid Build Coastguard Worker     use openssl::sign::Signer;
287*d9ecfb0fSAndroid Build Coastguard Worker 
288*d9ecfb0fSAndroid Build Coastguard Worker     pub struct PrivateKey {
289*d9ecfb0fSAndroid Build Coastguard Worker         kind: SignatureKind,
290*d9ecfb0fSAndroid Build Coastguard Worker         pkey: PKey<Private>,
291*d9ecfb0fSAndroid Build Coastguard Worker     }
292*d9ecfb0fSAndroid Build Coastguard Worker 
293*d9ecfb0fSAndroid Build Coastguard Worker     impl PrivateKey {
from_pem(pem: &str) -> Self294*d9ecfb0fSAndroid Build Coastguard Worker         pub fn from_pem(pem: &str) -> Self {
295*d9ecfb0fSAndroid Build Coastguard Worker             let pkey = PKey::private_key_from_pem(pem.as_bytes()).unwrap();
296*d9ecfb0fSAndroid Build Coastguard Worker             let kind = PublicKey::pkey_kind(&pkey).expect("unsupported private key");
297*d9ecfb0fSAndroid Build Coastguard Worker             Self { kind, pkey }
298*d9ecfb0fSAndroid Build Coastguard Worker         }
299*d9ecfb0fSAndroid Build Coastguard Worker 
kind(&self) -> SignatureKind300*d9ecfb0fSAndroid Build Coastguard Worker         pub(crate) fn kind(&self) -> SignatureKind {
301*d9ecfb0fSAndroid Build Coastguard Worker             self.kind
302*d9ecfb0fSAndroid Build Coastguard Worker         }
303*d9ecfb0fSAndroid Build Coastguard Worker 
public_key(&self) -> PublicKey304*d9ecfb0fSAndroid Build Coastguard Worker         pub fn public_key(&self) -> PublicKey {
305*d9ecfb0fSAndroid Build Coastguard Worker             public_from_private(&self.pkey).try_into().unwrap()
306*d9ecfb0fSAndroid Build Coastguard Worker         }
307*d9ecfb0fSAndroid Build Coastguard Worker 
sign(&self, message: &[u8]) -> Result<Vec<u8>>308*d9ecfb0fSAndroid Build Coastguard Worker         pub fn sign(&self, message: &[u8]) -> Result<Vec<u8>> {
309*d9ecfb0fSAndroid Build Coastguard Worker             let mut signer = match self.kind {
310*d9ecfb0fSAndroid Build Coastguard Worker                 SignatureKind::Ed25519 => Signer::new_without_digest(&self.pkey)?,
311*d9ecfb0fSAndroid Build Coastguard Worker                 SignatureKind::Ec(ec) => Signer::new(digest_for_ec(ec), &self.pkey)?,
312*d9ecfb0fSAndroid Build Coastguard Worker             };
313*d9ecfb0fSAndroid Build Coastguard Worker             signer.sign_oneshot_to_vec(message).context("signing message")
314*d9ecfb0fSAndroid Build Coastguard Worker         }
315*d9ecfb0fSAndroid Build Coastguard Worker     }
316*d9ecfb0fSAndroid Build Coastguard Worker 
317*d9ecfb0fSAndroid Build Coastguard Worker     /// Gives the public key that matches the private key.
public_from_private(pkey: &PKey<Private>) -> PKey<Public>318*d9ecfb0fSAndroid Build Coastguard Worker     pub fn public_from_private(pkey: &PKey<Private>) -> PKey<Public> {
319*d9ecfb0fSAndroid Build Coastguard Worker         // It feels like there should be a more direct way to do this but I haven't found it.
320*d9ecfb0fSAndroid Build Coastguard Worker         PKey::public_key_from_der(&pkey.public_key_to_der().unwrap()).unwrap()
321*d9ecfb0fSAndroid Build Coastguard Worker     }
322*d9ecfb0fSAndroid Build Coastguard Worker 
323*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of X25519 private keys.
324*d9ecfb0fSAndroid Build Coastguard Worker     pub const X25519_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
325*d9ecfb0fSAndroid Build Coastguard Worker         MC4CAQAwBQYDK2VuBCIEIMDLdDFad6CwwacwNtW/kQujlrAkxIjQ/Co3DleSd9xV\n\
326*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n"];
327*d9ecfb0fSAndroid Build Coastguard Worker 
328*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of Ed25519 private keys.
329*d9ecfb0fSAndroid Build Coastguard Worker     pub const ED25519_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
330*d9ecfb0fSAndroid Build Coastguard Worker         MC4CAQAwBQYDK2VwBCIEILKW0KEeuieFxhDAzigQPE4XRTiQx+0/AlAjJqHmUWE6\n\
331*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n"];
332*d9ecfb0fSAndroid Build Coastguard Worker 
333*d9ecfb0fSAndroid Build Coastguard Worker     pub const ED25519_KEY_WITH_LEADING_ZEROS_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
334*d9ecfb0fSAndroid Build Coastguard Worker         MC4CAQAwBQYDK2VwBCIEIBDTK4d0dffOye5RD6HsgcOFoDTtvQH1tPmr9RjpadxJ\n\
335*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n"];
336*d9ecfb0fSAndroid Build Coastguard Worker 
337*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of elliptic curve P-256 private keys.
338*d9ecfb0fSAndroid Build Coastguard Worker     pub const P256_KEY_PEM: &[&str] = &[
339*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
340*d9ecfb0fSAndroid Build Coastguard Worker         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg+CO3ZBuAsimwPKAL\n\
341*d9ecfb0fSAndroid Build Coastguard Worker         IeDyCh4cRZ5EMd6llGu5MQCpibGhRANCAAQObPxc4bIPjupILrvKJjTrpTcyCf6q\n\
342*d9ecfb0fSAndroid Build Coastguard Worker         V552FlS67fGphwhg2LDfQ8adEdkuRfQvk+IvKJz8MDcPjErBG3Wlps1N\n\
343*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
344*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
345*d9ecfb0fSAndroid Build Coastguard Worker         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgw1OPIcfQv5twO68B\n\
346*d9ecfb0fSAndroid Build Coastguard Worker         H+xNstW3DLXC6e4PGEYG/VppYVahRANCAAQMyWyv4ffVMu+wVNhNEk2mQSaTmSl/\n\
347*d9ecfb0fSAndroid Build Coastguard Worker         dLdRbEowfqPwMzdqdQ3QlKSV4ZcU2lsJEuQMkZzmVPz02enY2qcKctmj\n\
348*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
349*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
350*d9ecfb0fSAndroid Build Coastguard Worker         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgbXO6ee7i7sY4YfFS\n\
351*d9ecfb0fSAndroid Build Coastguard Worker         Gn60ScPuL3QuYFMX4nJbcqPSQ7+hRANCAAS8i9xA8cIcWStbMG97YrttQsYEIR2a\n\
352*d9ecfb0fSAndroid Build Coastguard Worker         15+alxbb6b7422FuxBB0qG5nJ4m+Jd3Bp+N2lwx4rHBFDqU4cp8VlQav\n\
353*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
354*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
355*d9ecfb0fSAndroid Build Coastguard Worker         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/JuxkbpPyyouat11\n\
356*d9ecfb0fSAndroid Build Coastguard Worker         szDR+OA7d/fuMk9IhGkH7z1xHzChRANCAASRlY0D7Uh5T/FmB6txGr21w6jqKW2x\n\
357*d9ecfb0fSAndroid Build Coastguard Worker         RXdsaZgCB6XnrXlkgkvuWDc0CTLSBWdPFgW6OX0fyXViglEBH95REyQr\n\
358*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
359*d9ecfb0fSAndroid Build Coastguard Worker     ];
360*d9ecfb0fSAndroid Build Coastguard Worker 
361*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of EC keys that should have leading zeros in their coordinates
362*d9ecfb0fSAndroid Build Coastguard Worker     pub const EC2_KEY_WITH_LEADING_ZEROS_PEM: &[&str] = &[
363*d9ecfb0fSAndroid Build Coastguard Worker         // P256
364*d9ecfb0fSAndroid Build Coastguard Worker         // Public key has Y coordinate with most significant byte of 0x00
365*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
366*d9ecfb0fSAndroid Build Coastguard Worker         MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCWbRSB3imI03F5YNVq\n\
367*d9ecfb0fSAndroid Build Coastguard Worker         8AN8ZbyzW/h+5BQ53caD5VkWJg==\n\
368*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
369*d9ecfb0fSAndroid Build Coastguard Worker         // P256
370*d9ecfb0fSAndroid Build Coastguard Worker         // Public key has X coordinate with most significant byte of 0x00
371*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
372*d9ecfb0fSAndroid Build Coastguard Worker         MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDe5E5WqNmCLxtsCNTc\n\
373*d9ecfb0fSAndroid Build Coastguard Worker         UOb9CPXCn6l3CZpbrp0aivb+Bw==\n\
374*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
375*d9ecfb0fSAndroid Build Coastguard Worker         // P384
376*d9ecfb0fSAndroid Build Coastguard Worker         // Public key has Y coordinate with most significant byte of 0x00
377*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
378*d9ecfb0fSAndroid Build Coastguard Worker         ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDCzgVHCz7wgmSdb7/IixYik\n\
379*d9ecfb0fSAndroid Build Coastguard Worker         3AuQceCtBTiFrJpgpGFluwgLUR0S2NpzIuty4M7xU74=\n\
380*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
381*d9ecfb0fSAndroid Build Coastguard Worker         // P384
382*d9ecfb0fSAndroid Build Coastguard Worker         // Public key has X coordinate with most significant byte of 0x00
383*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
384*d9ecfb0fSAndroid Build Coastguard Worker         ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDBoW+8zbvwf5fYOS8YPyPEH\n\
385*d9ecfb0fSAndroid Build Coastguard Worker         jHP71Vr1MnRYRp/yG1wbthW2XEu0UWbp4qrZ5WTnZPg=\n\
386*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
387*d9ecfb0fSAndroid Build Coastguard Worker     ];
388*d9ecfb0fSAndroid Build Coastguard Worker     pub const EC2_KEY_WITH_HIGH_BITS_SET_PEM: &[&str] = &[
389*d9ecfb0fSAndroid Build Coastguard Worker         // P256
390*d9ecfb0fSAndroid Build Coastguard Worker         // Public key has X & Y coordinate that both have most significant bit set,
391*d9ecfb0fSAndroid Build Coastguard Worker         // and some stacks will add a padding byte
392*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
393*d9ecfb0fSAndroid Build Coastguard Worker         MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCWOWcXPDEVZ4Qz3EBK\n\
394*d9ecfb0fSAndroid Build Coastguard Worker         uvSqhD9HmxDGxcNe3yxKi9pazw==\n\
395*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
396*d9ecfb0fSAndroid Build Coastguard Worker         // P384
397*d9ecfb0fSAndroid Build Coastguard Worker         // Public key has X & Y coordinate that both have most significant bit set,
398*d9ecfb0fSAndroid Build Coastguard Worker         // and some stacks will add a padding byte
399*d9ecfb0fSAndroid Build Coastguard Worker         "-----BEGIN PRIVATE KEY-----\n\
400*d9ecfb0fSAndroid Build Coastguard Worker         ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDD2A69j5M/6oc6/WGoYln4t\n\
401*d9ecfb0fSAndroid Build Coastguard Worker         Alnn0C6kpJz1EVC+eH6y0YNrcGamz8pPY4NkzUB/tj4=\n\
402*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n",
403*d9ecfb0fSAndroid Build Coastguard Worker     ];
404*d9ecfb0fSAndroid Build Coastguard Worker 
405*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of elliptic curve P-384 private keys.
406*d9ecfb0fSAndroid Build Coastguard Worker     pub const P384_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
407*d9ecfb0fSAndroid Build Coastguard Worker         MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBMZ414LiUpcuNTNq5W\n\
408*d9ecfb0fSAndroid Build Coastguard Worker         Ig/qbnbFn0MpuZZxUn5YZ8/+2/tyXFFHRyQoQ4YpNN1P/+qhZANiAAScPDyisb21\n\
409*d9ecfb0fSAndroid Build Coastguard Worker         GldmGksI5g82hjPRYscWNs/6pFxQTMcxABE+/1lWaryLR193ZD74VxVRIKDBluRs\n\
410*d9ecfb0fSAndroid Build Coastguard Worker         uuHi+VayOreTX1/qlUoxgBT+XTI0nTdLn6WwO6vVO1NIkGEVnYvB2eM=\n\
411*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n"];
412*d9ecfb0fSAndroid Build Coastguard Worker 
413*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of elliptic curve P-521 private keys.
414*d9ecfb0fSAndroid Build Coastguard Worker     pub const P521_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
415*d9ecfb0fSAndroid Build Coastguard Worker         MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBQuD8Db3jT2yPYR5t\n\
416*d9ecfb0fSAndroid Build Coastguard Worker         Y1ZqESxOe4eBWzekFKg7cjVWsSiJEvWTPC1H7CLtXQBHZglO90dwMt4flL91xHkl\n\
417*d9ecfb0fSAndroid Build Coastguard Worker         iZOzyHahgYkDgYYABAHACwmmKkZu01fp1QTTTQ0cv7IAfYv9FEBz8yfhNGPnI2WY\n\
418*d9ecfb0fSAndroid Build Coastguard Worker         iH1/lYeCfYc9d33aSc/ELY9+vIFzVStJumS/B/WTewEhxVomlKPAkUJeLdCaK5av\n\
419*d9ecfb0fSAndroid Build Coastguard Worker         nlUNj7pNQ/5v5FZVxmoFJvAtUAnZqnJqo/QkLtEnmKlzpLte2LuwTPZhG35z0HeL\n\
420*d9ecfb0fSAndroid Build Coastguard Worker         2g==\n\
421*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n"];
422*d9ecfb0fSAndroid Build Coastguard Worker 
423*d9ecfb0fSAndroid Build Coastguard Worker     /// A selection of 2048-bit RSA private keys.
424*d9ecfb0fSAndroid Build Coastguard Worker     pub const RSA2048_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
425*d9ecfb0fSAndroid Build Coastguard Worker         MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbOJh7Ys7CuIju\n\
426*d9ecfb0fSAndroid Build Coastguard Worker         VVKMlFlZWwDEGBX5bVYD/xNBNNF1FY9bOcV/BG20IwoZkdV0N+vm8eWSuv/uwIJp\n\
427*d9ecfb0fSAndroid Build Coastguard Worker         sN2PMWPAEIWbPGGMnSdePpkwrdpFFywhEQqUrfdCFXZ8zeF85Nz5mL8ysl4vlMsL\n\
428*d9ecfb0fSAndroid Build Coastguard Worker         mbErCkrq++K0lzs+k7w/FtPCgs4M3WypJfZef5zM0CGWxpHZGoUGm0HW9fen4sv8\n\
429*d9ecfb0fSAndroid Build Coastguard Worker         hTmMGNY/r0SJhdZREGmiGCx2v+ksOEBon1r/6QKVTP8S73XFsyNCWyop0hYTakut\n\
430*d9ecfb0fSAndroid Build Coastguard Worker         D3HtJ5sWzu2RU8rrch3Txinz0jpGF8PATHk35YMw/9jwwwSqjDw+pOQcYk8SviAf\n\
431*d9ecfb0fSAndroid Build Coastguard Worker         glZf8aZlAgMBAAECggEAAS67PK67tuaOWywJSWHLsWGmqJ4I2tZiTzCT9EZ2MOVx\n\
432*d9ecfb0fSAndroid Build Coastguard Worker         +4ZChNfjHUsskXUp4XNL/FE0J3WvhEYjXR1u+L37nvqc48mJpjoPN7o/CMb6rM/J\n\
433*d9ecfb0fSAndroid Build Coastguard Worker         +ly9A2ZOvEB4ppOYDYh5QVDm7/otmvEMzJxuUOpvxYxqnJpAPgl9dBpNQ0nSt3YX\n\
434*d9ecfb0fSAndroid Build Coastguard Worker         jJS4+vuzQpwwSTfchpcCZYU3AX9DpQpxnrLX3/7d3GTs2NuedmSwRz+mCfwaOlFk\n\
435*d9ecfb0fSAndroid Build Coastguard Worker         jdrJ2uJJrDLcK6yhSdsE9aNgKkmX6aNLhxbbCFTyDNiGY5HHayyL3mVvyaeovYcn\n\
436*d9ecfb0fSAndroid Build Coastguard Worker         ZS+Z+0TJGCgXDRHHSFyIAsgVonxHfn49x9uvfpuMFQKBgQD2cVp26+aQgt46ajVv\n\
437*d9ecfb0fSAndroid Build Coastguard Worker         yn4fxbNpfovL0pgtSjo7ekZOWYJ3Is1SDmnni8k1ViKgUYC210dTTlrljxUil8T0\n\
438*d9ecfb0fSAndroid Build Coastguard Worker         83e03k2xasDi2c+h/7JFYJPDyZwIm1o19ciUwY73D54iJaRbrzEximFeA0h4LGKw\n\
439*d9ecfb0fSAndroid Build Coastguard Worker         Yjd4xkKMJw16CU00gInyI193BwKBgQDjuP0/QEEPpYvzpag5Ul4+h22K/tiOUrFj\n\
440*d9ecfb0fSAndroid Build Coastguard Worker         NuSgd+IvQG1hW48zHEa9vXvORQ/FteiQ708racz6ByqY+n2w6QdtdRMj7Hsyo2fk\n\
441*d9ecfb0fSAndroid Build Coastguard Worker         SEeNaLrR7Sif6MfkYajbSGFySDD82vj4Jt76vzdt3MjpZfs6ryPmnKLVPWNA3mnS\n\
442*d9ecfb0fSAndroid Build Coastguard Worker         4+u2J/+QMwKBgFfiJnugNnG0aaF1PKcoFAAqlYd6XEoMSL5l6QxK14WbP/5SR9wK\n\
443*d9ecfb0fSAndroid Build Coastguard Worker         TdQHsnI1zFVVm0wYy1O27o1MkCHs84zSwg6a9CPfyPdc60F/GMjK3wcD/4PGOs5h\n\
444*d9ecfb0fSAndroid Build Coastguard Worker         Xu1FdUE/rYnJ2KnleOqMyZooG5DXaz4xWEzWjubCCnlJleGyMP9LhADDAoGAR/jK\n\
445*d9ecfb0fSAndroid Build Coastguard Worker         iXgcV/6haeMcdOl0gdy5oWmENg8qo0nRHmplYTvCljei3at9LDC79WhcYMdqdow8\n\
446*d9ecfb0fSAndroid Build Coastguard Worker         AGOS9h7XtrvMh+JOh6it4Pe3xDxi9IJnoujLytditI+Uxbib7ppEuiLY4MGwWHWo\n\
447*d9ecfb0fSAndroid Build Coastguard Worker         maVftmhGU4X4zgZWmWc+C5k4SmNBHPcOI2cm3YMCgYB5/Ni+tBxng0S/PRAtwCeG\n\
448*d9ecfb0fSAndroid Build Coastguard Worker         dVnQnYvS2C5nHCn9D5rmAcVXUKrIJ1/1K4se8vQ15DDcpuBF1SejYTJzdUP8Zgcs\n\
449*d9ecfb0fSAndroid Build Coastguard Worker         p8wVq7neK8uSsmG+AfUgxMjbetoAVTP3L8+GbjocznR9auB7BEjFVO25iYSiTp/w\n\
450*d9ecfb0fSAndroid Build Coastguard Worker         NNzbIKQRDN+c3vUpneJcuw==\n\
451*d9ecfb0fSAndroid Build Coastguard Worker         -----END PRIVATE KEY-----\n"];
452*d9ecfb0fSAndroid Build Coastguard Worker }
453