sequoia_openpgp/cert/bindings.rs
1use std::time;
2
3use crate::Error;
4use crate::Result;
5use crate::Cert;
6use crate::types::{HashAlgorithm, SignatureType};
7use crate::crypto::Signer;
8use crate::packet::{UserID, UserAttribute, key, Key, signature, Signature};
9
10impl<P: key::KeyParts> Key<P, key::SubordinateRole> {
11 /// Creates a binding signature.
12 ///
13 /// The signature binds this subkey to `cert`. `signer` will be used
14 /// to create a signature using `signature` as builder.
15 /// The`hash_algo` defaults to SHA512, `creation_time` to the
16 /// current time.
17 ///
18 /// Note that subkeys with signing capabilities need a [primary
19 /// key binding signature]. If you are creating this binding
20 /// signature from a previous binding signature, you can reuse the
21 /// primary key binding signature if it is still valid and meets
22 /// current algorithm requirements. Otherwise, you can create one
23 /// using [`SignatureBuilder::sign_primary_key_binding`].
24 ///
25 /// [primary key binding signature]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
26 /// [`SignatureBuilder::sign_primary_key_binding`]: signature::SignatureBuilder::sign_primary_key_binding()
27 ///
28 /// This function adds a creation time subpacket, an issuer
29 /// fingerprint subpacket, and an issuer subpacket to the
30 /// signature.
31 ///
32 /// # Examples
33 ///
34 /// This example demonstrates how to bind this key to a Cert. Note
35 /// that in general, the `CertBuilder` is a better way to add
36 /// subkeys to a Cert.
37 ///
38 /// ```
39 /// # use sequoia_openpgp::{*, packet::prelude::*, types::*, cert::*};
40 /// # fn main() -> Result<()> {
41 /// use sequoia_openpgp::policy::StandardPolicy;
42 /// let p = &StandardPolicy::new();
43 ///
44 /// // Generate a Cert, and create a keypair from the primary key.
45 /// let (cert, _) = CertBuilder::new().generate()?;
46 /// let mut keypair = cert.primary_key().key().clone()
47 /// .parts_into_secret()?.into_keypair()?;
48 ///
49 /// // Let's add an encryption subkey.
50 /// let flags = KeyFlags::empty().set_storage_encryption();
51 /// assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
52 /// .key_flags(&flags).count(),
53 /// 0);
54 ///
55 /// // Generate a subkey and a binding signature.
56 /// let subkey: Key<_, key::SubordinateRole> =
57 /// Key6::generate_ecc(false, Curve::Cv25519)?
58 /// .into();
59 /// let builder = signature::SignatureBuilder::new(SignatureType::SubkeyBinding)
60 /// .set_key_flags(flags.clone())?;
61 /// let binding = subkey.bind(&mut keypair, &cert, builder)?;
62 ///
63 /// // Now merge the key and binding signature into the Cert.
64 /// let cert = cert.insert_packets(vec![Packet::from(subkey),
65 /// binding.into()])?.0;
66 ///
67 /// // Check that we have an encryption subkey.
68 /// assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
69 /// .key_flags(flags).count(),
70 /// 1);
71 /// # Ok(()) }
72 pub fn bind(&self, signer: &mut dyn Signer, cert: &Cert,
73 signature: signature::SignatureBuilder)
74 -> Result<Signature>
75 {
76 signature.sign_subkey_binding(
77 signer, cert.primary_key().key(), self)
78 }
79}
80
81impl UserID {
82 /// Creates a binding signature.
83 ///
84 /// The signature binds this User ID to `cert`. `signer` will be used
85 /// to create a signature using `signature` as builder.
86 /// The`hash_algo` defaults to SHA512, `creation_time` to the
87 /// current time.
88 ///
89 /// This function adds a creation time subpacket, an issuer
90 /// fingerprint subpacket, and an issuer subpacket to the
91 /// signature.
92 ///
93 /// # Examples
94 ///
95 /// This example demonstrates how to bind this User ID to a Cert.
96 /// Note that in general, the `CertBuilder` is a better way to add
97 /// User IDs to a Cert.
98 ///
99 /// ```
100 /// # use sequoia_openpgp::{*, packet::prelude::*, types::*, cert::*};
101 /// # fn main() -> Result<()> {
102 /// // Generate a Cert, and create a keypair from the primary key.
103 /// let (cert, _) = CertBuilder::new().generate()?;
104 /// let mut keypair = cert.primary_key().key().clone()
105 /// .parts_into_secret()?.into_keypair()?;
106 /// assert_eq!(cert.userids().len(), 0);
107 ///
108 /// // Generate a User ID and a binding signature.
109 /// let userid = UserID::from("test@example.org");
110 /// let builder =
111 /// signature::SignatureBuilder::new(SignatureType::PositiveCertification);
112 /// let binding = userid.bind(&mut keypair, &cert, builder)?;
113 ///
114 /// // Now merge the User ID and binding signature into the Cert.
115 /// let cert = cert.insert_packets(vec![Packet::from(userid),
116 /// binding.into()])?.0;
117 ///
118 /// // Check that we have a User ID.
119 /// assert_eq!(cert.userids().len(), 1);
120 /// # Ok(()) }
121 pub fn bind(&self, signer: &mut dyn Signer, cert: &Cert,
122 signature: signature::SignatureBuilder)
123 -> Result<Signature>
124 {
125 signature.sign_userid_binding(
126 signer, cert.primary_key().key(), self)
127 }
128
129 /// Returns a certification for the User ID.
130 ///
131 /// The signature binds this User ID to `cert`. `signer` will be
132 /// used to create a certification signature of type
133 /// `signature_type`. `signature_type` defaults to
134 /// `SignatureType::GenericCertification`, `hash_algo` to SHA512,
135 /// `creation_time` to the current time.
136 ///
137 /// This function adds a creation time subpacket, an issuer
138 /// fingerprint subpacket, and an issuer subpacket to the
139 /// signature.
140 ///
141 /// # Errors
142 ///
143 /// Returns `Error::InvalidArgument` if `signature_type` is not
144 /// one of `SignatureType::{Generic, Persona, Casual,
145 /// Positive}Certification`
146 ///
147 /// # Examples
148 ///
149 /// This example demonstrates how to certify a User ID.
150 ///
151 /// ```
152 /// # use sequoia_openpgp::{*, packet::prelude::*, types::*, cert::*};
153 /// # fn main() -> Result<()> {
154 /// // Generate a Cert, and create a keypair from the primary key.
155 /// let (alice, _) = CertBuilder::new()
156 /// .set_primary_key_flags(KeyFlags::empty().set_certification())
157 /// .add_userid("alice@example.org")
158 /// .generate()?;
159 /// let mut keypair = alice.primary_key().key().clone()
160 /// .parts_into_secret()?.into_keypair()?;
161 ///
162 /// // Generate a Cert for Bob.
163 /// let (bob, _) = CertBuilder::new()
164 /// .set_primary_key_flags(KeyFlags::empty().set_certification())
165 /// .add_userid("bob@example.org")
166 /// .generate()?;
167 ///
168 /// // Alice now certifies the binding between `bob@example.org` and `bob`.
169 /// let certification =
170 /// bob.userids().nth(0).unwrap()
171 /// .userid()
172 /// .certify(&mut keypair, &bob, SignatureType::PositiveCertification,
173 /// None, None)?;
174 ///
175 /// // `certification` can now be used, e.g. by merging it into `bob`.
176 /// let bob = bob.insert_packets(certification)?.0;
177 ///
178 /// // Check that we have a certification on the User ID.
179 /// assert_eq!(bob.userids().nth(0).unwrap()
180 /// .certifications().count(), 1);
181 /// # Ok(()) }
182 pub fn certify<S, H, T>(&self, signer: &mut dyn Signer, cert: &Cert,
183 signature_type: S,
184 hash_algo: H, creation_time: T)
185 -> Result<Signature>
186 where S: Into<Option<SignatureType>>,
187 H: Into<Option<HashAlgorithm>>,
188 T: Into<Option<time::SystemTime>>
189 {
190 let typ = signature_type.into();
191 let typ = match typ {
192 Some(SignatureType::GenericCertification)
193 | Some(SignatureType::PersonaCertification)
194 | Some(SignatureType::CasualCertification)
195 | Some(SignatureType::PositiveCertification) => typ.unwrap(),
196 Some(t) => return Err(Error::InvalidArgument(
197 format!("Invalid signature type: {}", t)).into()),
198 None => SignatureType::GenericCertification,
199 };
200 let mut sig = signature::SignatureBuilder::new(typ);
201 if let Some(algo) = hash_algo.into() {
202 sig = sig.set_hash_algo(algo);
203 }
204 if let Some(creation_time) = creation_time.into() {
205 sig = sig.set_signature_creation_time(creation_time)?;
206 }
207 self.bind(signer, cert, sig)
208 }
209}
210
211impl UserAttribute {
212 /// Creates a binding signature.
213 ///
214 /// The signature binds this user attribute to `cert`. `signer`
215 /// will be used to create a signature using `signature` as
216 /// builder. The`hash_algo` defaults to SHA512, `creation_time`
217 /// to the current time.
218 ///
219 /// This function adds a creation time subpacket, an issuer
220 /// fingerprint subpacket, and an issuer subpacket to the
221 /// signature.
222 ///
223 /// # Examples
224 ///
225 /// This example demonstrates how to bind this user attribute to a
226 /// Cert. Note that in general, the `CertBuilder` is a better way
227 /// to add User IDs to a Cert.
228 ///
229 /// ```
230 /// # use sequoia_openpgp::{*, packet::prelude::*, types::*, cert::*,
231 /// # packet::user_attribute::*};
232 /// # fn main() -> Result<()> {
233 /// // Generate a Cert, and create a keypair from the primary key.
234 /// let (cert, _) = CertBuilder::new()
235 /// .generate()?;
236 /// let mut keypair = cert.primary_key().key().clone()
237 /// .parts_into_secret()?.into_keypair()?;
238 /// assert_eq!(cert.userids().len(), 0);
239 ///
240 /// // Generate a user attribute and a binding signature.
241 /// let user_attr = UserAttribute::new(&[
242 /// Subpacket::Image(
243 /// Image::Private(100, vec![0, 1, 2].into_boxed_slice())),
244 /// ])?;
245 /// let builder =
246 /// signature::SignatureBuilder::new(SignatureType::PositiveCertification);
247 /// let binding = user_attr.bind(&mut keypair, &cert, builder)?;
248 ///
249 /// // Now merge the user attribute and binding signature into the Cert.
250 /// let cert = cert.insert_packets(vec![Packet::from(user_attr),
251 /// binding.into()])?.0;
252 ///
253 /// // Check that we have a user attribute.
254 /// assert_eq!(cert.user_attributes().count(), 1);
255 /// # Ok(()) }
256 pub fn bind(&self, signer: &mut dyn Signer, cert: &Cert,
257 signature: signature::SignatureBuilder)
258 -> Result<Signature>
259 {
260 signature.sign_user_attribute_binding(
261 signer, cert.primary_key().key(), self)
262 }
263
264 /// Returns a certification for the user attribute.
265 ///
266 /// The signature binds this user attribute to `cert`. `signer` will be
267 /// used to create a certification signature of type
268 /// `signature_type`. `signature_type` defaults to
269 /// `SignatureType::GenericCertification`, `hash_algo` to SHA512,
270 /// `creation_time` to the current time.
271 ///
272 /// This function adds a creation time subpacket, an issuer
273 /// fingerprint subpacket, and an issuer subpacket to the
274 /// signature.
275 ///
276 /// # Errors
277 ///
278 /// Returns `Error::InvalidArgument` if `signature_type` is not
279 /// one of `SignatureType::{Generic, Persona, Casual,
280 /// Positive}Certification`
281 ///
282 /// # Examples
283 ///
284 /// This example demonstrates how to certify a User ID.
285 ///
286 /// ```
287 /// # use sequoia_openpgp::{*, packet::prelude::*, types::*, cert::*,
288 /// # packet::user_attribute::*};
289 /// # fn main() -> Result<()> {
290 /// // Generate a Cert, and create a keypair from the primary key.
291 /// let (alice, _) = CertBuilder::new()
292 /// .add_userid("alice@example.org")
293 /// .generate()?;
294 /// let mut keypair = alice.primary_key().key().clone()
295 /// .parts_into_secret()?.into_keypair()?;
296 ///
297 /// // Generate a Cert for Bob.
298 /// let user_attr = UserAttribute::new(&[
299 /// Subpacket::Image(
300 /// Image::Private(100, vec![0, 1, 2].into_boxed_slice())),
301 /// ])?;
302 /// let (bob, _) = CertBuilder::new()
303 /// .set_primary_key_flags(KeyFlags::empty().set_certification())
304 /// .add_user_attribute(user_attr)
305 /// .generate()?;
306 ///
307 /// // Alice now certifies the binding between `bob@example.org` and `bob`.
308 /// let certification =
309 /// bob.user_attributes().nth(0).unwrap()
310 /// .user_attribute()
311 /// .certify(&mut keypair, &bob, SignatureType::PositiveCertification,
312 /// None, None)?;
313 ///
314 /// // `certification` can now be used, e.g. by merging it into `bob`.
315 /// let bob = bob.insert_packets(certification)?.0;
316 ///
317 /// // Check that we have a certification on the User ID.
318 /// assert_eq!(bob.user_attributes().nth(0).unwrap()
319 /// .certifications().count(),
320 /// 1);
321 /// # Ok(()) }
322 pub fn certify<S, H, T>(&self, signer: &mut dyn Signer, cert: &Cert,
323 signature_type: S,
324 hash_algo: H, creation_time: T)
325 -> Result<Signature>
326 where S: Into<Option<SignatureType>>,
327 H: Into<Option<HashAlgorithm>>,
328 T: Into<Option<time::SystemTime>>
329 {
330 let typ = signature_type.into();
331 let typ = match typ {
332 Some(SignatureType::GenericCertification)
333 | Some(SignatureType::PersonaCertification)
334 | Some(SignatureType::CasualCertification)
335 | Some(SignatureType::PositiveCertification) => typ.unwrap(),
336 Some(t) => return Err(Error::InvalidArgument(
337 format!("Invalid signature type: {}", t)).into()),
338 None => SignatureType::GenericCertification,
339 };
340 let mut sig = signature::SignatureBuilder::new(typ);
341 if let Some(algo) = hash_algo.into() {
342 sig = sig.set_hash_algo(algo);
343 }
344 if let Some(creation_time) = creation_time.into() {
345 sig = sig.set_signature_creation_time(creation_time)?;
346 }
347 self.bind(signer, cert, sig)
348 }
349}