summaryrefslogtreecommitdiffstats
path: root/comm/mail/extensions/openpgp/content/modules/RNPLib.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/extensions/openpgp/content/modules/RNPLib.jsm')
-rw-r--r--comm/mail/extensions/openpgp/content/modules/RNPLib.jsm2109
1 files changed, 2109 insertions, 0 deletions
diff --git a/comm/mail/extensions/openpgp/content/modules/RNPLib.jsm b/comm/mail/extensions/openpgp/content/modules/RNPLib.jsm
new file mode 100644
index 0000000000..58bcb383b5
--- /dev/null
+++ b/comm/mail/extensions/openpgp/content/modules/RNPLib.jsm
@@ -0,0 +1,2109 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const EXPORTED_SYMBOLS = ["RNPLibLoader"];
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+const { ctypes } = ChromeUtils.importESModule(
+ "resource://gre/modules/ctypes.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ setTimeout: "resource://gre/modules/Timer.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ OpenPGPMasterpass: "chrome://openpgp/content/modules/masterpass.jsm",
+});
+
+const MIN_RNP_VERSION = [0, 17, 0];
+
+var systemOS = Services.appinfo.OS.toLowerCase();
+var abi = ctypes.default_abi;
+
+// Open librnp. Determine the path to the chrome directory and look for it
+// there first. If not, fallback to searching the standard locations.
+var librnp, librnpPath;
+
+function tryLoadRNP(name, suffix) {
+ let filename = ctypes.libraryName(name) + suffix;
+ let binPath = Services.dirsvc.get("XpcomLib", Ci.nsIFile).path;
+ let binDir = PathUtils.parent(binPath);
+ librnpPath = PathUtils.join(binDir, filename);
+
+ try {
+ librnp = ctypes.open(librnpPath);
+ } catch (e) {}
+
+ if (!librnp) {
+ try {
+ // look in standard locations
+ librnpPath = filename;
+ librnp = ctypes.open(librnpPath);
+ } catch (e) {}
+ }
+}
+
+function loadExternalRNPLib() {
+ if (!librnp) {
+ // Try loading librnp.so, librnp.dylib, or rnp.dll first
+ tryLoadRNP("rnp", "");
+ }
+
+ if (!librnp && (systemOS === "winnt" || systemOS === "darwin")) {
+ // rnp.0.dll or rnp.0.dylib
+ tryLoadRNP("rnp.0", "");
+ }
+
+ if (!librnp) {
+ tryLoadRNP("rnp-0", "");
+ }
+
+ if (!librnp && systemOS === "winnt") {
+ // librnp-0.dll
+ tryLoadRNP("librnp-0", "");
+ }
+
+ if (!librnp && !(systemOS === "winnt") && !(systemOS === "darwin")) {
+ // librnp.so.0
+ tryLoadRNP("rnp", ".0");
+ }
+}
+
+var RNPLibLoader = {
+ init() {
+ const required_version_str = `${MIN_RNP_VERSION[0]}.${MIN_RNP_VERSION[1]}.${MIN_RNP_VERSION[2]}`;
+
+ let dummyRNPLib = {
+ loaded: false,
+ loadedOfficial: false,
+ loadStatus: "libs-rnp-status-load-failed",
+ loadErrorReason: "RNP/OpenPGP library failed to load",
+ path: "",
+
+ getRNPLibStatus() {
+ return {
+ min_version: required_version_str,
+ loaded_version: "-",
+ status: this.loadStatus,
+ error: this.loadErrorReason,
+ path: this.path,
+ };
+ },
+ };
+
+ loadExternalRNPLib();
+ if (!librnp) {
+ return dummyRNPLib;
+ }
+
+ try {
+ enableRNPLibJS();
+ } catch (e) {
+ console.log(e);
+ return dummyRNPLib;
+ }
+
+ const rnp_version_str =
+ RNPLib.rnp_version_string_full().readStringReplaceMalformed();
+ RNPLib.loadedVersion = rnp_version_str;
+ RNPLib.expectedVersion = required_version_str;
+
+ let hasRequiredVersion = RNPLib.check_required_version();
+
+ if (!hasRequiredVersion) {
+ RNPLib.loadErrorReason = `RNP version ${rnp_version_str} does not meet minimum required ${required_version_str}.`;
+ RNPLib.loadStatus = "libs-rnp-status-incompatible";
+ return RNPLib;
+ }
+
+ RNPLib.loaded = true;
+
+ let hasOfficialVersion =
+ rnp_version_str.includes(".MZLA") ||
+ rnp_version_str.match("^[0-9]+.[0-9]+.[0-9]+(.[0-9]+)?$");
+ if (!hasOfficialVersion) {
+ RNPLib.loadErrorReason = `RNP reports unexpected version information, it's considered an unofficial version with unknown capabilities.`;
+ RNPLib.loadStatus = "libs-rnp-status-unofficial";
+ } else {
+ RNPLib.loadedOfficial = true;
+ }
+
+ return RNPLib;
+ },
+};
+
+const rnp_result_t = ctypes.uint32_t;
+const rnp_ffi_t = ctypes.void_t.ptr;
+const rnp_input_t = ctypes.void_t.ptr;
+const rnp_output_t = ctypes.void_t.ptr;
+const rnp_key_handle_t = ctypes.void_t.ptr;
+const rnp_uid_handle_t = ctypes.void_t.ptr;
+const rnp_identifier_iterator_t = ctypes.void_t.ptr;
+const rnp_op_generate_t = ctypes.void_t.ptr;
+const rnp_op_encrypt_t = ctypes.void_t.ptr;
+const rnp_op_sign_t = ctypes.void_t.ptr;
+const rnp_op_sign_signature_t = ctypes.void_t.ptr;
+const rnp_op_verify_t = ctypes.void_t.ptr;
+const rnp_op_verify_signature_t = ctypes.void_t.ptr;
+const rnp_signature_handle_t = ctypes.void_t.ptr;
+const rnp_recipient_handle_t = ctypes.void_t.ptr;
+const rnp_symenc_handle_t = ctypes.void_t.ptr;
+
+const rnp_password_cb_t = ctypes.FunctionType(abi, ctypes.bool, [
+ rnp_ffi_t,
+ ctypes.void_t.ptr,
+ rnp_key_handle_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.size_t,
+]).ptr;
+
+const rnp_key_signatures_cb = ctypes.FunctionType(abi, ctypes.void_t, [
+ rnp_ffi_t,
+ ctypes.void_t.ptr,
+ rnp_signature_handle_t,
+ ctypes.uint32_t.ptr,
+]).ptr;
+
+var RNPLib;
+
+function enableRNPLibJS() {
+ // this must be delayed until after "librnp" is initialized
+
+ RNPLib = {
+ loaded: false,
+ loadedOfficial: false,
+ loadStatus: "",
+ loadErrorReason: "",
+ expectedVersion: "",
+ loadedVersion: "",
+
+ getRNPLibStatus() {
+ return {
+ min_version: this.expectedVersion,
+ loaded_version: this.loadedVersion,
+ status:
+ this.loaded && this.loadedOfficial
+ ? "libs-rnp-status-ok"
+ : this.loadStatus,
+ error: this.loadErrorReason,
+ path: this.path,
+ };
+ },
+
+ path: librnpPath,
+
+ // Handle to the RNP library and primary key data store.
+ // Kept at null if init fails.
+ ffi: null,
+
+ // returns rnp_input_t, destroy using rnp_input_destroy
+ async createInputFromPath(path) {
+ // IOUtils.read always returns an array.
+ let u8 = await IOUtils.read(path);
+ if (!u8.length) {
+ return null;
+ }
+
+ let input_from_memory = new this.rnp_input_t();
+ try {
+ this.rnp_input_from_memory(
+ input_from_memory.address(),
+ u8,
+ u8.length,
+ false
+ );
+ } catch (ex) {
+ throw new Error("rnp_input_from_memory for file " + path + " failed");
+ }
+ return input_from_memory;
+ },
+
+ getFilenames() {
+ let secFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ secFile.append("secring.gpg");
+ let pubFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ pubFile.append("pubring.gpg");
+
+ let secRingPath = secFile.path;
+ let pubRingPath = pubFile.path;
+
+ return { pubRingPath, secRingPath };
+ },
+
+ /**
+ * Load a keyring file into the global ffi context.
+ *
+ * @param {string} filename - The file to load
+ * @param keyringFlag - either RNP_LOAD_SAVE_PUBLIC_KEYS
+ * or RNP_LOAD_SAVE_SECRET_KEYS
+ */
+ async loadFile(filename, keyringFlag) {
+ let in_file = await this.createInputFromPath(filename);
+ if (in_file) {
+ this.rnp_load_keys(this.ffi, "GPG", in_file, keyringFlag);
+ this.rnp_input_destroy(in_file);
+ }
+ },
+
+ /**
+ * Load a keyring file into the global ffi context.
+ * If the file couldn't be opened, fall back to a backup file,
+ * by appending ".old" to filename.
+ *
+ * @param {string} filename - The file to load
+ * @param keyringFlag - either RNP_LOAD_SAVE_PUBLIC_KEYS
+ * or RNP_LOAD_SAVE_SECRET_KEYS
+ */
+ async loadWithFallback(filename, keyringFlag) {
+ let loadBackup = false;
+ try {
+ await this.loadFile(filename, keyringFlag);
+ } catch (ex) {
+ if (DOMException.isInstance(ex)) {
+ loadBackup = true;
+ }
+ }
+ if (loadBackup) {
+ filename += ".old";
+ try {
+ await this.loadFile(filename, keyringFlag);
+ } catch (ex) {}
+ }
+ },
+
+ async _fixUnprotectedKeys() {
+ // Bug 1710290, protect all unprotected keys.
+ // To do so, we require that the user has already unlocked
+ // by entering the global primary password, if it is set.
+ // Ensure that other repairing is done first, if necessary,
+ // as handled by masterpass.jsm (OpenPGP automatic password).
+
+ // Note we have two failure scenarios, either a failure, or
+ // retrieveOpenPGPPassword() returning null (that function
+ // might fail because of inconsistencies or corruption).
+ let canRepair = false;
+ try {
+ console.log("Trying to automatically protect the unprotected keys.");
+ let mp = await lazy.OpenPGPMasterpass.retrieveOpenPGPPassword();
+ if (mp) {
+ await RNPLib.protectUnprotectedKeys();
+ await RNPLib.saveKeys();
+ canRepair = true;
+ console.log("Successfully protected the unprotected keys.");
+ let [prot, unprot] = RNPLib.getProtectedKeysCount();
+ console.debug(
+ `Found (${prot} protected and ${unprot} unprotected secret keys.`
+ );
+ }
+ } catch (ex) {
+ console.log(ex);
+ }
+
+ if (!canRepair) {
+ console.log("Cannot protect the unprotected keys at this time.");
+ }
+ },
+
+ check_required_version() {
+ const min_version = this.rnp_version_for(...MIN_RNP_VERSION);
+ const this_version = this.rnp_version();
+ return Boolean(this_version >= min_version);
+ },
+
+ /**
+ * Prepare an RNP library handle, and in addition set all the
+ * application's preferences for library behavior.
+ *
+ * Other application code should NOT call rnp_ffi_create directly,
+ * but obtain an RNP library handle from this function.
+ */
+ prepare_ffi() {
+ let ffi = new rnp_ffi_t();
+ if (this._rnp_ffi_create(ffi.address(), "GPG", "GPG")) {
+ return null;
+ }
+
+ // Treat MD5 as insecure.
+ if (
+ this.rnp_add_security_rule(
+ ffi,
+ this.RNP_FEATURE_HASH_ALG,
+ this.RNP_ALGNAME_MD5,
+ this.RNP_SECURITY_OVERRIDE,
+ 0,
+ this.RNP_SECURITY_INSECURE
+ )
+ ) {
+ return null;
+ }
+
+ // Use RNP's default rule for SHA1 used with data signatures,
+ // and use our override to allow it for key signatures.
+ if (
+ this.rnp_add_security_rule(
+ ffi,
+ this.RNP_FEATURE_HASH_ALG,
+ this.RNP_ALGNAME_SHA1,
+ this.RNP_SECURITY_VERIFY_KEY | this.RNP_SECURITY_OVERRIDE,
+ 0,
+ this.RNP_SECURITY_DEFAULT
+ )
+ ) {
+ return null;
+ }
+
+ /*
+ // Security rules API does not yet support PK and SYMM algs.
+ //
+ // If a hash algorithm is already disabled at build time,
+ // and an attempt is made to set a security rule for that
+ // algorithm, then RNP returns a failure.
+ //
+ // Ideally, RNP should allow these calls (regardless of build time
+ // settings) to define an application security rule, that is
+ // independent of the configuration used for building the
+ // RNP library.
+
+ if (
+ this.rnp_add_security_rule(
+ ffi,
+ this.RNP_FEATURE_HASH_ALG,
+ this.RNP_ALGNAME_SM3,
+ this.RNP_SECURITY_OVERRIDE,
+ 0,
+ this.RNP_SECURITY_PROHIBITED
+ )
+ ) {
+ return null;
+ }
+
+ if (
+ this.rnp_add_security_rule(
+ ffi,
+ this.RNP_FEATURE_PK_ALG,
+ this.RNP_ALGNAME_SM2,
+ this.RNP_SECURITY_OVERRIDE,
+ 0,
+ this.RNP_SECURITY_PROHIBITED
+ )
+ ) {
+ return null;
+ }
+
+ if (
+ this.rnp_add_security_rule(
+ ffi,
+ this.RNP_FEATURE_SYMM_ALG,
+ this.RNP_ALGNAME_SM4,
+ this.RNP_SECURITY_OVERRIDE,
+ 0,
+ this.RNP_SECURITY_PROHIBITED
+ )
+ ) {
+ return null;
+ }
+ */
+
+ return ffi;
+ },
+
+ /**
+ * Test the correctness of security rules, in particular, test
+ * if the given hash algorithm is allowed at the given time.
+ *
+ * This is an application consistency test. If the behavior isn't
+ * according to the expectation, the function throws an error.
+ *
+ * @param {string} hashAlg - Test this hash algorithm
+ * @param {time_t} time - Test status at this timestamp
+ * @param {boolean} keySigAllowed - Test if using the hash algorithm
+ * is allowed for signatures found inside OpenPGP keys.
+ * @param {boolean} dataSigAllowed - Test if using the hash algorithm
+ * is allowed for signatures on data.
+ */
+ _confirmSecurityRule(hashAlg, time, keySigAllowed, dataSigAllowed) {
+ let level = new ctypes.uint32_t();
+ let flag = new ctypes.uint32_t();
+
+ flag.value = this.RNP_SECURITY_VERIFY_DATA;
+ let testDataSuccess = false;
+ if (
+ !RNPLib.rnp_get_security_rule(
+ this.ffi,
+ this.RNP_FEATURE_HASH_ALG,
+ hashAlg,
+ time,
+ flag.address(),
+ null,
+ level.address()
+ )
+ ) {
+ if (dataSigAllowed) {
+ testDataSuccess = level.value == RNPLib.RNP_SECURITY_DEFAULT;
+ } else {
+ testDataSuccess = level.value < RNPLib.RNP_SECURITY_DEFAULT;
+ }
+ }
+
+ if (!testDataSuccess) {
+ throw new Error("security configuration for data signatures failed");
+ }
+
+ flag.value = this.RNP_SECURITY_VERIFY_KEY;
+ let testKeySuccess = false;
+ if (
+ !RNPLib.rnp_get_security_rule(
+ this.ffi,
+ this.RNP_FEATURE_HASH_ALG,
+ hashAlg,
+ time,
+ flag.address(),
+ null,
+ level.address()
+ )
+ ) {
+ if (keySigAllowed) {
+ testKeySuccess = level.value == RNPLib.RNP_SECURITY_DEFAULT;
+ } else {
+ testKeySuccess = level.value < RNPLib.RNP_SECURITY_DEFAULT;
+ }
+ }
+
+ if (!testKeySuccess) {
+ throw new Error("security configuration for key signatures failed");
+ }
+ },
+
+ /**
+ * Perform tests that the RNP library behaves according to the
+ * defined security rules.
+ * If a problem is found, the function throws an error.
+ */
+ _sanityCheckSecurityRules() {
+ let time_t_now = Math.round(Date.now() / 1000);
+ let ten_years_in_seconds = 10 * 365 * 24 * 60 * 60;
+ let ten_years_future = time_t_now + ten_years_in_seconds;
+
+ this._confirmSecurityRule(this.RNP_ALGNAME_MD5, time_t_now, false, false);
+ this._confirmSecurityRule(
+ this.RNP_ALGNAME_MD5,
+ ten_years_future,
+ false,
+ false
+ );
+
+ this._confirmSecurityRule(this.RNP_ALGNAME_SHA1, time_t_now, true, false);
+ this._confirmSecurityRule(
+ this.RNP_ALGNAME_SHA1,
+ ten_years_future,
+ true,
+ false
+ );
+ },
+
+ async init() {
+ this.ffi = this.prepare_ffi();
+ if (!this.ffi) {
+ throw new Error("Couldn't initialize librnp.");
+ }
+
+ this.rnp_ffi_set_log_fd(this.ffi, 2); // stderr
+
+ this.keep_password_cb_alive = rnp_password_cb_t(
+ this.password_cb,
+ this, // this value used while executing callback
+ false // callback return value if exception is thrown
+ );
+ this.rnp_ffi_set_pass_provider(
+ this.ffi,
+ this.keep_password_cb_alive,
+ null
+ );
+
+ let { pubRingPath, secRingPath } = this.getFilenames();
+
+ try {
+ this._sanityCheckSecurityRules();
+ } catch (e) {
+ // Disable all RNP operation
+ this.ffi = null;
+ throw e;
+ }
+
+ await this.loadWithFallback(pubRingPath, this.RNP_LOAD_SAVE_PUBLIC_KEYS);
+ await this.loadWithFallback(secRingPath, this.RNP_LOAD_SAVE_SECRET_KEYS);
+
+ let pubnum = new ctypes.size_t();
+ this.rnp_get_public_key_count(this.ffi, pubnum.address());
+
+ let secnum = new ctypes.size_t();
+ this.rnp_get_secret_key_count(this.ffi, secnum.address());
+
+ let [prot, unprot] = this.getProtectedKeysCount();
+ console.debug(
+ `Found ${pubnum.value} public keys and ${secnum.value} secret keys (${prot} protected, ${unprot} unprotected)`
+ );
+
+ if (unprot) {
+ // We need automatic repair, which can involve a primary password
+ // prompt. Let's use a short timer, so we keep it out of the
+ // early startup code.
+ console.log(
+ "Will attempt to automatically protect the unprotected keys in 30 seconds"
+ );
+ lazy.setTimeout(RNPLib._fixUnprotectedKeys, 30000);
+ }
+ return true;
+ },
+
+ /**
+ * Returns two numbers, the number of protected and unprotected keys.
+ * Because we use an automatic password for all secret keys
+ * (regardless of a primary password being used),
+ * the number of unprotected keys should be zero.
+ */
+ getProtectedKeysCount() {
+ let prot = 0;
+ let unprot = 0;
+
+ let iter = new RNPLib.rnp_identifier_iterator_t();
+ let grip = new ctypes.char.ptr();
+
+ if (
+ RNPLib.rnp_identifier_iterator_create(
+ RNPLib.ffi,
+ iter.address(),
+ "grip"
+ )
+ ) {
+ throw new Error("rnp_identifier_iterator_create failed");
+ }
+
+ while (
+ !RNPLib.rnp_identifier_iterator_next(iter, grip.address()) &&
+ !grip.isNull()
+ ) {
+ let handle = new RNPLib.rnp_key_handle_t();
+ if (RNPLib.rnp_locate_key(RNPLib.ffi, "grip", grip, handle.address())) {
+ throw new Error("rnp_locate_key failed");
+ }
+
+ if (this.getSecretAvailableFromHandle(handle)) {
+ let is_protected = new ctypes.bool();
+ if (RNPLib.rnp_key_is_protected(handle, is_protected.address())) {
+ throw new Error("rnp_key_is_protected failed");
+ }
+ if (is_protected.value) {
+ prot++;
+ } else {
+ unprot++;
+ }
+ }
+
+ RNPLib.rnp_key_handle_destroy(handle);
+ }
+
+ RNPLib.rnp_identifier_iterator_destroy(iter);
+ return [prot, unprot];
+ },
+
+ getSecretAvailableFromHandle(handle) {
+ let have_secret = new ctypes.bool();
+ if (RNPLib.rnp_key_have_secret(handle, have_secret.address())) {
+ throw new Error("rnp_key_have_secret failed");
+ }
+ return have_secret.value;
+ },
+
+ /**
+ * If the given secret key is a pseudo secret key, which doesn't
+ * contain the underlying key material, then return false.
+ *
+ * Only call this function if getSecretAvailableFromHandle returns
+ * true for the given handle (which means it claims to contain a
+ * secret key).
+ *
+ * @param {rnp_key_handle_t} handle - handle of the key to query
+ * @returns {boolean} - true if secret key material is available
+ *
+ */
+ isSecretKeyMaterialAvailable(handle) {
+ let protection_type = new ctypes.char.ptr();
+ if (
+ RNPLib.rnp_key_get_protection_type(handle, protection_type.address())
+ ) {
+ throw new Error("rnp_key_get_protection_type failed");
+ }
+ let result;
+ switch (protection_type.readString()) {
+ case "GPG-None":
+ case "GPG-Smartcard":
+ case "Unknown":
+ result = false;
+ break;
+ default:
+ result = true;
+ break;
+ }
+ RNPLib.rnp_buffer_destroy(protection_type);
+ return result;
+ },
+
+ async protectUnprotectedKeys() {
+ let iter = new RNPLib.rnp_identifier_iterator_t();
+ let grip = new ctypes.char.ptr();
+
+ let newPass = await lazy.OpenPGPMasterpass.retrieveOpenPGPPassword();
+
+ if (
+ RNPLib.rnp_identifier_iterator_create(
+ RNPLib.ffi,
+ iter.address(),
+ "grip"
+ )
+ ) {
+ throw new Error("rnp_identifier_iterator_create failed");
+ }
+
+ while (
+ !RNPLib.rnp_identifier_iterator_next(iter, grip.address()) &&
+ !grip.isNull()
+ ) {
+ let handle = new RNPLib.rnp_key_handle_t();
+ if (RNPLib.rnp_locate_key(RNPLib.ffi, "grip", grip, handle.address())) {
+ throw new Error("rnp_locate_key failed");
+ }
+
+ if (RNPLib.getSecretAvailableFromHandle(handle)) {
+ let is_protected = new ctypes.bool();
+ if (RNPLib.rnp_key_is_protected(handle, is_protected.address())) {
+ throw new Error("rnp_key_is_protected failed");
+ }
+ if (!is_protected.value) {
+ RNPLib.protectKeyWithSubKeys(handle, newPass);
+ }
+ }
+
+ RNPLib.rnp_key_handle_destroy(handle);
+ }
+
+ RNPLib.rnp_identifier_iterator_destroy(iter);
+ },
+
+ protectKeyWithSubKeys(handle, newPass) {
+ if (RNPLib.isSecretKeyMaterialAvailable(handle)) {
+ if (RNPLib.rnp_key_protect(handle, newPass, null, null, null, 0)) {
+ throw new Error("rnp_key_protect failed");
+ }
+ }
+
+ let sub_count = new ctypes.size_t();
+ if (RNPLib.rnp_key_get_subkey_count(handle, sub_count.address())) {
+ throw new Error("rnp_key_get_subkey_count failed");
+ }
+
+ for (let i = 0; i < sub_count.value; i++) {
+ let sub_handle = new RNPLib.rnp_key_handle_t();
+ if (RNPLib.rnp_key_get_subkey_at(handle, i, sub_handle.address())) {
+ throw new Error("rnp_key_get_subkey_at failed");
+ }
+ if (
+ RNPLib.getSecretAvailableFromHandle(sub_handle) &&
+ RNPLib.isSecretKeyMaterialAvailable(sub_handle)
+ ) {
+ if (
+ RNPLib.rnp_key_protect(sub_handle, newPass, null, null, null, 0)
+ ) {
+ throw new Error("rnp_key_protect failed");
+ }
+ }
+ RNPLib.rnp_key_handle_destroy(sub_handle);
+ }
+ },
+
+ /**
+ * Save keyring file to the given path.
+ *
+ * @param {string} path - The file path to save to.
+ * @param {number} keyRingFlag - RNP_LOAD_SAVE_PUBLIC_KEYS or
+ * RNP_LOAD_SAVE_SECRET_KEYS.
+ */
+ async saveKeyRing(path, keyRingFlag) {
+ if (!this.ffi) {
+ return;
+ }
+
+ let oldPath = path + ".old";
+
+ // Ignore failure, oldPath might not exist yet.
+ await IOUtils.copy(path, oldPath).catch(() => {});
+
+ let u8 = null;
+ let keyCount = new ctypes.size_t();
+
+ if (keyRingFlag == this.RNP_LOAD_SAVE_SECRET_KEYS) {
+ this.rnp_get_secret_key_count(this.ffi, keyCount.address());
+ } else {
+ this.rnp_get_public_key_count(this.ffi, keyCount.address());
+ }
+
+ let keyCountNum = parseInt(keyCount.value.toString());
+ if (keyCountNum) {
+ let rnp_out = new this.rnp_output_t();
+ if (this.rnp_output_to_memory(rnp_out.address(), 0)) {
+ throw new Error("rnp_output_to_memory failed");
+ }
+ if (this.rnp_save_keys(this.ffi, "GPG", rnp_out, keyRingFlag)) {
+ throw new Error("rnp_save_keys failed");
+ }
+
+ let result_buf = new ctypes.uint8_t.ptr();
+ let result_len = new ctypes.size_t();
+
+ // Parameter false means "don't copy rnp_out to result_buf",
+ // rather a reference to the memory is used. Be careful to
+ // destroy rnp_out after we're done with the data.
+ if (
+ this.rnp_output_memory_get_buf(
+ rnp_out,
+ result_buf.address(),
+ result_len.address(),
+ false
+ )
+ ) {
+ throw new Error("rnp_output_memory_get_buf failed");
+ } else {
+ let uint8_array = ctypes.cast(
+ result_buf,
+ ctypes.uint8_t.array(result_len.value).ptr
+ ).contents;
+ // This call creates a copy of the data, it should be
+ // safe to destroy rnp_out afterwards.
+ u8 = uint8_array.readTypedArray();
+ }
+ this.rnp_output_destroy(rnp_out);
+ }
+
+ u8 = u8 || new Uint8Array();
+
+ await IOUtils.write(path, u8, {
+ tmpPath: path + ".tmp-new",
+ });
+ },
+
+ async saveKeys() {
+ if (!this.ffi) {
+ return;
+ }
+ let { pubRingPath, secRingPath } = this.getFilenames();
+
+ let saveThem = async () => {
+ await this.saveKeyRing(pubRingPath, this.RNP_LOAD_SAVE_PUBLIC_KEYS);
+ await this.saveKeyRing(secRingPath, this.RNP_LOAD_SAVE_SECRET_KEYS);
+ };
+ let saveBlocker = saveThem();
+ IOUtils.profileBeforeChange.addBlocker(
+ "OpenPGP: writing out keyring",
+ saveBlocker
+ );
+ await saveBlocker;
+ IOUtils.profileBeforeChange.removeBlocker(saveBlocker);
+ },
+
+ keep_password_cb_alive: null,
+
+ cached_pw: null,
+
+ /**
+ * Past versions of Thunderbird used this callback to provide
+ * the automatically managed passphrase to RNP, which was used
+ * for all OpenPGP. Nowadays, Thunderbird supports the definition
+ * of used-defined passphrase. To better control the unlocking of
+ * keys, Thunderbird no longer uses this callback.
+ * The application is designed to unlock secret keys as needed,
+ * prior to calling the respective RNP APIs.
+ * If this callback is reached anyway, it's an internal error,
+ * it means that some Thunderbird code hasn't properly unlocked
+ * the required key yet.
+ *
+ * This is a C callback from an external library, so we cannot
+ * rely on the usual JS throw mechanism to abort this operation.
+ */
+ password_cb(ffi, app_ctx, key, pgp_context, buf, buf_len) {
+ let fingerprint = new ctypes.char.ptr();
+ let fpStr;
+ if (!RNPLib.rnp_key_get_fprint(key, fingerprint.address())) {
+ fpStr = "Fingerprint: " + fingerprint.readString();
+ }
+ RNPLib.rnp_buffer_destroy(fingerprint);
+
+ console.debug(
+ `Internal error, RNP password callback called unexpectedly. ${fpStr}.`
+ );
+ return false;
+ },
+
+ // For comparing version numbers
+ rnp_version_for: librnp.declare(
+ "rnp_version_for",
+ abi,
+ ctypes.uint32_t,
+ ctypes.uint32_t, // major
+ ctypes.uint32_t, // minor
+ ctypes.uint32_t // patch
+ ),
+
+ // Get the library version.
+ rnp_version: librnp.declare("rnp_version", abi, ctypes.uint32_t),
+
+ rnp_version_string_full: librnp.declare(
+ "rnp_version_string_full",
+ abi,
+ ctypes.char.ptr
+ ),
+
+ // Get a RNP library handle.
+ // Mark with leading underscore, to clarify that this function
+ // shouldn't be called directly - you should call prepare_ffi().
+ _rnp_ffi_create: librnp.declare(
+ "rnp_ffi_create",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t.ptr,
+ ctypes.char.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_ffi_destroy: librnp.declare(
+ "rnp_ffi_destroy",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t
+ ),
+
+ rnp_ffi_set_log_fd: librnp.declare(
+ "rnp_ffi_set_log_fd",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.int
+ ),
+
+ rnp_get_public_key_count: librnp.declare(
+ "rnp_get_public_key_count",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_get_secret_key_count: librnp.declare(
+ "rnp_get_secret_key_count",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_input_from_path: librnp.declare(
+ "rnp_input_from_path",
+ abi,
+ rnp_result_t,
+ rnp_input_t.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_input_from_memory: librnp.declare(
+ "rnp_input_from_memory",
+ abi,
+ rnp_result_t,
+ rnp_input_t.ptr,
+ ctypes.uint8_t.ptr,
+ ctypes.size_t,
+ ctypes.bool
+ ),
+
+ rnp_output_to_memory: librnp.declare(
+ "rnp_output_to_memory",
+ abi,
+ rnp_result_t,
+ rnp_output_t.ptr,
+ ctypes.size_t
+ ),
+
+ rnp_output_to_path: librnp.declare(
+ "rnp_output_to_path",
+ abi,
+ rnp_result_t,
+ rnp_output_t.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_decrypt: librnp.declare(
+ "rnp_decrypt",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ rnp_input_t,
+ rnp_output_t
+ ),
+
+ rnp_output_memory_get_buf: librnp.declare(
+ "rnp_output_memory_get_buf",
+ abi,
+ rnp_result_t,
+ rnp_output_t,
+ ctypes.uint8_t.ptr.ptr,
+ ctypes.size_t.ptr,
+ ctypes.bool
+ ),
+
+ rnp_input_destroy: librnp.declare(
+ "rnp_input_destroy",
+ abi,
+ rnp_result_t,
+ rnp_input_t
+ ),
+
+ rnp_output_destroy: librnp.declare(
+ "rnp_output_destroy",
+ abi,
+ rnp_result_t,
+ rnp_output_t
+ ),
+
+ rnp_load_keys: librnp.declare(
+ "rnp_load_keys",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.char.ptr,
+ rnp_input_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_save_keys: librnp.declare(
+ "rnp_save_keys",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.char.ptr,
+ rnp_output_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_ffi_set_pass_provider: librnp.declare(
+ "rnp_ffi_set_pass_provider",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ rnp_password_cb_t,
+ ctypes.void_t.ptr
+ ),
+
+ rnp_identifier_iterator_create: librnp.declare(
+ "rnp_identifier_iterator_create",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ rnp_identifier_iterator_t.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_identifier_iterator_next: librnp.declare(
+ "rnp_identifier_iterator_next",
+ abi,
+ rnp_result_t,
+ rnp_identifier_iterator_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_identifier_iterator_destroy: librnp.declare(
+ "rnp_identifier_iterator_destroy",
+ abi,
+ rnp_result_t,
+ rnp_identifier_iterator_t
+ ),
+
+ rnp_locate_key: librnp.declare(
+ "rnp_locate_key",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ rnp_key_handle_t.ptr
+ ),
+
+ rnp_key_handle_destroy: librnp.declare(
+ "rnp_key_handle_destroy",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t
+ ),
+
+ rnp_key_allows_usage: librnp.declare(
+ "rnp_key_allows_usage",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_is_sub: librnp.declare(
+ "rnp_key_is_sub",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_is_primary: librnp.declare(
+ "rnp_key_is_primary",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_have_secret: librnp.declare(
+ "rnp_key_have_secret",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_have_public: librnp.declare(
+ "rnp_key_have_public",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_get_fprint: librnp.declare(
+ "rnp_key_get_fprint",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_get_keyid: librnp.declare(
+ "rnp_key_get_keyid",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_get_alg: librnp.declare(
+ "rnp_key_get_alg",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_get_grip: librnp.declare(
+ "rnp_key_get_grip",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_get_primary_grip: librnp.declare(
+ "rnp_key_get_primary_grip",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_is_revoked: librnp.declare(
+ "rnp_key_is_revoked",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_buffer_destroy: librnp.declare(
+ "rnp_buffer_destroy",
+ abi,
+ ctypes.void_t,
+ ctypes.void_t.ptr
+ ),
+
+ rnp_key_get_subkey_count: librnp.declare(
+ "rnp_key_get_subkey_count",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_key_get_subkey_at: librnp.declare(
+ "rnp_key_get_subkey_at",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.size_t,
+ rnp_key_handle_t.ptr
+ ),
+
+ rnp_key_get_creation: librnp.declare(
+ "rnp_key_get_creation",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_key_get_expiration: librnp.declare(
+ "rnp_key_get_expiration",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_key_get_bits: librnp.declare(
+ "rnp_key_get_bits",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_key_get_uid_count: librnp.declare(
+ "rnp_key_get_uid_count",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_key_get_primary_uid: librnp.declare(
+ "rnp_key_get_primary_uid",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_get_uid_at: librnp.declare(
+ "rnp_key_get_uid_at",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.size_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_get_uid_handle_at: librnp.declare(
+ "rnp_key_get_uid_handle_at",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.size_t,
+ rnp_uid_handle_t.ptr
+ ),
+
+ rnp_uid_handle_destroy: librnp.declare(
+ "rnp_uid_handle_destroy",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t
+ ),
+
+ rnp_uid_is_revoked: librnp.declare(
+ "rnp_uid_is_revoked",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_unlock: librnp.declare(
+ "rnp_key_unlock",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_key_lock: librnp.declare(
+ "rnp_key_lock",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t
+ ),
+
+ rnp_key_unprotect: librnp.declare(
+ "rnp_key_unprotect",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_key_protect: librnp.declare(
+ "rnp_key_protect",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.size_t
+ ),
+
+ rnp_key_is_protected: librnp.declare(
+ "rnp_key_is_protected",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_is_locked: librnp.declare(
+ "rnp_key_is_locked",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_op_generate_create: librnp.declare(
+ "rnp_op_generate_create",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t.ptr,
+ rnp_ffi_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_generate_subkey_create: librnp.declare(
+ "rnp_op_generate_subkey_create",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t.ptr,
+ rnp_ffi_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_generate_set_bits: librnp.declare(
+ "rnp_op_generate_set_bits",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_op_generate_set_curve: librnp.declare(
+ "rnp_op_generate_set_curve",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_generate_set_protection_password: librnp.declare(
+ "rnp_op_generate_set_protection_password",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_generate_set_userid: librnp.declare(
+ "rnp_op_generate_set_userid",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_generate_set_expiration: librnp.declare(
+ "rnp_op_generate_set_expiration",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_op_generate_execute: librnp.declare(
+ "rnp_op_generate_execute",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t
+ ),
+
+ rnp_op_generate_get_key: librnp.declare(
+ "rnp_op_generate_get_key",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t,
+ rnp_key_handle_t.ptr
+ ),
+
+ rnp_op_generate_destroy: librnp.declare(
+ "rnp_op_generate_destroy",
+ abi,
+ rnp_result_t,
+ rnp_op_generate_t
+ ),
+
+ rnp_guess_contents: librnp.declare(
+ "rnp_guess_contents",
+ abi,
+ rnp_result_t,
+ rnp_input_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_import_signatures: librnp.declare(
+ "rnp_import_signatures",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ rnp_input_t,
+ ctypes.uint32_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_import_keys: librnp.declare(
+ "rnp_import_keys",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ rnp_input_t,
+ ctypes.uint32_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_key_remove: librnp.declare(
+ "rnp_key_remove",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_uid_remove: librnp.declare(
+ "rnp_uid_remove",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ rnp_uid_handle_t
+ ),
+
+ rnp_key_remove_signatures: librnp.declare(
+ "rnp_key_remove_signatures",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t,
+ rnp_key_signatures_cb,
+ ctypes.void_t.ptr
+ ),
+
+ rnp_op_encrypt_create: librnp.declare(
+ "rnp_op_encrypt_create",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t.ptr,
+ rnp_ffi_t,
+ rnp_input_t,
+ rnp_output_t
+ ),
+
+ rnp_op_sign_cleartext_create: librnp.declare(
+ "rnp_op_sign_cleartext_create",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t.ptr,
+ rnp_ffi_t,
+ rnp_input_t,
+ rnp_output_t
+ ),
+
+ rnp_op_sign_detached_create: librnp.declare(
+ "rnp_op_sign_detached_create",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t.ptr,
+ rnp_ffi_t,
+ rnp_input_t,
+ rnp_output_t
+ ),
+
+ rnp_op_encrypt_add_recipient: librnp.declare(
+ "rnp_op_encrypt_add_recipient",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ rnp_key_handle_t
+ ),
+
+ rnp_op_encrypt_add_signature: librnp.declare(
+ "rnp_op_encrypt_add_signature",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ rnp_key_handle_t,
+ rnp_op_sign_signature_t.ptr
+ ),
+
+ rnp_op_sign_add_signature: librnp.declare(
+ "rnp_op_sign_add_signature",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t,
+ rnp_key_handle_t,
+ rnp_op_sign_signature_t.ptr
+ ),
+
+ rnp_op_encrypt_set_armor: librnp.declare(
+ "rnp_op_encrypt_set_armor",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ ctypes.bool
+ ),
+
+ rnp_op_sign_set_armor: librnp.declare(
+ "rnp_op_sign_set_armor",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t,
+ ctypes.bool
+ ),
+
+ rnp_op_encrypt_set_hash: librnp.declare(
+ "rnp_op_encrypt_set_hash",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_sign_set_hash: librnp.declare(
+ "rnp_op_sign_set_hash",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_encrypt_set_cipher: librnp.declare(
+ "rnp_op_encrypt_set_cipher",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_sign_execute: librnp.declare(
+ "rnp_op_sign_execute",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t
+ ),
+
+ rnp_op_sign_destroy: librnp.declare(
+ "rnp_op_sign_destroy",
+ abi,
+ rnp_result_t,
+ rnp_op_sign_t
+ ),
+
+ rnp_op_encrypt_execute: librnp.declare(
+ "rnp_op_encrypt_execute",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t
+ ),
+
+ rnp_op_encrypt_destroy: librnp.declare(
+ "rnp_op_encrypt_destroy",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t
+ ),
+
+ rnp_key_export: librnp.declare(
+ "rnp_key_export",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ rnp_output_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_key_export_revocation: librnp.declare(
+ "rnp_key_export_revocation",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ rnp_output_t,
+ ctypes.uint32_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_output_to_armor: librnp.declare(
+ "rnp_output_to_armor",
+ abi,
+ rnp_result_t,
+ rnp_output_t,
+ rnp_output_t.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_output_finish: librnp.declare(
+ "rnp_output_finish",
+ abi,
+ rnp_result_t,
+ rnp_output_t
+ ),
+
+ rnp_op_verify_create: librnp.declare(
+ "rnp_op_verify_create",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t.ptr,
+ rnp_ffi_t,
+ rnp_input_t,
+ rnp_output_t
+ ),
+
+ rnp_op_verify_detached_create: librnp.declare(
+ "rnp_op_verify_detached_create",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t.ptr,
+ rnp_ffi_t,
+ rnp_input_t,
+ rnp_input_t
+ ),
+
+ rnp_op_verify_execute: librnp.declare(
+ "rnp_op_verify_execute",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t
+ ),
+
+ rnp_op_verify_destroy: librnp.declare(
+ "rnp_op_verify_destroy",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t
+ ),
+
+ rnp_op_verify_get_signature_count: librnp.declare(
+ "rnp_op_verify_get_signature_count",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_op_verify_get_signature_at: librnp.declare(
+ "rnp_op_verify_get_signature_at",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.size_t,
+ rnp_op_verify_signature_t.ptr
+ ),
+
+ rnp_op_verify_signature_get_handle: librnp.declare(
+ "rnp_op_verify_signature_get_handle",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_signature_t,
+ rnp_signature_handle_t.ptr
+ ),
+
+ rnp_op_verify_signature_get_status: librnp.declare(
+ "rnp_op_verify_signature_get_status",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_signature_t
+ ),
+
+ rnp_op_verify_signature_get_key: librnp.declare(
+ "rnp_op_verify_signature_get_key",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_signature_t,
+ rnp_key_handle_t.ptr
+ ),
+
+ rnp_op_verify_signature_get_times: librnp.declare(
+ "rnp_op_verify_signature_get_times",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_signature_t,
+ ctypes.uint32_t.ptr,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_uid_get_signature_count: librnp.declare(
+ "rnp_uid_get_signature_count",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_uid_get_signature_at: librnp.declare(
+ "rnp_uid_get_signature_at",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t,
+ ctypes.size_t,
+ rnp_signature_handle_t.ptr
+ ),
+
+ rnp_key_get_signature_count: librnp.declare(
+ "rnp_key_get_signature_count",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_key_get_signature_at: librnp.declare(
+ "rnp_key_get_signature_at",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.size_t,
+ rnp_signature_handle_t.ptr
+ ),
+
+ rnp_signature_get_hash_alg: librnp.declare(
+ "rnp_signature_get_hash_alg",
+ abi,
+ rnp_result_t,
+ rnp_signature_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_signature_get_creation: librnp.declare(
+ "rnp_signature_get_creation",
+ abi,
+ rnp_result_t,
+ rnp_signature_handle_t,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_signature_get_keyid: librnp.declare(
+ "rnp_signature_get_keyid",
+ abi,
+ rnp_result_t,
+ rnp_signature_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_signature_get_signer: librnp.declare(
+ "rnp_signature_get_signer",
+ abi,
+ rnp_result_t,
+ rnp_signature_handle_t,
+ rnp_key_handle_t.ptr
+ ),
+
+ rnp_signature_handle_destroy: librnp.declare(
+ "rnp_signature_handle_destroy",
+ abi,
+ rnp_result_t,
+ rnp_signature_handle_t
+ ),
+
+ rnp_enarmor: librnp.declare(
+ "rnp_enarmor",
+ abi,
+ rnp_result_t,
+ rnp_input_t,
+ rnp_output_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_verify_get_protection_info: librnp.declare(
+ "rnp_op_verify_get_protection_info",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.char.ptr.ptr,
+ ctypes.char.ptr.ptr,
+ ctypes.bool.ptr
+ ),
+
+ rnp_op_verify_get_recipient_count: librnp.declare(
+ "rnp_op_verify_get_recipient_count",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_op_verify_get_used_recipient: librnp.declare(
+ "rnp_op_verify_get_used_recipient",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ rnp_recipient_handle_t.ptr
+ ),
+
+ rnp_op_verify_get_recipient_at: librnp.declare(
+ "rnp_op_verify_get_recipient_at",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.size_t,
+ rnp_recipient_handle_t.ptr
+ ),
+
+ rnp_recipient_get_keyid: librnp.declare(
+ "rnp_recipient_get_keyid",
+ abi,
+ rnp_result_t,
+ rnp_recipient_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_recipient_get_alg: librnp.declare(
+ "rnp_recipient_get_alg",
+ abi,
+ rnp_result_t,
+ rnp_recipient_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_op_verify_get_symenc_count: librnp.declare(
+ "rnp_op_verify_get_symenc_count",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.size_t.ptr
+ ),
+
+ rnp_op_verify_get_used_symenc: librnp.declare(
+ "rnp_op_verify_get_used_symenc",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ rnp_symenc_handle_t.ptr
+ ),
+
+ rnp_op_verify_get_symenc_at: librnp.declare(
+ "rnp_op_verify_get_symenc_at",
+ abi,
+ rnp_result_t,
+ rnp_op_verify_t,
+ ctypes.size_t,
+ rnp_symenc_handle_t.ptr
+ ),
+
+ rnp_symenc_get_cipher: librnp.declare(
+ "rnp_symenc_get_cipher",
+ abi,
+ rnp_result_t,
+ rnp_symenc_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_symenc_get_aead_alg: librnp.declare(
+ "rnp_symenc_get_aead_alg",
+ abi,
+ rnp_result_t,
+ rnp_symenc_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_symenc_get_hash_alg: librnp.declare(
+ "rnp_symenc_get_hash_alg",
+ abi,
+ rnp_result_t,
+ rnp_symenc_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_symenc_get_s2k_type: librnp.declare(
+ "rnp_symenc_get_s2k_type",
+ abi,
+ rnp_result_t,
+ rnp_symenc_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_symenc_get_s2k_iterations: librnp.declare(
+ "rnp_symenc_get_s2k_iterations",
+ abi,
+ rnp_result_t,
+ rnp_symenc_handle_t,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_key_set_expiration: librnp.declare(
+ "rnp_key_set_expiration",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_key_revoke: librnp.declare(
+ "rnp_key_revoke",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.char.ptr
+ ),
+
+ rnp_key_export_autocrypt: librnp.declare(
+ "rnp_key_export_autocrypt",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr,
+ rnp_output_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_key_valid_till: librnp.declare(
+ "rnp_key_valid_till",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_key_valid_till64: librnp.declare(
+ "rnp_key_valid_till64",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.uint64_t.ptr
+ ),
+
+ rnp_uid_is_valid: librnp.declare(
+ "rnp_uid_is_valid",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_uid_is_primary: librnp.declare(
+ "rnp_uid_is_primary",
+ abi,
+ rnp_result_t,
+ rnp_uid_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_signature_is_valid: librnp.declare(
+ "rnp_signature_is_valid",
+ abi,
+ rnp_result_t,
+ rnp_signature_handle_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_key_get_protection_type: librnp.declare(
+ "rnp_key_get_protection_type",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_output_armor_set_line_length: librnp.declare(
+ "rnp_output_armor_set_line_length",
+ abi,
+ rnp_result_t,
+ rnp_output_t,
+ ctypes.size_t
+ ),
+
+ rnp_key_25519_bits_tweaked: librnp.declare(
+ "rnp_key_25519_bits_tweaked",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.bool.ptr
+ ),
+
+ rnp_key_25519_bits_tweak: librnp.declare(
+ "rnp_key_25519_bits_tweak",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t
+ ),
+
+ rnp_key_get_curve: librnp.declare(
+ "rnp_key_get_curve",
+ abi,
+ rnp_result_t,
+ rnp_key_handle_t,
+ ctypes.char.ptr.ptr
+ ),
+
+ rnp_get_security_rule: librnp.declare(
+ "rnp_get_security_rule",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.uint64_t,
+ ctypes.uint32_t.ptr,
+ ctypes.uint64_t.ptr,
+ ctypes.uint32_t.ptr
+ ),
+
+ rnp_add_security_rule: librnp.declare(
+ "rnp_add_security_rule",
+ abi,
+ rnp_result_t,
+ rnp_ffi_t,
+ ctypes.char.ptr,
+ ctypes.char.ptr,
+ ctypes.uint32_t,
+ ctypes.uint64_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_op_encrypt_set_aead: librnp.declare(
+ "rnp_op_encrypt_set_aead",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ ctypes.char.ptr
+ ),
+
+ rnp_op_encrypt_set_flags: librnp.declare(
+ "rnp_op_encrypt_set_flags",
+ abi,
+ rnp_result_t,
+ rnp_op_encrypt_t,
+ ctypes.uint32_t
+ ),
+
+ rnp_result_t,
+ rnp_ffi_t,
+ rnp_password_cb_t,
+ rnp_input_t,
+ rnp_output_t,
+ rnp_key_handle_t,
+ rnp_uid_handle_t,
+ rnp_identifier_iterator_t,
+ rnp_op_generate_t,
+ rnp_op_encrypt_t,
+ rnp_op_sign_t,
+ rnp_op_sign_signature_t,
+ rnp_op_verify_t,
+ rnp_op_verify_signature_t,
+ rnp_signature_handle_t,
+ rnp_recipient_handle_t,
+ rnp_symenc_handle_t,
+
+ RNP_LOAD_SAVE_PUBLIC_KEYS: 1,
+ RNP_LOAD_SAVE_SECRET_KEYS: 2,
+ RNP_LOAD_SAVE_PERMISSIVE: 256,
+
+ RNP_KEY_REMOVE_PUBLIC: 1,
+ RNP_KEY_REMOVE_SECRET: 2,
+ RNP_KEY_REMOVE_SUBKEYS: 4,
+
+ RNP_KEY_EXPORT_ARMORED: 1,
+ RNP_KEY_EXPORT_PUBLIC: 2,
+ RNP_KEY_EXPORT_SECRET: 4,
+ RNP_KEY_EXPORT_SUBKEYS: 8,
+
+ RNP_KEY_SIGNATURE_NON_SELF_SIG: 4,
+
+ RNP_SUCCESS: 0x00000000,
+
+ RNP_FEATURE_SYMM_ALG: "symmetric algorithm",
+ RNP_FEATURE_HASH_ALG: "hash algorithm",
+ RNP_FEATURE_PK_ALG: "public key algorithm",
+ RNP_ALGNAME_MD5: "MD5",
+ RNP_ALGNAME_SHA1: "SHA1",
+ RNP_ALGNAME_SM2: "SM2",
+ RNP_ALGNAME_SM3: "SM3",
+ RNP_ALGNAME_SM4: "SM4",
+
+ RNP_SECURITY_OVERRIDE: 1,
+ RNP_SECURITY_VERIFY_KEY: 2,
+ RNP_SECURITY_VERIFY_DATA: 4,
+ RNP_SECURITY_REMOVE_ALL: 65536,
+
+ RNP_SECURITY_PROHIBITED: 0,
+ RNP_SECURITY_INSECURE: 1,
+ RNP_SECURITY_DEFAULT: 2,
+
+ RNP_ENCRYPT_NOWRAP: 1,
+
+ /* Common error codes */
+ RNP_ERROR_GENERIC: 0x10000000, // 268435456
+ RNP_ERROR_BAD_FORMAT: 0x10000001, // 268435457
+ RNP_ERROR_BAD_PARAMETERS: 0x10000002, // 268435458
+ RNP_ERROR_NOT_IMPLEMENTED: 0x10000003, // 268435459
+ RNP_ERROR_NOT_SUPPORTED: 0x10000004, // 268435460
+ RNP_ERROR_OUT_OF_MEMORY: 0x10000005, // 268435461
+ RNP_ERROR_SHORT_BUFFER: 0x10000006, // 268435462
+ RNP_ERROR_NULL_POINTER: 0x10000007, // 268435463
+
+ /* Storage */
+ RNP_ERROR_ACCESS: 0x11000000, // 285212672
+ RNP_ERROR_READ: 0x11000001, // 285212673
+ RNP_ERROR_WRITE: 0x11000002, // 285212674
+
+ /* Crypto */
+ RNP_ERROR_BAD_STATE: 0x12000000, // 301989888
+ RNP_ERROR_MAC_INVALID: 0x12000001, // 301989889
+ RNP_ERROR_SIGNATURE_INVALID: 0x12000002, // 301989890
+ RNP_ERROR_KEY_GENERATION: 0x12000003, // 301989891
+ RNP_ERROR_BAD_PASSWORD: 0x12000004, // 301989892
+ RNP_ERROR_KEY_NOT_FOUND: 0x12000005, // 301989893
+ RNP_ERROR_NO_SUITABLE_KEY: 0x12000006, // 301989894
+ RNP_ERROR_DECRYPT_FAILED: 0x12000007, // 301989895
+ RNP_ERROR_RNG: 0x12000008, // 301989896
+ RNP_ERROR_SIGNING_FAILED: 0x12000009, // 301989897
+ RNP_ERROR_NO_SIGNATURES_FOUND: 0x1200000a, // 301989898
+
+ RNP_ERROR_SIGNATURE_EXPIRED: 0x1200000b, // 301989899
+
+ /* Parsing */
+ RNP_ERROR_NOT_ENOUGH_DATA: 0x13000000, // 318767104
+ RNP_ERROR_UNKNOWN_TAG: 0x13000001, // 318767105
+ RNP_ERROR_PACKET_NOT_CONSUMED: 0x13000002, // 318767106
+ RNP_ERROR_NO_USERID: 0x13000003, // 318767107
+ RNP_ERROR_EOF: 0x13000004, // 318767108
+ };
+}