summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2020-06-17 14:50:21 +0200
committerNeal H. Walfield <neal@pep.foundation>2020-06-17 15:05:39 +0200
commitcaa2801b87cb055c2a2fe27c67c3e13cd44fc71d (patch)
tree7f80a63c7125852f604e81de3b6ad7756d097564
parentcd20d026549c26ef81a7ebc53abf7ed1b7b4764e (diff)
openpgp-ffi: Wrap the password handling functionality.
- Wrap functions to create a password-protected certificate (`pgp_cert_builder_set_password`), and to work with keys that are password protected (`pgp_key_has_unencrypted_secret`, `pgp_key_decrypt_secret`).
-rw-r--r--openpgp-ffi/include/sequoia/openpgp.h26
-rw-r--r--openpgp-ffi/src/cert.rs17
-rw-r--r--openpgp-ffi/src/packet/key.rs94
3 files changed, 136 insertions, 1 deletions
diff --git a/openpgp-ffi/include/sequoia/openpgp.h b/openpgp-ffi/include/sequoia/openpgp.h
index 9b6dadd1..99510a81 100644
--- a/openpgp-ffi/include/sequoia/openpgp.h
+++ b/openpgp-ffi/include/sequoia/openpgp.h
@@ -1096,6 +1096,15 @@ void pgp_cert_builder_set_cipher_suite(pgp_cert_builder_t *certb,
pgp_cert_cipher_suite_t cs);
/*/
+/// Sets the password for primary and all subkeys.
+///
+/// `password` is a byte array. `password_len` is its length.
+/*/
+void pgp_cert_builder_set_password(pgp_cert_builder_t *certb,
+ const uint8_t *password,
+ size_t password_len);
+
+/*/
/// Adds a new user ID. The first user ID added replaces the default
/// ID that is just the empty string.
/*/
@@ -1307,6 +1316,23 @@ int pgp_key_public_key_bits(pgp_key_t key);
/*/
pgp_key_pair_t pgp_key_into_key_pair (pgp_error_t *errp, pgp_key_t key);
+/// Returns whether the secret key material is encrypted.
+///
+/// Returns false if there is no secret key material.
+bool pgp_key_has_unencrypted_secret(pgp_key_t key);
+
+/// Decrypts the secret key material.
+///
+/// `password` is a byte array. `password_len` is its length.
+///
+/// Returns false if there is no secret key material.
+///
+/// This function takes ownership of `key`. On failure, `key` is
+/// deallocated.
+pgp_key_t pgp_key_decrypt_secret(pgp_error_t *errp, pgp_key_t key,
+ const uint8_t *password,
+ size_t password_len);
+
/*/
/// Constructs a User ID.
///
diff --git a/openpgp-ffi/src/cert.rs b/openpgp-ffi/src/cert.rs
index b2e8a576..c1040c11 100644
--- a/openpgp-ffi/src/cert.rs
+++ b/openpgp-ffi/src/cert.rs
@@ -13,6 +13,7 @@ use libc::{c_char, c_int, size_t, time_t};
extern crate sequoia_openpgp as openpgp;
use self::openpgp::{
crypto,
+ crypto::Password,
types::ReasonForRevocation,
parse::{
PacketParserResult,
@@ -963,6 +964,22 @@ pub extern "C" fn pgp_cert_builder_set_cipher_suite
*certb = box_raw!(certb_);
}
+/// Sets the password for primary and all subkeys.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "C" fn pgp_cert_builder_set_password
+ (certb: *mut *mut CertBuilder, password: *const u8, password_len: size_t)
+{
+ let certb = ffi_param_ref_mut!(certb);
+ let certb_ = ffi_param_move!(*certb);
+ assert!(!password.is_null());
+ let password = unsafe {
+ slice::from_raw_parts(password, password_len as usize)
+ };
+ let password: Password = password.into();
+ let certb_ = certb_.set_password(Some(password));
+ *certb = box_raw!(certb_);
+}
+
/// Adds a new user ID. The first user ID added replaces the default
/// ID that is just the empty string.
///
diff --git a/openpgp-ffi/src/packet/key.rs b/openpgp-ffi/src/packet/key.rs
index 6966acc1..088c3325 100644
--- a/openpgp-ffi/src/packet/key.rs
+++ b/openpgp-ffi/src/packet/key.rs
@@ -4,10 +4,12 @@
//!
//! [Section 5.5 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.5
-use libc::{c_int, time_t};
+use libc::{c_int, time_t, size_t};
+use std::slice;
extern crate sequoia_openpgp as openpgp;
use self::openpgp::packet::key;
+use self::openpgp::crypto::Password;
use super::super::fingerprint::Fingerprint;
use super::super::keyid::KeyID;
@@ -85,3 +87,93 @@ fn pgp_key_into_key_pair(errp: Option<&mut *mut crate::error::Error>,
let key = ffi_try!(key.move_from_raw().parts_into_secret());
ffi_try_box!(key.into_keypair())
}
+
+/// Returns whether the secret key material is unencrypted.
+///
+/// Returns false if there is no secret key material.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
+fn pgp_key_has_unencrypted_secret(key: *const Key) -> bool
+{
+ let key = key.ref_raw();
+ key.has_unencrypted_secret()
+}
+
+/// Decrypts the secret key material.
+///
+/// `password` is a byte array. `password_len` is its length.
+///
+/// Returns NULL if there is no secret key material, or the password
+/// is incorrect.
+///
+/// This function takes ownership of `key`. On failure, `key` is
+/// deallocated.
+///
+/// # Example
+///
+/// ```c
+/// #include <assert.h>
+/// #include <sequoia/openpgp.h>
+///
+/// pgp_cert_builder_t builder;
+/// pgp_cert_t cert;
+/// pgp_signature_t revocation;
+/// pgp_key_t encrypted_primary_key;
+/// pgp_key_t primary_key;
+/// pgp_key_pair_t primary_keypair;
+/// const uint8_t password[] = "foobar";
+/// const size_t password_len = strlen ((char *) password);
+///
+/// builder = pgp_cert_builder_new ();
+/// pgp_cert_builder_set_cipher_suite (&builder, PGP_CERT_CIPHER_SUITE_CV25519);
+/// pgp_cert_builder_set_password (&builder, password, password_len);
+/// pgp_cert_builder_generate (NULL, builder, &cert, &revocation);
+/// assert (cert);
+/// assert (revocation);
+/// pgp_signature_free (revocation); /* Free the generated one. */
+///
+/// encrypted_primary_key = pgp_cert_primary_key (cert);
+/// assert(! pgp_key_has_unencrypted_secret (encrypted_primary_key));
+///
+/// // This will fail, because primary_key is password protected.
+/// primary_keypair
+/// = pgp_key_into_key_pair (NULL, pgp_key_clone (encrypted_primary_key));
+/// assert(! primary_keypair);
+///
+/// // Try decrypting it with the wrong password.
+/// primary_key
+/// = pgp_key_decrypt_secret (NULL, pgp_key_clone (encrypted_primary_key),
+/// password, password_len - 1);
+/// assert(! primary_key);
+///
+/// // If we decrypt it, then we can create a keypair.
+/// primary_key
+/// = pgp_key_decrypt_secret (NULL, pgp_key_clone (encrypted_primary_key),
+/// password, password_len);
+/// assert(primary_key);
+/// assert(pgp_key_has_unencrypted_secret (primary_key));
+///
+/// primary_keypair
+/// = pgp_key_into_key_pair (NULL, pgp_key_clone (primary_key));
+/// assert(primary_keypair);
+///
+/// pgp_key_pair_free(primary_keypair);
+/// pgp_key_free (primary_key);
+/// pgp_key_free (encrypted_primary_key);
+/// pgp_cert_free (cert);
+/// ```
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
+fn pgp_key_decrypt_secret(errp: Option<&mut *mut crate::error::Error>,
+ key: *mut Key,
+ password: *const u8, password_len: size_t)
+ -> *mut Key
+{
+ ffi_make_fry_from_errp!(errp);
+ assert!(!password.is_null());
+ let password = unsafe {
+ slice::from_raw_parts(password, password_len as usize)
+ };
+ let password: Password = password.into();
+ let key = ffi_try!(key.move_from_raw().parts_into_secret());
+
+ ffi_try!(key.decrypt_secret(&password)).parts_into_unspecified().move_into_raw()
+}