wiktor-k / pysequoia

OpenPGP in Python using Sequoia PGP
https://pypi.org/project/pysequoia/
Apache License 2.0
9 stars 2 forks source link

Private Key with password causes: pyo3_runtime.PanicException: called `Option::unwrap()` on a `None` value #2

Closed vollkorn1982 closed 1 year ago

vollkorn1982 commented 1 year ago

I did the following to setup pysequoia:

I exported a secret key to a file called sender.asc like this:

gpg --armor --export-secret-key <fingerprint> > sender.asc

And a public key like this:

gpg --armor --export <other fingerprint> > recipient.asc

Then I did the following setup steps. Download files from https://pypi.org/project/pysequoia/#files

tar -xvzf pysequoia-0.1.11.tar.gz
python3 -m venv .env
source .env/bin/activate
pip install maturin[patchelf]
cd pysequoia-0.1.11/
maturin develop  # finishes without error

I copy-pasted the demo code in a file named minimal_test_case.py like this:

from pysequoia import Cert, Context

s = Cert.from_file("sender.asc")
r = Cert.from_bytes(open("recipient.asc", "rb").read())
encrypted = Context.standard().encrypt(s, r, "content to encrypt")
print(f"Encrypted data: {encrypted}")

And ran it like this, but it fails:

% RUST_BACKTRACE=full python minimal_test_case.py                                      
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:422:10
stack backtrace:
   0:     0x7fbaf6b8191d - std::backtrace_rs::backtrace::libunwind::trace::h8217d0a8f3fd2f41
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x7fbaf6b8191d - std::backtrace_rs::backtrace::trace_unsynchronized::h308103876b3af410
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x7fbaf6b8191d - std::sys_common::backtrace::_print_fmt::hc208018c6153605e
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:66:5
   3:     0x7fbaf6b8191d - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hf89a7ed694dfb585
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:45:22
   4:     0x7fbaf6ba1d8c - core::fmt::write::h21038c1382fe4264
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/fmt/mod.rs:1197:17
   5:     0x7fbaf6b7cbe1 - std::io::Write::write_fmt::h7dbb1c9a3c254aef
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/io/mod.rs:1672:15
   6:     0x7fbaf6b83095 - std::sys_common::backtrace::_print::h4e8889719c9ddeb8
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:48:5
   7:     0x7fbaf6b83095 - std::sys_common::backtrace::print::h1506fe2cb3022667
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:35:9
   8:     0x7fbaf6b83095 - std::panicking::default_hook::{{closure}}::hd9d7ce2a8a782440
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:295:22
   9:     0x7fbaf6b82db6 - std::panicking::default_hook::h5b16ec25444b1b5d
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:314:9
  10:     0x7fbaf6b83626 - std::panicking::rust_panic_with_hook::hb0138cb6e6fea3e4
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:698:17
  11:     0x7fbaf6b834d9 - std::panicking::begin_panic_handler::{{closure}}::h4cb67095557cd1aa
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:586:13
  12:     0x7fbaf6b81dd4 - std::sys_common::backtrace::__rust_end_short_backtrace::h2bfcac279dcdc911
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:138:18
  13:     0x7fbaf6b83249 - rust_begin_unwind
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:584:5
  14:     0x7fbaf5fc6ed3 - core::panicking::panic_fmt::h1de71520faaa17d3
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/panicking.rs:142:14
  15:     0x7fbaf5fc6d9d - core::panicking::panic::h467ee1bf554babeb
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/panicking.rs:48:5
  16:     0x7fbaf6064295 - core::option::Option<T>::unwrap::h77fc95d20dc76962
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/option.rs:775:21
  17:     0x7fbaf602e895 - pysequoia::encrypt_for::h2a260e67e6f38090
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.11/src/lib.rs:413:24
  18:     0x7fbaf5fce8d7 - pysequoia::Context::encrypt::hfcdbeb07f8e4c2c8
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.11/src/lib.rs:183:9
  19:     0x7fbaf6032f54 - pysequoia::_::<impl pysequoia::Context>::__pymethod_encrypt__::{{closure}}::h9a0754f163b3f3d4
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.11/src/lib.rs:168:1
  20:     0x7fbaf5ff5bb0 - std::panicking::try::do_call::h13d762b9bcaf9d8d
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:492:40
  21:     0x7fbaf5ffa74b - __rust_try
  22:     0x7fbaf5ff3c06 - std::panicking::try::ha055326381e54c20
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:456:19
  23:     0x7fbaf5ffe758 - std::panic::catch_unwind::h99c32f221df2de43
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panic.rs:137:14
  24:     0x7fbaf5fceb4c - pysequoia::_::<impl pysequoia::Context>::__pymethod_encrypt__::h208e3e5d91acac13
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.11/src/lib.rs:168:1
  25:     0x557b6be97f7e - <unknown>
  26:     0x557b6be6014a - _PyEval_EvalFrameDefault
  27:     0x557b6be5c766 - <unknown>
  28:     0x557b6bf54456 - PyEval_EvalCode
  29:     0x557b6bf80f08 - <unknown>
  30:     0x557b6bf79d5b - <unknown>
  31:     0x557b6bf80c55 - <unknown>
  32:     0x557b6bf80138 - _PyRun_SimpleFileObject
  33:     0x557b6bf7fe33 - _PyRun_AnyFileObject
  34:     0x557b6bf710ae - Py_RunMain
  35:     0x557b6bf4734d - Py_BytesMain
  36:     0x7fbaf788ad90 - __libc_start_call_main
                               at ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
  37:     0x7fbaf788ae40 - __libc_start_main_impl
                               at ./csu/../csu/libc-start.c:392:3
  38:     0x557b6bf47245 - _start
  39:                0x0 - <unknown>
Traceback (most recent call last):
  File "/home/jan/Projekte/pysequoia/minimal_test_case.py", line 5, in <module>
    encrypted = Context.standard().encrypt(s, r, "content to encrypt")
pyo3_runtime.PanicException: called `Option::unwrap()` on a `None` value

The error is the same when I install pysequoia via pip.

Am I doing something wrong? Or is this a bug?

wiktor-k commented 1 year ago

Sounds very much like a bug. Thanks for the instructions I'll replicate it locally and fix it.

Just for the record: I hope you are aware that the API is in flux and may change at any time? :)

Edit: On first sight it seems the key may be password protected and currently pysequoia expects keys without password protection. That will be addressed in the future.

vollkorn1982 commented 1 year ago

Thanks for looking into it. Yes, I am aware this is a very early stage, but I've been waiting since about the inception of sequoia for Python Bindings and am willing to rewrite my code a few times. Regard me as an early adopter, who'll happily help you with testing your project and sending bug reports etc. along the way.

wiktor-k commented 1 year ago

Great to hear that!

Just out of curiosity do you already have a use case in mind? We've got a couple of features in the pipeline but are always happy to look at what real users would need...

vollkorn1982 commented 1 year ago

I want to use it for the mailer part of a membership management application we use in the Chaos Computer Club. We have quite a few members who use PGP and would like to receive encrypted mails. I could use a project like Kuverto, but I want better integration for managing keys of members. I want the software to fetch, store, and read keys and send custom error messages, when a key does not work for some reason. Also, I want the code to be very efficient, because we may be sending thousands of mails in a single day. So I am looking into multiprocessing and async programming.

So far I believe most of my use cases are covered with the current API described at https://pypi.org/project/pysequoia/

What I am not yet sure how to do is how to check the validity of a key. What if a key is revoked, expired, or unusable in any other way? How can I find that out (and send a error message to the recipient)?

vollkorn1982 commented 1 year ago

Hi @wiktor-k, I tested version 0.1.12 from PyPI, but the problem is still the same:

RUST_BACKTRACE=full python minimal_test_case.py
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:422:10
stack backtrace:
   0:     0x7fe6201ca22d - std::backtrace_rs::backtrace::libunwind::trace::h8217d0a8f3fd2f41
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x7fe6201ca22d - std::backtrace_rs::backtrace::trace_unsynchronized::h308103876b3af410
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x7fe6201ca22d - std::sys_common::backtrace::_print_fmt::hc208018c6153605e
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:66:5
   3:     0x7fe6201ca22d - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hf89a7ed694dfb585
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:45:22
   4:     0x7fe6201ea66c - core::fmt::write::h21038c1382fe4264
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/fmt/mod.rs:1197:17
   5:     0x7fe6201c54f1 - std::io::Write::write_fmt::h7dbb1c9a3c254aef
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/io/mod.rs:1672:15
   6:     0x7fe6201cb9a5 - std::sys_common::backtrace::_print::h4e8889719c9ddeb8
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:48:5
   7:     0x7fe6201cb9a5 - std::sys_common::backtrace::print::h1506fe2cb3022667
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:35:9
   8:     0x7fe6201cb9a5 - std::panicking::default_hook::{{closure}}::hd9d7ce2a8a782440
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:295:22
   9:     0x7fe6201cb6c6 - std::panicking::default_hook::h5b16ec25444b1b5d
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:314:9
  10:     0x7fe6201cbf36 - std::panicking::rust_panic_with_hook::hb0138cb6e6fea3e4
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:698:17
  11:     0x7fe6201cbde9 - std::panicking::begin_panic_handler::{{closure}}::h4cb67095557cd1aa
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:586:13
  12:     0x7fe6201ca6e4 - std::sys_common::backtrace::__rust_end_short_backtrace::h2bfcac279dcdc911
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/sys_common/backtrace.rs:138:18
  13:     0x7fe6201cbb59 - rust_begin_unwind
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:584:5
  14:     0x7fe61f4f8ea3 - core::panicking::panic_fmt::h1de71520faaa17d3
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/panicking.rs:142:14
  15:     0x7fe61f4f8d6d - core::panicking::panic::h467ee1bf554babeb
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/panicking.rs:48:5
  16:     0x7fe61f594445 - core::option::Option<T>::unwrap::h3b1a3a66b47b87e8
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/option.rs:775:21
  17:     0x7fe61f54f105 - pysequoia::encrypt_for::h7531509fd4750f41
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.12/src/lib.rs:413:24
  18:     0x7fe61f55eb97 - pysequoia::Context::encrypt::hf4f313356aa7a21e
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.12/src/lib.rs:183:9
  19:     0x7fe61f5537c4 - pysequoia::_::<impl pysequoia::Context>::__pymethod_encrypt__::{{closure}}::h10a8e2cd46e49d51
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.12/src/lib.rs:168:1
  20:     0x7fe61f52ec20 - std::panicking::try::do_call::hcf6ede9284f014af
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:492:40
  21:     0x7fe61f531ecb - __rust_try
  22:     0x7fe61f528a56 - std::panicking::try::h16dde3ad569341e8
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:456:19
  23:     0x7fe61f54aaa8 - std::panic::catch_unwind::h7047c3700816f519
                               at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panic.rs:137:14
  24:     0x7fe61f55ee0c - pysequoia::_::<impl pysequoia::Context>::__pymethod_encrypt__::h7a5aa14f5be61582
                               at /home/jan/Projekte/pysequoia/pysequoia-0.1.12/src/lib.rs:168:1
  25:     0x55a0151bbf7e - <unknown>
  26:     0x55a01518414a - _PyEval_EvalFrameDefault
  27:     0x55a015180766 - <unknown>
  28:     0x55a015278456 - PyEval_EvalCode
  29:     0x55a0152a4f08 - <unknown>
  30:     0x55a01529dd5b - <unknown>
  31:     0x55a0152a4c55 - <unknown>
  32:     0x55a0152a4138 - _PyRun_SimpleFileObject
  33:     0x55a0152a3e33 - _PyRun_AnyFileObject
  34:     0x55a0152950ae - Py_RunMain
  35:     0x55a01526b34d - Py_BytesMain
  36:     0x7fe620f21d90 - __libc_start_call_main
                               at ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
  37:     0x7fe620f21e40 - __libc_start_main_impl
                               at ./csu/../csu/libc-start.c:392:3
  38:     0x55a01526b245 - _start
  39:                0x0 - <unknown>
Traceback (most recent call last):
  File "/home/jan/Projekte/pysequoia/minimal_test_case.py", line 5, in <module>
    encrypted = Context.standard().encrypt(s, r, "content to encrypt")
pyo3_runtime.PanicException: called `Option::unwrap()` on a `None` value
vollkorn1982 commented 1 year ago

I think I figured out the problem. I checked the source at src/lib.rs:422:10:

    let signing_cert = signing_cert
        .cert
        .keys()
        .unencrypted_secret()
        .with_policy(policy, None)
        .alive()
        .revoked(false)
        .for_signing()
        .next()
        .unwrap()
        .key()
        .clone()
        .into_keypair()?;

.unencrypted_secret() reads to me as if only keys whitouth a password are supported right now. So I generated a test key without a password and this worked.

wiktor-k commented 1 year ago

Great to hear! BTW I think my edit didn't reach you as I suggested just that: https://github.com/wiktor-k/pysequoia/issues/2#issuecomment-1425435485

vollkorn1982 commented 1 year ago

Ah, indeed. I neither noticed the edit nor got a notification.