From a464ce819ccd1fa07ff8c6d0be74cff5eec5cf34 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Fri, 31 Jan 2020 14:20:53 +0100 Subject: openpgp: Add a policy object. - Change all functions that need to evaluate the validity of a signature (either directly or indirectly to take a policy object. - Use the policy object to allow the user to place additional constraints on a signature's validity. - This addresses the first half of #274 (it introduces the policy object, but does not yet implement any policy). --- examples/guide-exploring-openpgp.rs | 7 +- guide/src/chapter_01.md | 98 +++++--- guide/src/chapter_02.md | 88 +++++--- ipc/examples/gpg-agent-decrypt.rs | 12 +- ipc/examples/gpg-agent-sign.rs | 5 +- ipc/tests/gpg-agent.rs | 20 +- openpgp-ffi/examples/decrypt-with.c | 4 +- openpgp-ffi/examples/encrypt-for.c | 4 +- openpgp-ffi/include/sequoia/openpgp.h | 82 +++++-- openpgp-ffi/include/sequoia/openpgp/types.h | 10 + openpgp-ffi/src/cert.rs | 54 +++-- openpgp-ffi/src/common.rs | 1 + openpgp-ffi/src/parse/stream.rs | 26 ++- openpgp-ffi/src/policy.rs | 36 +++ openpgp/examples/decrypt-with.rs | 10 +- openpgp/examples/encrypt-for.rs | 5 +- openpgp/examples/generate-encrypt-decrypt.rs | 27 ++- openpgp/examples/generate-sign-verify.rs | 17 +- openpgp/examples/notarize.rs | 4 +- openpgp/examples/pad.rs | 4 +- openpgp/examples/sign-detached.rs | 4 +- openpgp/examples/sign.rs | 4 +- openpgp/src/autocrypt.rs | 11 +- openpgp/src/cert/amalgamation.rs | 56 +++-- openpgp/src/cert/bindings.rs | 7 +- openpgp/src/cert/builder.rs | 46 ++-- openpgp/src/cert/component_iter.rs | 15 +- openpgp/src/cert/components.rs | 27 ++- openpgp/src/cert/key_amalgamation.rs | 52 +++-- openpgp/src/cert/keyiter.rs | 91 +++++--- openpgp/src/cert/mod.rs | 323 ++++++++++++++++----------- openpgp/src/cert/revoke.rs | 23 +- openpgp/src/lib.rs | 1 + openpgp/src/packet/signature/mod.rs | 7 +- openpgp/src/parse/stream.rs | 163 +++++++++----- openpgp/src/policy.rs | 82 +++++++ openpgp/src/serialize/cert.rs | 26 ++- openpgp/src/serialize/cert_armored.rs | 13 +- openpgp/src/serialize/stream.rs | 42 +++- openpgp/src/types/timestamp.rs | 8 +- sqv/src/sqv.rs | 5 +- tool/src/commands/decrypt.rs | 25 ++- tool/src/commands/inspect.rs | 33 +-- tool/src/commands/mod.rs | 20 +- tool/src/commands/sign.rs | 20 +- tool/src/sq.rs | 22 +- tool/tests/sq-sign.rs | 101 +++++---- 47 files changed, 1188 insertions(+), 553 deletions(-) create mode 100644 openpgp-ffi/src/policy.rs create mode 100644 openpgp/src/policy.rs diff --git a/examples/guide-exploring-openpgp.rs b/examples/guide-exploring-openpgp.rs index e70c6361..05a777e4 100644 --- a/examples/guide-exploring-openpgp.rs +++ b/examples/guide-exploring-openpgp.rs @@ -2,8 +2,11 @@ extern crate sequoia_openpgp as openpgp; use crate::openpgp::parse::Parse; +use crate::openpgp::policy::StandardPolicy as P; fn main() { + let p = &P::new(); + let cert = "-----BEGIN PGP PUBLIC KEY BLOCK----- @@ -52,7 +55,7 @@ fn main() { println!("Fingerprint: {}", cert.fingerprint()); // List userids. - for (i, ca) in cert.userids().policy(None).enumerate() { + for (i, ca) in cert.userids().set_policy(p, None).enumerate() { println!("{}: UID: {}, {} self-signature(s), {} certification(s)", i, ca.userid(), ca.binding().self_signatures().len(), @@ -60,7 +63,7 @@ fn main() { } // List subkeys. - for (i, ka) in cert.keys().policy(None).skip(1).enumerate() { + for (i, ka) in cert.keys().set_policy(p, None).skip(1).enumerate() { println!("{}: Fingerprint: {}, {} self-signature(s), {} certification(s)", i, ka.key().fingerprint(), ka.binding().self_signatures().len(), diff --git a/guide/src/chapter_01.md b/guide/src/chapter_01.md index 16020b6b..629515eb 100644 --- a/guide/src/chapter_01.md +++ b/guide/src/chapter_01.md @@ -17,20 +17,24 @@ extern crate sequoia_openpgp as openpgp; use openpgp::serialize::stream::*; use openpgp::packet::prelude::*; use openpgp::parse::stream::*; +use openpgp::policy::Policy; +use openpgp::policy::StandardPolicy as P; const MESSAGE: &'static str = "дружба"; fn main() { + let p = &P::new(); + // Generate a key. let key = generate().unwrap(); // Sign the message. let mut signed_message = Vec::new(); - sign(&mut signed_message, MESSAGE, &key).unwrap(); + sign(p, &mut signed_message, MESSAGE, &key).unwrap(); // Verify the message. let mut plaintext = Vec::new(); - verify(&mut plaintext, &signed_message, &key).unwrap(); + verify(p, &mut plaintext, &signed_message, &key).unwrap(); assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); } @@ -48,11 +52,14 @@ fn main() { # } # # /// Signs the given message. -# fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) -# -> openpgp::Result<()> { +# fn sign(policy: &dyn Policy, +# sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) +# -> openpgp::Result<()> +# { # // Get the keypair to do the signing from the Cert. -# let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). -# key().clone().mark_parts_secret().unwrap().into_keypair()?; +# let keypair = tsk.keys().set_policy(policy, None) +# .alive().revoked(false).for_signing().nth(0).unwrap() +# .key().clone().mark_parts_secret().unwrap().into_keypair()?; # # // Start streaming an OpenPGP message. # let message = Message::new(sink); @@ -74,7 +81,8 @@ fn main() { # } # # /// Verifies the given message. -# fn verify(sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) +# fn verify(policy: &dyn Policy, +# sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) # -> openpgp::Result<()> { # // Make a helper that that feeds the sender's public key to the # // verifier. @@ -83,7 +91,7 @@ fn main() { # }; # # // Now, create a verifier with a helper using the given Certs. -# let mut verifier = Verifier::from_bytes(signed_message, helper, None)?; +# let mut verifier = Verifier::from_bytes(policy, signed_message, helper, None)?; # # // Verify the data. # io::copy(&mut verifier, sink)?; @@ -161,22 +169,26 @@ create it: # extern crate failure; # extern crate sequoia_openpgp as openpgp; # use openpgp::serialize::stream::*; -# use openpgp::parse::stream::*; # use openpgp::packet::prelude::*; +# use openpgp::parse::stream::*; +# use openpgp::policy::Policy; +# use openpgp::policy::StandardPolicy as P; # # const MESSAGE: &'static str = "дружба"; # # fn main() { +# let p = &P::new(); +# # // Generate a key. # let key = generate().unwrap(); # # // Sign the message. # let mut signed_message = Vec::new(); -# sign(&mut signed_message, MESSAGE, &key).unwrap(); +# sign(p, &mut signed_message, MESSAGE, &key).unwrap(); # # // Verify the message. # let mut plaintext = Vec::new(); -# verify(&mut plaintext, &signed_message, &key).unwrap(); +# verify(p, &mut plaintext, &signed_message, &key).unwrap(); # # assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); # } @@ -194,11 +206,14 @@ fn generate() -> openpgp::Result { } # # /// Signs the given message. -# fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) -# -> openpgp::Result<()> { +# fn sign(policy: &dyn Policy, +# sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) +# -> openpgp::Result<()> +# { # // Get the keypair to do the signing from the Cert. -# let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). -# key().clone().mark_parts_secret().unwrap().into_keypair()?; +# let keypair = tsk.keys().set_policy(policy, None) +# .alive().revoked(false).for_signing().nth(0).unwrap() +# .key().clone().mark_parts_secret().unwrap().into_keypair()?; # # // Start streaming an OpenPGP message. # let message = Message::new(sink); @@ -220,7 +235,8 @@ fn generate() -> openpgp::Result { # } # # /// Verifies the given message. -# fn verify(sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) +# fn verify(policy: &dyn Policy, +# sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) # -> openpgp::Result<()> { # // Make a helper that that feeds the sender's public key to the # // verifier. @@ -229,7 +245,7 @@ fn generate() -> openpgp::Result { # }; # # // Now, create a verifier with a helper using the given Certs. -# let mut verifier = Verifier::from_bytes(signed_message, helper, None)?; +# let mut verifier = Verifier::from_bytes(policy, signed_message, helper, None)?; # # // Verify the data. # io::copy(&mut verifier, sink)?; @@ -309,20 +325,24 @@ implements [`io::Write`], and we simply write the plaintext to it. # use openpgp::serialize::stream::*; # use openpgp::packet::prelude::*; # use openpgp::parse::stream::*; +# use openpgp::policy::Policy; +# use openpgp::policy::StandardPolicy as P; # # const MESSAGE: &'static str = "дружба"; # # fn main() { +# let p = &P::new(); +# # // Generate a key. # let key = generate().unwrap(); # # // Sign the message. # let mut signed_message = Vec::new(); -# sign(&mut signed_message, MESSAGE, &key).unwrap(); +# sign(p, &mut signed_message, MESSAGE, &key).unwrap(); # # // Verify the message. # let mut plaintext = Vec::new(); -# verify(&mut plaintext, &signed_message, &key).unwrap(); +# verify(p, &mut plaintext, &signed_message, &key).unwrap(); # # assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); # } @@ -340,11 +360,14 @@ implements [`io::Write`], and we simply write the plaintext to it. # } # /// Signs the given message. -fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) - -> openpgp::Result<()> { +fn sign(policy: &dyn Policy, + sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) + -> openpgp::Result<()> +{ // Get the keypair to do the signing from the Cert. - let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). - key().clone().mark_parts_secret().unwrap().into_keypair()?; + let keypair = tsk.keys().set_policy(policy, None) + .alive().revoked(false).for_signing().nth(0).unwrap() + .key().clone().mark_parts_secret().unwrap().into_keypair()?; // Start streaming an OpenPGP message. let message = Message::new(sink); @@ -366,7 +389,8 @@ fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) } # # /// Verifies the given message. -# fn verify(sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) +# fn verify(policy: &dyn Policy, +# sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) # -> openpgp::Result<()> { # // Make a helper that that feeds the sender's public key to the # // verifier. @@ -375,7 +399,7 @@ fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) # }; # # // Now, create a verifier with a helper using the given Certs. -# let mut verifier = Verifier::from_bytes(signed_message, helper, None)?; +# let mut verifier = Verifier::from_bytes(policy, signed_message, helper, None)?; # # // Verify the data. # io::copy(&mut verifier, sink)?; @@ -466,20 +490,24 @@ Verified data can be read from this using [`io::Read`]. # use openpgp::serialize::stream::*; # use openpgp::packet::prelude::*; # use openpgp::parse::stream::*; +# use openpgp::policy::Policy; +# use openpgp::policy::StandardPolicy as P; # # const MESSAGE: &'static str = "дружба"; # # fn main() { +# let p = &P::new(); +# # // Generate a key. # let key = generate().unwrap(); # # // Sign the message. # let mut signed_message = Vec::new(); -# sign(&mut signed_message, MESSAGE, &key).unwrap(); +# sign(p, &mut signed_message, MESSAGE, &key).unwrap(); # # // Verify the message. # let mut plaintext = Vec::new(); -# verify(&mut plaintext, &signed_message, &key).unwrap(); +# verify(p, &mut plaintext, &signed_message, &key).unwrap(); # # assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); # } @@ -497,11 +525,14 @@ Verified data can be read from this using [`io::Read`]. # } # # /// Signs the given message. -# fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) -# -> openpgp::Result<()> { +# fn sign(policy: &dyn Policy, +# sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) +# -> openpgp::Result<()> +# { # // Get the keypair to do the signing from the Cert. -# let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). -# key().clone().mark_parts_secret().unwrap().into_keypair()?; +# let keypair = tsk.keys().set_policy(policy, None) +# .alive().revoked(false).for_signing().nth(0).unwrap() +# .key().clone().mark_parts_secret().unwrap().into_keypair()?; # # // Start streaming an OpenPGP message. # let message = Message::new(sink); @@ -523,7 +554,8 @@ Verified data can be read from this using [`io::Read`]. # } # /// Verifies the given message. -fn verify(sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) +fn verify(policy: &dyn Policy, + sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) -> openpgp::Result<()> { // Make a helper that that feeds the sender's public key to the // verifier. @@ -532,7 +564,7 @@ fn verify(sink: &mut Write, signed_message: &[u8], sender: &openpgp::Cert) }; // Now, create a verifier with a helper using the given Certs. - let mut verifier = Verifier::from_bytes(signed_message, helper, None)?; + let mut verifier = Verifier::from_bytes(policy, signed_message, helper, None)?; // Verify the data. io::copy(&mut verifier, sink)?; diff --git a/guide/src/chapter_02.md b/guide/src/chapter_02.md index 697f93cf..6f18c59c 100644 --- a/guide/src/chapter_02.md +++ b/guide/src/chapter_02.md @@ -16,20 +16,24 @@ use openpgp::crypto::SessionKey; use openpgp::types::SymmetricAlgorithm; use openpgp::serialize::stream::*; use openpgp::parse::stream::*; +use openpgp::policy::Policy; +use openpgp::policy::StandardPolicy as P; const MESSAGE: &'static str = "дружба"; fn main() { + let p = &P::new(); + // Generate a key. let key = generate().unwrap(); // Encrypt the message. let mut ciphertext = Vec::new(); - encrypt(&mut ciphertext, MESSAGE, &key).unwrap(); + encrypt(p, &mut ciphertext, MESSAGE, &key).unwrap(); // Decrypt the message. let mut plaintext = Vec::new(); - decrypt(&mut plaintext, &ciphertext, &key).unwrap(); + decrypt(p, &mut plaintext, &ciphertext, &key).unwrap(); assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); } @@ -47,11 +51,12 @@ fn main() { # } # # /// Encrypts the given message. -# fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) +# fn encrypt(policy: &dyn Policy, +# sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. # let mut recipients = -# recipient.keys().policy(None).alive().revoked(false) +# recipient.keys().set_policy(policy, None).alive().revoked(false) # .for_transport_encryption() # .map(|ka| ka.key().into()) # .collect::>(); @@ -81,16 +86,18 @@ fn main() { # } # # /// Decrypts the given message. -# fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) +# fn decrypt(policy: &dyn Policy, +# sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) # -> openpgp::Result<()> { # // Make a helper that that feeds the recipient's secret key to the # // decryptor. # let helper = Helper { +# policy: policy, # secret: recipient, # }; # # // Now, create a decryptor with a helper using the given Certs. -# let mut decryptor = Decryptor::from_bytes(ciphertext, helper, None)?; +# let mut decryptor = Decryptor::from_bytes(policy, ciphertext, helper, None)?; # # // Decrypt the data. # io::copy(&mut decryptor, sink)?; @@ -99,6 +106,7 @@ fn main() { # } # # struct Helper<'a> { +# policy: &'a dyn Policy, # secret: &'a openpgp::Cert, # } # @@ -125,7 +133,7 @@ fn main() { # where D: FnMut(SymmetricAlgorithm, &SessionKey) -> openpgp::Result<()> # { # // The encryption key is the first and only subkey. -# let key = self.secret.keys().policy(None) +# let key = self.secret.keys().set_policy(self.policy, None) # .for_transport_encryption().nth(0).unwrap().key().clone(); # # // The secret key is not encrypted. @@ -156,20 +164,24 @@ create it: # use openpgp::types::SymmetricAlgorithm; # use openpgp::serialize::stream::*; # use openpgp::parse::stream::*; +# use openpgp::policy::Policy; +# use openpgp::policy::StandardPolicy as P; # # const MESSAGE: &'static str = "дружба"; # # fn main() { +# let p = &P::new(); +# # // Generate a key. # let key = generate().unwrap(); # # // Encrypt the message. # let mut ciphertext = Vec::new(); -# encrypt(&mut ciphertext, MESSAGE, &key).unwrap(); +# encrypt(p, &mut ciphertext, MESSAGE, &key).unwrap(); # # // Decrypt the message. # let mut plaintext = Vec::new(); -# decrypt(&mut plaintext, &ciphertext, &key).unwrap(); +# decrypt(p, &mut plaintext, &ciphertext, &key).unwrap(); # # assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); # } @@ -187,11 +199,12 @@ fn generate() -> openpgp::Result { } # # /// Encrypts the given message. -# fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) +# fn encrypt(policy: &dyn Policy, +# sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. # let mut recipients = -# recipient.keys().policy(None).alive().revoked(false) +# recipient.keys().set_policy(policy, None).alive().revoked(false) # .for_transport_encryption() # .map(|ka| ka.key().into()) # .collect::>(); @@ -221,16 +234,18 @@ fn generate() -> openpgp::Result { # } # # /// Decrypts the given message. -# fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) +# fn decrypt(policy: &dyn Policy, +# sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) # -> openpgp::Result<()> { # // Make a helper that that feeds the recipient's secret key to the # // decryptor. # let helper = Helper { +# policy: policy, # secret: recipient, # }; # # // Now, create a decryptor with a helper using the given Certs. -# let mut decryptor = Decryptor::from_bytes(ciphertext, helper, None)?; +# let mut decryptor = Decryptor::from_bytes(policy, ciphertext, helper, None)?; # # // Decrypt the data. # io::copy(&mut decryptor, sink)?; @@ -239,6 +254,7 @@ fn generate() -> openpgp::Result { # } # # struct Helper<'a> { +# policy: &'a dyn Policy, # secret: &'a openpgp::Cert, # } # @@ -265,7 +281,7 @@ fn generate() -> openpgp::Result { # where D: FnMut(SymmetricAlgorithm, &SessionKey) -> openpgp::Result<()> # { # // The encryption key is the first and only subkey. -# let key = self.secret.keys().policy(None) +# let key = self.secret.keys().set_policy(self.policy, None) # .for_transport_encryption().nth(0).unwrap().key().clone(); # # // The secret key is not encrypted. @@ -296,20 +312,24 @@ implements [`io::Write`], and we simply write the plaintext to it. # use openpgp::types::SymmetricAlgorithm; # use openpgp::serialize::stream::*; # use openpgp::parse::stream::*; +# use openpgp::policy::Policy; +# use openpgp::policy::StandardPolicy as P; # # const MESSAGE: &'static str = "дружба"; # # fn main() { +# let p = &P::new(); +# # // Generate a key. # let key = generate().unwrap(); # # // Encrypt the message. # let mut ciphertext = Vec::new(); -# encrypt(&mut ciphertext, MESSAGE, &key).unwrap(); +# encrypt(p, &mut ciphertext, MESSAGE, &key).unwrap(); # # // Decrypt the message. # let mut plaintext = Vec::new(); -# decrypt(&mut plaintext, &ciphertext, &key).unwrap(); +# decrypt(p, &mut plaintext, &ciphertext, &key).unwrap(); # # assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); # } @@ -327,11 +347,12 @@ implements [`io::Write`], and we simply write the plaintext to it. # } # /// Encrypts the given message. -fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) +fn encrypt(policy: &dyn Policy, + sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) -> openpgp::Result<()> { // Build a vector of recipients to hand to Encryptor. let mut recipients = - recipient.keys().policy(None).alive().revoked(false) + recipient.keys().set_policy(policy, None).alive().revoked(false) .for_transport_encryption() .map(|ka| ka.key().into()) .collect::>(); @@ -361,16 +382,18 @@ fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) } # # /// Decrypts the given message. -# fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) +# fn decrypt(policy: &dyn Policy, +# sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) # -> openpgp::Result<()> { # // Make a helper that that feeds the recipient's secret key to the # // decryptor. # let helper = Helper { +# policy: policy, # secret: recipient, # }; # # // Now, create a decryptor with a helper using the given Certs. -# let mut decryptor = Decryptor::from_bytes(ciphertext, helper, None)?; +# let mut decryptor = Decryptor::from_bytes(policy, ciphertext, helper, None)?; # # // Decrypt the data. # io::copy(&mut decryptor, sink)?; @@ -379,6 +402,7 @@ fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) # } # # struct Helper<'a> { +# policy: &'a dyn Policy, # secret: &'a openpgp::Cert, # } # @@ -405,7 +429,7 @@ fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) # where D: FnMut(SymmetricAlgorithm, &SessionKey) -> openpgp::Result<()> # { # // The encryption key is the first and only subkey. -# let key = self.secret.keys().policy(None) +# let key = self.secret.keys().set_policy(self.policy, None) # .for_transport_encryption().nth(0).unwrap().key().clone(); # # // The secret key is not encrypted. @@ -450,20 +474,24 @@ Decrypted data can be read from this using [`io::Read`]. # use openpgp::types::SymmetricAlgorithm; # use openpgp::serialize::stream::*; # use openpgp::parse::stream::*; +# use openpgp::policy::Policy; +# use openpgp::policy::StandardPolicy as P; # # const MESSAGE: &'static str = "дружба"; # # fn main() { +# let p = &P::new(); +# # // Generate a key. # let key = generate().unwrap(); # # // Encrypt the message. # let mut ciphertext = Vec::new(); -# encrypt(&mut ciphertext, MESSAGE, &key).unwrap(); +# encrypt(p, &mut ciphertext, MESSAGE, &key).unwrap(); # # // Decrypt the message. # let mut plaintext = Vec::new(); -# decrypt(&mut plaintext, &ciphertext, &key).unwrap(); +# decrypt(p, &mut plaintext, &ciphertext, &key).unwrap(); # # assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); # } @@ -481,11 +509,12 @@ Decrypted data can be read from this using [`io::Read`]. # } # # /// Encrypts the given message. -# fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) +# fn encrypt(policy: &dyn Policy, +# sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. # let mut recipients = -# recipient.keys().policy(None).alive().revoked(false) +# recipient.keys().set_policy(policy, None).alive().revoked(false) # .for_transport_encryption() # .map(|ka| ka.key().into()) # .collect::>(); @@ -515,16 +544,18 @@ Decrypted data can be read from this using [`io::Read`]. # } # /// Decrypts the given message. -fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) +fn decrypt(policy: &dyn Policy, + sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) -> openpgp::Result<()> { // Make a helper that that feeds the recipient's secret key to the // decryptor. let helper = Helper { + policy: policy, secret: recipient, }; // Now, create a decryptor with a helper using the given Certs. - let mut decryptor = Decryptor::from_bytes(ciphertext, helper, None)?; + let mut decryptor = Decryptor::from_bytes(policy, ciphertext, helper, None)?; // Decrypt the data. io::copy(&mut decryptor, sink)?; @@ -533,6 +564,7 @@ fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::Cert) } struct Helper<'a> { + policy: &'a dyn Policy, secret: &'a openpgp::Cert, } @@ -558,7 +590,7 @@ impl<'a> DecryptionHelper for Helper<'a> { -> openpgp::Result> where D: FnMut(SymmetricAlgorithm, &SessionKey) -> openpgp::Result<()> { - let key = self.secret.keys().policy(None) + let key = self.secret.keys().set_policy(self.policy, None) .for_transport_encryption().nth(0).unwrap().key().clone(); // The secret key is not encrypted. diff --git a/ipc/examples/gpg-agent-decrypt.rs b/ipc/examples/gpg-agent-decrypt.rs index 69ba9d3b..0f0b3beb 100644 --- a/ipc/examples/gpg-agent-decrypt.rs +++ b/ipc/examples/gpg-agent-decrypt.rs @@ -21,9 +21,13 @@ use crate::openpgp::parse::{ MessageLayer, }, }; +use crate::openpgp::policy::Policy; +use crate::openpgp::policy::StandardPolicy as P; use crate::ipc::gnupg::{Context, KeyPair}; fn main() { + let p = &P::new(); + let matches = clap::App::new("gpg-agent-decrypt") .version(env!("CARGO_PKG_VERSION")) .about("Connects to gpg-agent and decrypts a message.") @@ -51,7 +55,7 @@ fn main() { // Now, create a decryptor with a helper using the given Certs. let mut decryptor = - Decryptor::from_reader(io::stdin(), Helper::new(&ctx, certs), None) + Decryptor::from_reader(p, io::stdin(), Helper::new(&ctx, p, certs), None) .unwrap(); // Finally, stream the decrypted data to stdout. @@ -70,11 +74,13 @@ struct Helper<'a> { impl<'a> Helper<'a> { /// Creates a Helper for the given Certs with appropriate secrets. - fn new(ctx: &'a Context, certs: Vec) -> Self { + fn new(ctx: &'a Context, policy: &'a dyn Policy, certs: Vec) + -> Self + { // Map (sub)KeyIDs to secrets. let mut keys = HashMap::new(); for cert in certs { - for ka in cert.keys().policy(None) + for ka in cert.keys().set_policy(policy, None) .for_storage_encryption().for_transport_encryption() { let key = ka.key(); diff --git a/ipc/examples/gpg-agent-sign.rs b/ipc/examples/gpg-agent-sign.rs index a80f3935..424f2a74 100644 --- a/ipc/examples/gpg-agent-sign.rs +++ b/ipc/examples/gpg-agent-sign.rs @@ -9,9 +9,12 @@ extern crate sequoia_ipc as ipc; use crate::openpgp::armor; use crate::openpgp::parse::Parse; use crate::openpgp::serialize::stream::{Message, LiteralWriter, Signer}; +use crate::openpgp::policy::StandardPolicy as P; use crate::ipc::gnupg::{Context, KeyPair}; fn main() { + let p = &P::new(); + let matches = clap::App::new("gpg-agent-sign") .version(env!("CARGO_PKG_VERSION")) .about("Connects to gpg-agent and creates a dummy signature.") @@ -39,7 +42,7 @@ fn main() { // Construct a KeyPair for every signing-capable (sub)key. let mut signers = certs.iter().flat_map(|cert| { - cert.keys().policy(None).alive().revoked(false).for_signing() + cert.keys().set_policy(p, None).alive().revoked(false).for_signing() .filter_map(|ka| { KeyPair::new(&ctx, ka.key()).ok() }) diff --git a/ipc/tests/gpg-agent.rs b/ipc/tests/gpg-agent.rs index 8cb3216f..e8a69d92 100644 --- a/ipc/tests/gpg-agent.rs +++ b/ipc/tests/gpg-agent.rs @@ -15,6 +15,7 @@ use crate::openpgp::crypto::SessionKey; use crate::openpgp::parse::stream::*; use crate::openpgp::serialize::{Serialize, stream::*}; use crate::openpgp::cert::{CertBuilder, CipherSuite}; +use crate::openpgp::policy::Policy; extern crate sequoia_ipc as ipc; use crate::ipc::gnupg::{Context, Agent, KeyPair}; @@ -80,6 +81,9 @@ fn gpg_import(ctx: &Context, what: &[u8]) { #[test] fn sign() { use self::CipherSuite::*; + use openpgp::policy::StandardPolicy as P; + + let p = &P::new(); let ctx = make_context!(); for cs in &[RSA2k, Cv25519, P521] { @@ -95,7 +99,7 @@ fn sign() { let keypair = KeyPair::new( &ctx, - cert.keys().policy(None).alive().revoked(false) + cert.keys().set_policy(p, None).alive().revoked(false) .for_signing().take(1).next().unwrap().key()) .unwrap(); @@ -128,7 +132,7 @@ fn sign() { // Now, create a verifier with a helper using the given Certs. let mut verifier = - Verifier::from_bytes(&message, helper, None).unwrap(); + Verifier::from_bytes(p, &message, helper, None).unwrap(); // Verify the data. let mut sink = Vec::new(); @@ -193,6 +197,9 @@ fn sign() { #[test] fn decrypt() { use self::CipherSuite::*; + use openpgp::policy::StandardPolicy as P; + + let p = &P::new(); let ctx = make_context!(); for cs in &[RSA2k, Cv25519, P521] { @@ -209,7 +216,7 @@ fn decrypt() { let mut message = Vec::new(); { let recipient = - cert.keys().policy(None).alive().revoked(false) + cert.keys().set_policy(p, None).alive().revoked(false) .for_transport_encryption() .map(|ka| ka.key().into()) .nth(0).unwrap(); @@ -235,10 +242,10 @@ fn decrypt() { // Make a helper that that feeds the recipient's secret key to the // decryptor. - let helper = Helper { ctx: &ctx, cert: &cert, }; + let helper = Helper { policy: p, ctx: &ctx, cert: &cert, }; // Now, create a decryptor with a helper using the given Certs. - let mut decryptor = Decryptor::from_bytes(&message, helper, None) + let mut decryptor = Decryptor::from_bytes(p, &message, helper, None) .unwrap(); // Decrypt the data. @@ -247,6 +254,7 @@ fn decrypt() { assert_eq!(MESSAGE.as_bytes(), &sink[..]); struct Helper<'a> { + policy: &'a Policy, ctx: &'a Context, cert: &'a openpgp::Cert, } @@ -276,7 +284,7 @@ fn decrypt() { { let mut keypair = KeyPair::new( self.ctx, - self.cert.keys().policy(None) + self.cert.keys().set_policy(self.policy, None) .for_storage_encryption().for_transport_encryption() .take(1).next().unwrap().key()) .unwrap(); diff --git a/openpgp-ffi/examples/decrypt-with.c b/openpgp-ffi/examples/decrypt-with.c index 3f98c574..e288efbf 100644 --- a/openpgp-ffi/examples/decrypt-with.c +++ b/openpgp-ffi/examples/decrypt-with.c @@ -203,6 +203,7 @@ main (int argc, char **argv) pgp_reader_t plaintext; uint8_t buf[1024]; ssize_t nread; + pgp_policy_t policy = pgp_standard_policy (); if (argc != 2) error (1, 0, "Usage: %s plain", argv[0]); @@ -218,7 +219,7 @@ main (int argc, char **argv) .key = cert, .decrypt_called = 0, }; - plaintext = pgp_decryptor_new (&err, source, + plaintext = pgp_decryptor_new (&err, policy, source, get_public_keys_cb, decrypt_cb, check_cb, NULL, &cookie, 0); if (! plaintext) @@ -233,5 +234,6 @@ main (int argc, char **argv) pgp_reader_free (plaintext); pgp_reader_free (source); pgp_cert_free (cert); + pgp_policy_free (policy); return 0; } diff --git a/openpgp-ffi/examples/encrypt-for.c b/openpgp-ffi/examples/encrypt-for.c index aeb4dea4..27a7a585 100644 --- a/openpgp-ffi/examples/encrypt-for.c +++ b/openpgp-ffi/examples/encrypt-for.c @@ -28,6 +28,7 @@ main (int argc, char **argv) pgp_cert_t cert; pgp_writer_t sink; pgp_writer_stack_t writer = NULL; + pgp_policy_t policy = pgp_standard_policy (); if (argc != 2) error (1, 0, "Usage: %s cipher", argv[0]); @@ -36,7 +37,7 @@ main (int argc, char **argv) if (cert == NULL) error (1, 0, "pgp_cert_from_file: %s", pgp_error_to_string (err)); - pgp_cert_valid_key_iter_t iter = pgp_cert_valid_key_iter (cert, 0); + pgp_cert_valid_key_iter_t iter = pgp_cert_valid_key_iter (cert, policy, 0); pgp_cert_valid_key_iter_alive (iter); pgp_cert_valid_key_iter_revoked (iter, false); pgp_cert_valid_key_iter_for_storage_encryption (iter); @@ -91,5 +92,6 @@ main (int argc, char **argv) pgp_recipient_free (recipients[i]); free (recipients); pgp_cert_free (cert); + pgp_policy_free (policy); return 0; } diff --git a/openpgp-ffi/include/sequoia/openpgp.h b/openpgp-ffi/include/sequoia/openpgp.h index 405cd2c6..d15749d9 100644 --- a/openpgp-ffi/include/sequoia/openpgp.h +++ b/openpgp-ffi/include/sequoia/openpgp.h @@ -590,7 +590,8 @@ char *pgp_user_id_binding_user_id (pgp_user_id_binding_t binding); /*/ /// Returns a reference to the self-signature, if any. /*/ -pgp_signature_t pgp_user_id_binding_selfsig(pgp_user_id_binding_t binding); +pgp_signature_t pgp_user_id_binding_selfsig(pgp_user_id_binding_t binding, + pgp_policy_t policy); /* openpgp::cert::UserIDBindingIter. */ @@ -628,7 +629,7 @@ void pgp_cert_key_iter_unencrypted_secret (pgp_cert_key_iter_t iter); /// Note: you may not call this function after starting to iterate. /*/ pgp_cert_valid_key_iter_t pgp_cert_key_iter_policy - (pgp_cert_key_iter_t iter, time_t when); + (pgp_cert_key_iter_t iter, pgp_policy_t policy, time_t when); /*/ /// Returns a reference to the next key. Returns NULL if there are no @@ -703,15 +704,14 @@ void pgp_cert_valid_key_iter_for_transport_encryption (pgp_cert_valid_key_iter_t void pgp_cert_valid_key_iter_alive (pgp_cert_valid_key_iter_t iter); /*/ -/// Changes the iterator to only return keys whose revocation status -/// matches `revoked`. +/// Changes the iterator to only return keys that are revoked. /// /// Note: you may not call this function after starting to iterate. /*/ void pgp_cert_valid_key_iter_revoked (pgp_cert_valid_key_iter_t iter, bool revoked); /*/ -/// Changes the iterator to only return keys that have secret keys. +/// Changes the iterator to only return keys that are not revoked. /// /// Note: you may not call this function after starting to iterate. /*/ @@ -877,7 +877,8 @@ pgp_key_t pgp_cert_primary_key (pgp_cert_t cert); /// If `when` is 0, then returns the Cert's revocation status as of the /// time of the call. /*/ -pgp_revocation_status_t pgp_cert_revoked (pgp_cert_t cert, time_t when); +pgp_revocation_status_t pgp_cert_revoked (pgp_cert_t cert, + pgp_policy_t policy, time_t when); /*/ /// Writes a revocation certificate to the writer. @@ -906,7 +907,8 @@ pgp_cert_t pgp_cert_revoke_in_place (pgp_error_t *errp, /// /// If `when` is 0, then the current time is used. /*/ -pgp_status_t pgp_cert_alive(pgp_error_t *errp, pgp_cert_t cert, time_t when); +pgp_status_t pgp_cert_alive(pgp_error_t *errp, pgp_cert_t cert, + pgp_policy_t policy, time_t when); /*/ /// Changes the Cert's expiration. @@ -917,9 +919,10 @@ pgp_status_t pgp_cert_alive(pgp_error_t *errp, pgp_cert_t cert, time_t when); /// This function consumes `cert` and returns a new `Cert`. /*/ pgp_cert_t pgp_cert_set_expiry(pgp_error_t *errp, - pgp_cert_t cert, - pgp_signer_t signer, - uint32_t expiry); + pgp_cert_t cert, + pgp_policy_t policy, + pgp_signer_t signer, + uint32_t expiry); /*/ /// Returns whether the Cert includes any secret key material. @@ -946,12 +949,13 @@ pgp_cert_key_iter_t pgp_cert_key_iter (pgp_cert_t cert); /// subkeys that are valid (i.e., have a self-signature at time /// `when`). /*/ -pgp_cert_valid_key_iter_t pgp_cert_valid_key_iter (pgp_cert_t cert, time_t when); +pgp_cert_valid_key_iter_t pgp_cert_valid_key_iter + (pgp_cert_t cert, pgp_policy_t policy, time_t when); /*/ /// Returns the Cert's primary user id (if any). /*/ -char *pgp_cert_primary_user_id(pgp_cert_t cert); +char *pgp_cert_primary_user_id(pgp_cert_t cert, pgp_policy_t policy); /*/ /// Returns a CertParser. @@ -1740,7 +1744,9 @@ bool pgp_verification_result_error (pgp_verification_result_t, /// /// Note: all of the parameters are required; none may be NULL. /*/ -pgp_reader_t pgp_decryptor_new (pgp_error_t *errp, pgp_reader_t input, +pgp_reader_t pgp_decryptor_new (pgp_error_t *errp, + pgp_policy_t policy, + pgp_reader_t input, pgp_decryptor_get_public_keys_cb_t get_public_keys, pgp_decryptor_decrypt_cb_t decrypt, pgp_decryptor_check_cb_t check, @@ -1753,18 +1759,64 @@ pgp_reader_t pgp_decryptor_new (pgp_error_t *errp, pgp_reader_t input, /// No attempt is made to decrypt any encryption packets. These are /// treated as opaque containers. /*/ -pgp_reader_t pgp_verifier_new (pgp_error_t *errp, pgp_reader_t input, +pgp_reader_t pgp_verifier_new (pgp_error_t *errp, + pgp_policy_t policy, + pgp_reader_t input, pgp_decryptor_get_public_keys_cb_t get_public_keys, pgp_decryptor_check_cb_t check, void *cookie, time_t time); /*/ -/// Verifies a detached OpenPGP signature. +/// Verifies a detached OpenPGP signature./// +/// A Certificate (see [RFC 4880, section 11.1]) can be used to verify +/// signatures and encrypt data. It can be stored in a keystore and +/// uploaded to keyservers. +/// +/// [RFC 4880, section 11.1]: https://tools.ietf.org/html/rfc4880#section-11.1 + /*/ pgp_reader_t pgp_detached_verifier_new (pgp_error_t *errp, + pgp_policy_t policy, pgp_reader_t signature_input, pgp_reader_t input, pgp_decryptor_get_public_keys_cb_t get_public_keys, pgp_decryptor_check_cb_t check, void *cookie, time_t time); +/*/ +/// Returns a new standard policy. +/*/ +pgp_policy_t pgp_standard_policy (); + +/*/ +/// Clones the object. +/*/ +pgp_policy_t pgp_standard_policy_clone (pgp_standard_policy_t); + +/*/ +/// Frees this object. +/*/ +void pgp_standard_policy_free (pgp_standard_policy_t); + +/*/ +/// Returns a human readable description of this object suitable for +/// debugging. +/*/ +char *pgp_standard_policy_debug (const pgp_standard_policy_t); + +/*/ +/// Clones the object. +/*/ +pgp_policy_t pgp_policy_clone (pgp_policy_t); + +/*/ +/// Frees this object. +/*/ +void pgp_policy_free (pgp_policy_t); + +/*/ +/// Returns a human readable description of this object suitable for +/// debugging. +/*/ +char *pgp_policy_debug (const pgp_policy_t); + #endif diff --git a/openpgp-ffi/include/sequoia/openpgp/types.h b/openpgp-ffi/include/sequoia/openpgp/types.h index e9bbc1b7..7a8eb83a 100644 --- a/openpgp-ffi/include/sequoia/openpgp/types.h +++ b/openpgp-ffi/include/sequoia/openpgp/types.h @@ -520,4 +520,14 @@ typedef pgp_status_t (*pgp_decryptor_check_cb_t) (void *, typedef pgp_status_t (*pgp_decryptor_inspect_cb_t) (void *, pgp_packet_parser_t); +/*/ +/// An OpenPGP policy. +/*/ +typedef struct pgp_policy *pgp_policy_t; + +/*/ +/// A standard OpenPGP policy. +/*/ +typedef struct pgp_standard_policy *pgp_standard_policy_t; + #endif diff --git a/openpgp-ffi/src/cert.rs b/openpgp-ffi/src/cert.rs index 65c56f9f..e2a58c03 100644 --- a/openpgp-ffi/src/cert.rs +++ b/openpgp-ffi/src/cert.rs @@ -41,6 +41,7 @@ use super::packet::signature::Signature; use super::packet_pile::PacketPile; use super::tsk::TSK; use super::revocation_status::RevocationStatus; +use super::policy::Policy; use crate::Maybe; use crate::RefRaw; @@ -168,10 +169,13 @@ fn pgp_cert_primary_key(cert: *const Cert) -> *const Key { /// If `when` is 0, then returns the Cert's revocation status as of the /// time of the call. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn pgp_cert_revoked(cert: *const Cert, when: time_t) +fn pgp_cert_revoked(cert: *const Cert, policy: *const Policy, when: time_t) -> *mut RevocationStatus<'static> { - cert.ref_raw().revoked(maybe_time(when)).move_into_raw() + let policy = &**policy.ref_raw(); + cert.ref_raw() + .revoked(policy, maybe_time(when)) + .move_into_raw() } fn int_to_reason_for_revocation(code: c_int) -> ReasonForRevocation { @@ -203,6 +207,7 @@ fn int_to_reason_for_revocation(code: c_int) -> ReasonForRevocation { /// pgp_key_t primary_key; /// pgp_key_pair_t primary_keypair; /// pgp_signer_t primary_signer; +/// pgp_policy_t policy = pgp_standard_policy (); /// /// builder = pgp_cert_builder_new (); /// pgp_cert_builder_set_cipher_suite (&builder, PGP_CERT_CIPHER_SUITE_CV25519); @@ -227,11 +232,12 @@ fn int_to_reason_for_revocation(code: c_int) -> ReasonForRevocation { /// cert = pgp_cert_merge_packets (NULL, cert, &packet, 1); /// assert (cert); /// -/// pgp_revocation_status_t rs = pgp_cert_revoked (cert, 0); +/// pgp_revocation_status_t rs = pgp_cert_revoked (cert, policy, 0); /// assert (pgp_revocation_status_variant (rs) == PGP_REVOCATION_STATUS_REVOKED); /// pgp_revocation_status_free (rs); /// /// pgp_cert_free (cert); +/// pgp_policy_free (policy); /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_cert_revoke(errp: Option<&mut *mut crate::error::Error>, @@ -273,6 +279,7 @@ fn pgp_cert_revoke(errp: Option<&mut *mut crate::error::Error>, /// pgp_key_t primary_key; /// pgp_key_pair_t primary_keypair; /// pgp_signer_t primary_signer; +/// pgp_policy_t policy = pgp_standard_policy (); /// /// builder = pgp_cert_builder_new (); /// pgp_cert_builder_set_cipher_suite (&builder, PGP_CERT_CIPHER_SUITE_CV25519); @@ -293,11 +300,12 @@ fn pgp_cert_revoke(errp: Option<&mut *mut crate::error::Error>, /// pgp_signer_free (primary_signer); /// pgp_key_pair_free (primary_keypair); /// -/// pgp_revocation_status_t rs = pgp_cert_revoked (cert, 0); +/// pgp_revocation_status_t rs = pgp_cert_revoked (cert, policy, 0); /// assert (pgp_revocation_status_variant (rs) == PGP_REVOCATION_STATUS_REVOKED); /// pgp_revocation_status_free (rs); /// /// pgp_cert_free (cert); +/// pgp_policy_free (policy); /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_cert_revoke_in_place(errp: Option<&mut *mut crate::error::Error>, @@ -324,9 +332,12 @@ fn pgp_cert_revoke_in_place(errp: Option<&mut *mut crate::error::Error>, /// If `when` is 0, then the current time is used. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_cert_alive(errp: Option<&mut *mut crate::error::Error>, - cert: *const Cert, when: time_t) -> Status { + cert: *const Cert, policy: *const Policy, when: time_t) + -> Status +{ + let policy = &**policy.ref_raw(); ffi_make_fry_from_errp!(errp); - ffi_try_status!(cert.ref_raw().alive(maybe_time(when))) + ffi_try_status!(cert.ref_raw().alive(policy, maybe_time(when))) } /// Changes the Cert's expiration. @@ -338,14 +349,17 @@ fn pgp_cert_alive(errp: Option<&mut *mut crate::error::Error>, #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_cert_set_expiry(errp: Option<&mut *mut crate::error::Error>, cert: *mut Cert, + policy: *const Policy, primary_signer: *mut Box, expiry: u32) - -> Maybe { + -> Maybe +{ + let policy = &**policy.ref_raw(); let cert = cert.move_from_raw(); let signer = ffi_param_ref_mut!(primary_signer); - cert.set_expiry(signer.as_mut(), - Some(std::time::Duration::new(expiry as u64, 0))) + cert.set_expiry(policy, signer.as_mut(), + Some(std::time::Duration::new(expiry as u64, 0))) .move_into_raw(errp) } @@ -359,11 +373,12 @@ fn pgp_cert_is_tsk(cert: *const Cert) /// Returns an iterator over the Cert's user id bindings. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn pgp_cert_primary_user_id(cert: *const Cert) +fn pgp_cert_primary_user_id(cert: *const Cert, policy: *const Policy) -> *mut c_char { let cert = cert.ref_raw(); - if let Some(binding) = cert.primary_userid(None) { + let policy = &**policy.ref_raw(); + if let Some(binding) = cert.primary_userid(policy, None) { ffi_return_string!(binding.userid().value()) } else { ptr::null_mut() @@ -392,11 +407,13 @@ pub extern "C" fn pgp_user_id_binding_user_id( /// Returns a reference to the self-signature, if any. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_user_id_binding_selfsig( - binding: *const UserIDBinding) + binding: *const UserIDBinding, + policy: *const Policy) -> Maybe { let binding = ffi_param_ref!(binding); - binding.binding_signature(None).move_into_raw() + let policy = &**policy.ref_raw(); + binding.binding_signature(policy, None).move_into_raw() } @@ -505,9 +522,11 @@ pub extern "C" fn pgp_cert_key_iter_unencrypted_secret<'a>( #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_cert_key_iter_policy<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, + policy: *const Policy, when: time_t) -> *mut ValidKeyIterWrapper<'static> { + let policy = policy.ref_raw(); let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); @@ -517,7 +536,9 @@ pub extern "C" fn pgp_cert_key_iter_policy<'a>( let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); box_raw!(ValidKeyIterWrapper { - iter: unsafe { std::mem::transmute(tmp.policy(maybe_time(when))) }, + iter: unsafe { + std::mem::transmute(tmp.set_policy(&**policy, maybe_time(when))) + }, next_called: false, }) } @@ -561,7 +582,8 @@ pub struct ValidKeyIterWrapper<'a> { /// subkeys that are valid (i.e., have a self-signature at time /// `when`). #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_cert_valid_key_iter(cert: *const Cert, when: time_t) +pub extern "C" fn pgp_cert_valid_key_iter(cert: *const Cert, + policy: *const Policy, when: time_t) -> *mut ValidKeyIterWrapper<'static> { let cert = cert.ref_raw(); @@ -570,7 +592,7 @@ pub extern "C" fn pgp_cert_valid_key_iter(cert: *const Cert, when: time_t) next_called: false, }); - pgp_cert_key_iter_policy(iter, when) + pgp_cert_key_iter_policy(iter, policy, when) } /// Frees a pgp_cert_key_iter_t. diff --git a/openpgp-ffi/src/common.rs b/openpgp-ffi/src/common.rs index c22e5c9e..592c4776 100644 --- a/openpgp-ffi/src/common.rs +++ b/openpgp-ffi/src/common.rs @@ -342,3 +342,4 @@ pub mod serialize; pub mod cert; pub mod tsk; pub mod revocation_status; +pub mod policy; diff --git a/openpgp-ffi/src/parse/stream.rs b/openpgp-ffi/src/parse/stream.rs index e0a5e7c4..0fb0bec9 100644 --- a/openpgp-ffi/src/parse/stream.rs +++ b/openpgp-ffi/src/parse/stream.rs @@ -50,6 +50,7 @@ use super::super::{ packet::signature::Signature, packet::key::Key, parse::PacketParser, + policy::Policy, revocation_status::RevocationStatus, }; @@ -509,6 +510,7 @@ impl VerificationHelper for VHelper { /// pgp_reader_t plaintext; /// uint8_t buf[128]; /// ssize_t nread; +/// pgp_policy_t policy = pgp_standard_policy (); /// /// cert = pgp_cert_from_file (NULL, "../openpgp/tests/data/keys/testy.pgp"); /// assert(cert); @@ -520,7 +522,7 @@ impl VerificationHelper for VHelper { /// struct verify_cookie cookie = { /// .key = cert, /* Move. */ /// }; -/// plaintext = pgp_verifier_new (NULL, source, +/// plaintext = pgp_verifier_new (NULL, policy, source, /// get_public_keys_cb, check_cb, /// &cookie, 1554542219); /// assert (source); @@ -532,11 +534,13 @@ impl VerificationHelper for VHelper { /// /// pgp_reader_free (plaintext); /// pgp_reader_free (source); +/// pgp_policy_free (policy); /// return 0; /// } /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, + policy: *const Policy, input: *mut io::Reader, get_public_keys: GetPublicKeysCallback, check: CheckCallback, @@ -544,9 +548,10 @@ fn pgp_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, time: time_t) -> Maybe { + let policy = policy.ref_raw().as_ref(); let helper = VHelper::new(get_public_keys, check, cookie); - Verifier::from_reader(input.ref_mut_raw(), helper, maybe_time(time)) + Verifier::from_reader(policy, input.ref_mut_raw(), helper, maybe_time(time)) .map(|r| io::ReaderKind::Generic(Box::new(r))) .move_into_raw(errp) } @@ -620,6 +625,7 @@ fn pgp_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, /// pgp_reader_t plaintext; /// uint8_t buf[128]; /// ssize_t nread; +/// pgp_policy_t policy = pgp_standard_policy (); /// /// cert = pgp_cert_from_file (NULL, /// "../openpgp/tests/data/keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"); @@ -637,7 +643,7 @@ fn pgp_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, /// struct verify_cookie cookie = { /// .key = cert, /* Move. */ /// }; -/// plaintext = pgp_detached_verifier_new (NULL, signature, source, +/// plaintext = pgp_detached_verifier_new (NULL, policy, signature, source, /// get_public_keys_cb, check_cb, /// &cookie, 1554542219); /// assert (source); @@ -650,11 +656,13 @@ fn pgp_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, /// pgp_reader_free (plaintext); /// pgp_reader_free (source); /// pgp_reader_free (signature); +/// pgp_policy_free (policy); /// return 0; /// } /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_detached_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, + policy: *const Policy, signature_input: *mut io::Reader, input: *mut io::Reader, get_public_keys: GetPublicKeysCallback, @@ -663,9 +671,11 @@ fn pgp_detached_verifier_new<'a>(errp: Option<&mut *mut crate::error::Error>, time: time_t) -> Maybe { + let policy = policy.ref_raw().as_ref(); + let helper = VHelper::new(get_public_keys, check, cookie); - DetachedVerifier::from_reader(signature_input.ref_mut_raw(), + DetachedVerifier::from_reader(policy, signature_input.ref_mut_raw(), input.ref_mut_raw(), helper, maybe_time(time)) .map(|r| io::ReaderKind::Generic(Box::new(r))) .move_into_raw(errp) @@ -897,6 +907,7 @@ impl DecryptionHelper for DHelper { /// pgp_reader_t plaintext; /// uint8_t buf[128]; /// ssize_t nread; +/// pgp_policy_t policy = pgp_standard_policy (); /// /// cert = pgp_cert_from_file ( /// NULL, "../openpgp/tests/data/keys/testy-private.pgp"); @@ -910,7 +921,7 @@ impl DecryptionHelper for DHelper { /// .key = cert, /// .decrypt_called = 0, /// }; -/// plaintext = pgp_decryptor_new (NULL, source, +/// plaintext = pgp_decryptor_new (NULL, policy, source, /// get_public_keys_cb, decrypt_cb, /// check_cb, NULL, &cookie, 1554542219); /// assert (plaintext); @@ -923,11 +934,13 @@ impl DecryptionHelper for DHelper { /// pgp_reader_free (plaintext); /// pgp_reader_free (source); /// pgp_cert_free (cert); +/// pgp_policy_free (policy); /// return 0; /// } /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_decryptor_new<'a>(errp: Option<&mut *mut crate::error::Error>, + policy: *const Policy, input: *mut io::Reader, get_public_keys: GetPublicKeysCallback, decrypt: DecryptCallback, @@ -937,10 +950,11 @@ fn pgp_decryptor_new<'a>(errp: Option<&mut *mut crate::error::Error>, time: time_t) -> Maybe { + let policy = policy.ref_raw().as_ref(); let helper = DHelper::new( get_public_keys, decrypt, check, inspect, cookie); - Decryptor::from_reader(input.ref_mut_raw(), helper, maybe_time(time)) + Decryptor::from_reader(policy, input.ref_mut_raw(), helper, maybe_time(time)) .map(|r| io::ReaderKind::Generic(Box::new(r))) .move_into_raw(errp) } diff --git a/openpgp-ffi/src/policy.rs b/openpgp-ffi/src/policy.rs new file mode 100644 index 00000000..2c00ae52 --- /dev/null +++ b/openpgp-ffi/src/policy.rs @@ -0,0 +1,36 @@ +//! Policy objects. +//! +//! This module allows the caller to specify low-level policy like +//! what algorithms are allowed. +//! +//! Wraps the policy object functions, see +//! [`sequoia-openpgp::policy`]. +//! +//! [`sequoia-openpgp::policy`]: ../../sequoia_openpgp/policy/index.html + +extern crate sequoia_openpgp as openpgp; + +use crate::MoveIntoRaw; + +use self::openpgp::policy; + +/// A policy object. +#[crate::ffi_wrapper_type( + prefix = "pgp_", + derive = "Clone, Debug")] +pub struct Policy(Box); + +/// A StandardPolicy object. +#[crate::ffi_wrapper_type( + prefix = "pgp_", + derive = "Clone, Debug")] +pub struct StandardPolicy(policy::StandardPolicy); + +/// Returns a new standard policy. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] +pub extern "C" fn pgp_standard_policy() + -> *mut Policy +{ + let p : Box = Box::new(policy::StandardPolicy::new()); + p.move_into_raw() +} diff --git a/openpgp/examples/decrypt-with.rs b/openpgp/examples/decrypt-with.rs index 3f470f0f..b52c143c 100644 --- a/openpgp/examples/decrypt-with.rs +++ b/openpgp/examples/decrypt-with.rs @@ -21,8 +21,12 @@ use crate::openpgp::parse::{ MessageLayer, }, }; +use crate::openpgp::policy::Policy; +use crate::openpgp::policy::StandardPolicy as P; pub fn main() { + let p = &P::new(); + let args: Vec = env::args().collect(); if args.len() < 2 { panic!("A simple decryption filter.\n\n\ @@ -38,7 +42,7 @@ pub fn main() { // Now, create a decryptor with a helper using the given Certs. let mut decryptor = - Decryptor::from_reader(io::stdin(), Helper::new(certs), None).unwrap(); + Decryptor::from_reader(p, io::stdin(), Helper::new(p, certs), None).unwrap(); // Finally, stream the decrypted data to stdout. io::copy(&mut decryptor, &mut io::stdout()) @@ -54,11 +58,11 @@ struct Helper { impl Helper { /// Creates a Helper for the given Certs with appropriate secrets. - fn new(certs: Vec) -> Self { + fn new(p: &dyn Policy, certs: Vec) -> Self { // Map (sub)KeyIDs to secrets. let mut keys = HashMap::new(); for cert in certs { - for ka in cert.keys().policy(None) + for ka in cert.keys().set_policy(p, None) .for_storage_encryption().for_transport_encryption() { // This only works for unencrypted secret keys. diff --git a/openpgp/examples/encrypt-for.rs b/openpgp/examples/encrypt-for.rs index 63e0e071..b64165b7 100644 --- a/openpgp/examples/encrypt-for.rs +++ b/openpgp/examples/encrypt-for.rs @@ -11,8 +11,11 @@ use crate::openpgp::parse::Parse; use crate::openpgp::serialize::stream::{ Message, LiteralWriter, Encryptor, }; +use crate::openpgp::policy::StandardPolicy as P; fn main() { + let p = &P::new(); + let args: Vec = env::args().collect(); if args.len() < 3 { panic!("A simple encryption filter.\n\n\ @@ -39,7 +42,7 @@ fn main() { certs.iter() .flat_map(|cert| { cert.keys() - .policy(None).alive().revoked(false).key_flags(&mode) + .set_policy(p, None).alive().revoked(false).key_flags(&mode) }) .map(|ka| ka.key().into()) .collect::>(); diff --git a/openpgp/examples/generate-encrypt-decrypt.rs b/openpgp/examples/generate-encrypt-decrypt.rs index 0e109ccd..8258aaf4 100644 --- a/openpgp/examples/generate-encrypt-decrypt.rs +++ b/openpgp/examples/generate-encrypt-decrypt.rs @@ -7,20 +7,24 @@ use crate::openpgp::crypto::SessionKey; use crate::openpgp::types::SymmetricAlgorithm; use crate::openpgp::serialize::stream::*; use crate::openpgp::parse::stream::*; +use crate::openpgp::policy::Policy; +use crate::openpgp::policy::StandardPolicy as P; const MESSAGE: &'static str = "дружба"; fn main() { + let p = &P::new(); + // Generate a key. let key = generate().unwrap(); // Encrypt the message. let mut ciphertext = Vec::new(); - encrypt(&mut ciphertext, MESSAGE, &key).unwrap(); + encrypt(p, &mut ciphertext, MESSAGE, &key).unwrap(); // Decrypt the message. let mut plaintext = Vec::new(); - decrypt(&mut plaintext, &ciphertext, &key).unwrap(); + decrypt(p, &mut plaintext, &ciphertext, &key).unwrap(); assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); } @@ -38,11 +42,13 @@ fn generate() -> openpgp::Result { } /// Encrypts the given message. -fn encrypt(sink: &mut dyn Write, plaintext: &str, recipient: &openpgp::Cert) - -> openpgp::Result<()> { +fn encrypt(p: &dyn Policy, sink: &mut dyn Write, plaintext: &str, + recipient: &openpgp::Cert) + -> openpgp::Result<()> +{ // Build a vector of recipients to hand to Encryptor. - let mut recipients = recipient - .keys().policy(None).alive().revoked(false) + let mut recipients = + recipient.keys().set_policy(p, None).alive().revoked(false) .for_transport_encryption() .map(|ka| ka.key().into()) .collect::>(); @@ -72,16 +78,18 @@ fn encrypt(sink: &mut dyn Write, plaintext: &str, recipient: &openpgp::Cert) } /// Decrypts the given message. -fn decrypt(sink: &mut dyn Write, ciphertext: &[u8], recipient: &openpgp::Cert) +fn decrypt(p: &dyn Policy, + sink: &mut dyn Write, ciphertext: &[u8], recipient: &openpgp::Cert) -> openpgp::Result<()> { // Make a helper that that feeds the recipient's secret key to the // decryptor. let helper = Helper { secret: recipient, + policy: p, }; // Now, create a decryptor with a helper using the given Certs. - let mut decryptor = Decryptor::from_bytes(ciphertext, helper, None)?; + let mut decryptor = Decryptor::from_bytes(p, ciphertext, helper, None)?; // Decrypt the data. io::copy(&mut decryptor, sink)?; @@ -91,6 +99,7 @@ fn decrypt(sink: &mut dyn Write, ciphertext: &[u8], recipient: &openpgp::Cert) struct Helper<'a> { secret: &'a openpgp::Cert, + policy: &'a Policy, } impl<'a> VerificationHelper for Helper<'a> { @@ -115,7 +124,7 @@ impl<'a> DecryptionHelper for Helper<'a> { -> openpgp::Result> where D: FnMut(SymmetricAlgorithm, &SessionKey) -> openpgp::Result<()> { - let key = self.secret.keys().policy(None) + let key = self.secret.keys().set_policy(self.policy, None) .for_transport_encryption().nth(0).unwrap().key().clone(); // The secret key is not encrypted. diff --git a/openpgp/examples/generate-sign-verify.rs b/openpgp/examples/generate-sign-verify.rs index 8df9f1cf..e3142667 100644 --- a/openpgp/examples/generate-sign-verify.rs +++ b/openpgp/examples/generate-sign-verify.rs @@ -6,20 +6,24 @@ extern crate failure; extern crate sequoia_openpgp as openpgp; use crate::openpgp::serialize::stream::*; use crate::openpgp::parse::stream::*; +use crate::openpgp::policy::Policy; +use crate::openpgp::policy::StandardPolicy as P; const MESSAGE: &'static str = "дружба"; fn main() { + let p = &P::new(); + // Generate a key. let key = generate().unwrap(); // Sign the message. let mut signed_message = Vec::new(); - sign(&mut signed_message, MESSAGE, &key).unwrap(); + sign(p, &mut signed_message, MESSAGE, &key).unwrap(); // Verify the message. let mut plaintext = Vec::new(); - verify(&mut plaintext, &signed_message, &key).unwrap(); + verify(p, &mut plaintext, &signed_message, &key).unwrap(); assert_eq!(MESSAGE.as_bytes(), &plaintext[..]); } @@ -37,11 +41,11 @@ fn generate() -> openpgp::Result { } /// Signs the given message. -fn sign(sink: &mut dyn Write, plaintext: &str, tsk: &openpgp::Cert) +fn sign(p: &dyn Policy, sink: &mut dyn Write, plaintext: &str, tsk: &openpgp::Cert) -> openpgp::Result<()> { // Get the keypair to do the signing from the Cert. let keypair = tsk - .keys().policy(None).alive().revoked(false).for_signing() + .keys().set_policy(p, None).alive().revoked(false).for_signing() .nth(0).unwrap() .key().clone().mark_parts_secret().unwrap().into_keypair()?; @@ -65,7 +69,8 @@ fn sign(sink: &mut dyn Write, plaintext: &str, tsk: &openpgp::Cert) } /// Verifies the given message. -fn verify(sink: &mut dyn Write, signed_message: &[u8], sender: &openpgp::Cert) +fn verify(p: &dyn Policy, sink: &mut dyn Write, + signed_message: &[u8], sender: &openpgp::Cert) -> openpgp::Result<()> { // Make a helper that that feeds the sender's public key to the // verifier. @@ -74,7 +79,7 @@ fn verify(sink: &mut dyn Write, signed_message: &[u8], sender: &openpgp::Cert) }; // Now, create a verifier with a helper using the given Certs. - let mut verifier = Verifier::from_bytes(signed_message, helper, None)?; + let mut verifier = Verifier::from_bytes(p, signed_message, helper, None)?; // Verify the data. io::copy(&mut verifier, sink)?; diff --git a/openpgp/examples/notarize.rs b/openpgp/examples/notarize.rs index 5d14ff9e..62042e60 100644 --- a/openpgp/examples/notarize.rs +++ b/openpgp/examples/notarize.rs @@ -12,8 +12,10 @@ use crate::openpgp::{ serialize::Serialize, }; use crate: