1use crate::{
15 KeyPair, Mayo1, Mayo2, Mayo3, Mayo5, MayoParameter, Signature, SigningKey, VerifyingKey,
16};
17use ::pkcs8::{
18 AlgorithmIdentifierRef, EncodePrivateKey, ObjectIdentifier, PrivateKeyInfoRef,
19 der::{
20 self, AnyRef, Encode, Reader, TagMode, TagNumber,
21 asn1::{BitStringRef, ContextSpecific, OctetStringRef},
22 },
23 spki::{
24 self, AlgorithmIdentifier, AssociatedAlgorithmIdentifier, EncodePublicKey,
25 SignatureAlgorithmIdentifier, SignatureBitStringEncoding, SubjectPublicKeyInfo,
26 SubjectPublicKeyInfoRef,
27 },
28};
29
30const SEED_TAG_NUMBER: TagNumber = TagNumber(0);
32
33type SeedString<'a> = ContextSpecific<&'a OctetStringRef>;
35
36pub const MAYO1_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.9999.8.1.3");
50
51pub const MAYO2_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.9999.8.2.3");
53
54pub const MAYO3_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.9999.8.3.3");
56
57pub const MAYO5_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.9999.8.5.3");
59
60macro_rules! impl_algorithm_id {
65 ($type:ty, $oid:expr) => {
66 impl AssociatedAlgorithmIdentifier for $type {
67 type Params = AnyRef<'static>;
68
69 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef {
70 oid: $oid,
71 parameters: None,
72 };
73 }
74 };
75}
76
77impl_algorithm_id!(Mayo1, MAYO1_OID);
78impl_algorithm_id!(Mayo2, MAYO2_OID);
79impl_algorithm_id!(Mayo3, MAYO3_OID);
80impl_algorithm_id!(Mayo5, MAYO5_OID);
81
82impl<P> AssociatedAlgorithmIdentifier for Signature<P>
87where
88 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
89{
90 type Params = AnyRef<'static>;
91
92 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = P::ALGORITHM_IDENTIFIER;
93}
94
95impl<P: MayoParameter> SignatureBitStringEncoding for Signature<P> {
96 fn to_bitstring(&self) -> der::Result<der::asn1::BitString> {
97 der::asn1::BitString::new(0, self.as_ref().to_vec())
98 }
99}
100
101impl<P> SignatureAlgorithmIdentifier for KeyPair<P>
106where
107 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
108{
109 type Params = AnyRef<'static>;
110
111 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
112 Signature::<P>::ALGORITHM_IDENTIFIER;
113}
114
115impl<P> SignatureAlgorithmIdentifier for SigningKey<P>
116where
117 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
118{
119 type Params = AnyRef<'static>;
120
121 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
122 Signature::<P>::ALGORITHM_IDENTIFIER;
123}
124
125impl<P> SignatureAlgorithmIdentifier for VerifyingKey<P>
126where
127 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
128{
129 type Params = AnyRef<'static>;
130
131 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
132 Signature::<P>::ALGORITHM_IDENTIFIER;
133}
134
135impl<P> TryFrom<PrivateKeyInfoRef<'_>> for KeyPair<P>
140where
141 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
142{
143 type Error = ::pkcs8::Error;
144
145 fn try_from(private_key_info: PrivateKeyInfoRef<'_>) -> ::pkcs8::Result<Self> {
146 private_key_info
147 .algorithm
148 .assert_algorithm_oid(P::ALGORITHM_IDENTIFIER.oid)?;
149
150 let mut reader = der::SliceReader::new(private_key_info.private_key.as_bytes())?;
151 let seed_string = SeedString::decode_implicit(&mut reader, SEED_TAG_NUMBER)?
152 .ok_or(::pkcs8::Error::KeyMalformed)?;
153 let seed = seed_string.value.as_bytes();
154 reader.finish()?;
155
156 KeyPair::from_seed(seed).map_err(|_| ::pkcs8::Error::KeyMalformed)
157 }
158}
159
160impl<P> EncodePrivateKey for KeyPair<P>
161where
162 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
163{
164 fn to_pkcs8_der(&self) -> ::pkcs8::Result<der::SecretDocument> {
165 let seed = self.signing_key().as_ref();
166 let seed_der = SeedString {
167 tag_mode: TagMode::Implicit,
168 tag_number: SEED_TAG_NUMBER,
169 value: OctetStringRef::new(seed)?,
170 }
171 .to_der()?;
172
173 let private_key = OctetStringRef::new(&seed_der)?;
174 let private_key_info = PrivateKeyInfoRef::new(P::ALGORITHM_IDENTIFIER, private_key);
175 ::pkcs8::SecretDocument::encode_msg(&private_key_info).map_err(::pkcs8::Error::Asn1)
176 }
177}
178
179impl<P> TryFrom<PrivateKeyInfoRef<'_>> for SigningKey<P>
184where
185 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
186{
187 type Error = ::pkcs8::Error;
188
189 fn try_from(private_key_info: PrivateKeyInfoRef<'_>) -> ::pkcs8::Result<Self> {
190 let keypair = KeyPair::<P>::try_from(private_key_info)?;
191 Ok(keypair.signing_key().clone())
192 }
193}
194
195impl<P> TryFrom<SubjectPublicKeyInfoRef<'_>> for VerifyingKey<P>
200where
201 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
202{
203 type Error = spki::Error;
204
205 fn try_from(spki: SubjectPublicKeyInfoRef<'_>) -> spki::Result<Self> {
206 spki.algorithm
207 .assert_algorithm_oid(P::ALGORITHM_IDENTIFIER.oid)?;
208
209 let pk_bytes = spki
210 .subject_public_key
211 .as_bytes()
212 .ok_or(::pkcs8::Error::KeyMalformed)?;
213
214 VerifyingKey::try_from(pk_bytes).map_err(|_| ::pkcs8::Error::KeyMalformed.into())
215 }
216}
217
218impl<P> EncodePublicKey for VerifyingKey<P>
219where
220 P: MayoParameter + AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
221{
222 fn to_public_key_der(&self) -> spki::Result<der::Document> {
223 let subject_public_key = BitStringRef::new(0, self.as_ref())?;
224
225 SubjectPublicKeyInfo {
226 algorithm: P::ALGORITHM_IDENTIFIER,
227 subject_public_key,
228 }
229 .try_into()
230 }
231}