diff --git a/.github/workflows/before-script-linux.sh b/.github/workflows/before-script-linux.sh deleted file mode 100755 index 1189403..0000000 --- a/.github/workflows/before-script-linux.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash - -set -euxo pipefail - -if [ -f /usr/bin/yum ]; then - echo Manylinux2010 build - - #yum install -y centos-release-scl llvm-toolset-7 flex - - #source /opt/rh/llvm-toolset-7/enable - - PREFIX=/ - - # Need to download from mirror because of: https://www.theregister.com/2023/06/28/microsofts_github_gmp_project/ - # See: https://ftp.gnu.org/gnu/gmp/ - GMP_VERSION=6.3.0 - - # See: https://ftp.gnu.org/gnu/nettle/ - NETTLE_VERSION=3.9.1 - - # See: https://pcsclite.apdu.fr/files/ - PCSCLITE_VERSION=2.0.1 - - cd /tmp && - curl --fail -sSL -O https://pcsclite.apdu.fr/files/pcsc-lite-${PCSCLITE_VERSION}.tar.bz2 && \ - tar xf pcsc-lite-${PCSCLITE_VERSION}.tar.bz2 && \ - cd pcsc-lite-${PCSCLITE_VERSION} && \ - ./configure --prefix=$PREFIX \ - --disable-libsystemd \ - --disable-libudev \ - --disable-libusb \ - --disable-polkit \ - --enable-filter \ - --enable-ipcdir=/run/pcscd \ - --enable-usbdropdir=/usr/lib/pcsc/drivers && \ - make && make install - - cd /tmp && \ - curl --fail -sSL -O https://ftp.gnu.org/gnu/gmp/gmp-${GMP_VERSION}.tar.bz2 && \ - tar xf gmp-${GMP_VERSION}.tar.bz2 && \ - cd gmp-${GMP_VERSION} && \ - ./configure --prefix=$PREFIX && \ - make && make install - - cd /tmp && - curl --fail -sSL -O https://ftp.gnu.org/gnu/nettle/nettle-${NETTLE_VERSION}.tar.gz && \ - tar xf nettle-${NETTLE_VERSION}.tar.gz && \ - cd nettle-${NETTLE_VERSION} && \ - ./configure --prefix=$PREFIX \ - --with-lib-path=$PREFIX/lib \ - --with-include-path=$PREFIX/include \ - --disable-openssl && \ - make && make install - -else - echo Manylinux2020 build - sudo apt-get update - sudo apt-get install -yqq cargo clang git nettle-dev pkg-config libssl-dev openssl libpcsclite-dev llvm gcc-multilib libgmp-dev libgmp3-dev -fi diff --git a/Cargo.lock b/Cargo.lock index 74fc4de..858a699 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,12 +116,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -188,27 +182,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "card-backend" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd3ee3a298842065dc489180c34a4fe4bbbb8643bb422009d79558a099fb42e5" -dependencies = [ - "thiserror", -] - -[[package]] -name = "card-backend-pcsc" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bb0b707b1b6b058ed93abd70ef65703ed6fd4150d32a0d735b78cfa61cbb35" -dependencies = [ - "card-backend", - "iso7816-tlv", - "log", - "pcsc", -] - [[package]] name = "cast5" version = "0.11.1" @@ -373,17 +346,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "pem-rfc7468 0.6.0", - "zeroize", -] - [[package]] name = "der" version = "0.7.9" @@ -391,7 +353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", - "pem-rfc7468 0.7.0", + "pem-rfc7468", "zeroize", ] @@ -457,7 +419,7 @@ dependencies = [ "digest", "num-bigint-dig", "num-traits", - "pkcs8 0.10.2", + "pkcs8", "rfc6979", "sha2", "signature", @@ -498,12 +460,12 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.7.9", + "der", "digest", "elliptic-curve", "rfc6979", "signature", - "spki 0.7.3", + "spki", ] [[package]] @@ -512,7 +474,7 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8 0.10.2", + "pkcs8", "signature", ] @@ -550,8 +512,8 @@ dependencies = [ "generic-array 0.14.7", "group", "hkdf", - "pem-rfc7468 0.7.0", - "pkcs8 0.10.2", + "pem-rfc7468", + "pkcs8", "rand_core", "sec1", "subtle", @@ -667,12 +629,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-slice" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a308e0214554f07a81d8944abe45f552871c12e3c3c6e7e5d354039a6c4c" - [[package]] name = "hkdf" version = "0.12.4" @@ -888,15 +844,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "iso7816-tlv" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7660d28d24a831d690228a275d544654a30f3b167a8e491cf31af5fe5058b546" -dependencies = [ - "untrusted", -] - [[package]] name = "itertools" version = "0.11.0" @@ -972,7 +919,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", ] @@ -1029,28 +976,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -1110,53 +1041,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "openpgp-card" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4e4e4146cf765e416a6c73e6bef6a4aa4cb12a76d9ef24c8c170eba4e4384ca" -dependencies = [ - "card-backend", - "chrono", - "hex-slice", - "log", - "nom", - "thiserror", -] - -[[package]] -name = "openpgp-card" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e80b16bc0178ae2c4af372c986721385ddee2df4b9622612911b5f4e3ffb4c1" -dependencies = [ - "card-backend", - "chrono", - "hex-slice", - "log", - "nom", - "secrecy", - "sha2", - "thiserror", -] - -[[package]] -name = "openpgp-card-sequoia" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0835400374822b27054b7a6606770f4a48b9255ad800a098f1d242d8695b4f22" -dependencies = [ - "anyhow", - "card-backend", - "chrono", - "log", - "openpgp-card 0.4.2", - "rsa 0.8.2", - "sequoia-openpgp", - "sha2", - "thiserror", -] - [[package]] name = "p256" version = "0.13.2" @@ -1218,34 +1102,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "pcsc" -version = "2.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ed9d7f816b7d9ce9ddb0062dd2f393b3af31411a95a35411809b4b9116ea08" -dependencies = [ - "bitflags 1.3.2", - "pcsc-sys", -] - -[[package]] -name = "pcsc-sys" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09e9ba80f2c4d167f936d27594f7248bca3295921ffbfa44a24b339b6cb7403" -dependencies = [ - "pkg-config", -] - -[[package]] -name = "pem-rfc7468" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" -dependencies = [ - "base64ct", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1274,37 +1130,15 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pkcs1" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" -dependencies = [ - "der 0.6.1", - "pkcs8 0.9.0", - "spki 0.6.0", - "zeroize", -] - [[package]] name = "pkcs1" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der 0.7.9", - "pkcs8 0.10.2", - "spki 0.7.3", -] - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", + "der", + "pkcs8", + "spki", ] [[package]] @@ -1313,16 +1147,10 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.9", - "spki 0.7.3", + "der", + "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - [[package]] name = "polyval" version = "0.6.2" @@ -1444,12 +1272,9 @@ name = "pysequoia" version = "0.1.24" dependencies = [ "anyhow", - "card-backend-pcsc", "chrono", "hex", "once_cell", - "openpgp-card 0.5.0", - "openpgp-card-sequoia", "pyo3", "sequoia-openpgp", "testresult", @@ -1499,7 +1324,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -1561,26 +1386,6 @@ dependencies = [ "digest", ] -[[package]] -name = "rsa" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" -dependencies = [ - "byteorder", - "digest", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1 0.4.1", - "pkcs8 0.9.0", - "rand_core", - "signature", - "subtle", - "zeroize", -] - [[package]] name = "rsa" version = "0.9.6" @@ -1592,11 +1397,11 @@ dependencies = [ "num-bigint-dig", "num-integer", "num-traits", - "pkcs1 0.7.5", - "pkcs8 0.10.2", + "pkcs1", + "pkcs8", "rand_core", "signature", - "spki 0.7.3", + "spki", "subtle", "zeroize", ] @@ -1638,22 +1443,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", - "der 0.7.9", + "der", "generic-array 0.14.7", - "pkcs8 0.10.2", + "pkcs8", "subtle", "zeroize", ] -[[package]] -name = "secrecy" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" -dependencies = [ - "zeroize", -] - [[package]] name = "semver" version = "1.0.23" @@ -1706,7 +1502,7 @@ dependencies = [ "regex", "regex-syntax", "ripemd", - "rsa 0.9.6", + "rsa", "sha1collisiondetection", "sha2", "thiserror", @@ -1792,16 +1588,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - [[package]] name = "spki" version = "0.7.3" @@ -1809,7 +1595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der 0.7.9", + "der", ] [[package]] @@ -1964,12 +1750,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "utf16_iter" version = "1.0.5" diff --git a/Cargo.toml b/Cargo.toml index 071d1c2..883da28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,12 +17,9 @@ crate-type = ["cdylib"] [dependencies] anyhow = "1" -card-backend-pcsc = "0.5" chrono = "0.4" hex = "0.4.3" once_cell = "1.20" -openpgp-card = "0.5.0" -openpgp-card-sequoia = { version = "0.2.2", default-features = false } testresult = "0.4" sequoia-openpgp = { version = "1", default-features = false, features = [ "crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"] } diff --git a/NEXT.md b/NEXT.md index 187b634..7e323f5 100644 --- a/NEXT.md +++ b/NEXT.md @@ -1,16 +1,12 @@ # Next version changes ## This file contains changes that will be included in the next version that is released -v0.1.24 +v0.1.25 New: - - `Sig` - new class exposing signature related functions: - - `Sig.from_file` - read detached signature from file, - - `Sig.from_bytes` - read detached signature from bytes, - - `sig.issuer_fpr` - fingerprint of the issuer (may be `None`), - - `sig.created` - date and time when the signature was issued, Changed: Removed: + - `Card` - OpenPGP Card features removed as they are complex to build for multiple architectures and `openpgp-card-sequoia` is deprecated. ### git tag --edit -s -F NEXT.md v... diff --git a/README.md b/README.md index 65ca11d..d2c8414 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ toolchain][RUSTUP] is necessary for the installation to succeed. This entire document is used for end-to-end integration tests that exercise the package's API surface. -The tests assume that these keys and cards exist: +The tests assume that these keys exist: ```bash # generate a key with password @@ -56,17 +56,6 @@ gpg --batch --pinentry-mode loopback --passphrase hunter22 --export-secret-key p # generate a key without password gpg --batch --pinentry-mode loopback --passphrase '' --quick-gen-key no-passwd@example.com future-default gpg --batch --pinentry-mode loopback --passphrase '' --export-secret-key no-passwd@example.com > no-passwd.pgp - -# initialize dummy OpenPGP Card -sh /start.sh -echo 12345678 > pin -CARD_ADMIN="opgpcard admin --card 0000:00000000 --admin-pin pin" -$CARD_ADMIN import full-key.asc -$CARD_ADMIN name "John Doe" -$CARD_ADMIN url "https://example.com/key.pgp" -$CARD_ADMIN touch --key SIG --policy Fixed -$CARD_ADMIN touch --key DEC --policy Off -$CARD_ADMIN touch --key AUT --policy Fixed ``` ## Functions @@ -442,81 +431,6 @@ assert sig.issuer_fpr == "e8f23996f23218640cb44cbe75cf5ac418b8e74c" assert sig.created == datetime.fromisoformat("2023-07-19T18:14:01+00:00") ``` -## OpenPGP Cards - -There's an experimental feature allowing communication with OpenPGP -Cards (like YubiKey or Nitrokey). - -```python -from pysequoia import Card - -# enumerate all cards -all = Card.all() - -# open card by card ident -card = Card.open("0000:00000000") - -print(f"Card ident: {card.ident}") -assert card.cardholder == "John Doe" -assert card.cert_url == "https://example.com/key.pgp" -``` - -Cards provide `keys` property that can be used to see which keys are imported -on the card: - -```python -keys = card.keys -print(f"Keys: {keys}") -assert len(keys) == 3 - -assert keys[0].fingerprint == "ddc3e03c91fb52ca2d95c2444566f2743ed5f382" -assert "sign" in keys[0].usage -assert keys[0].touch_required - -assert keys[1].fingerprint == "689e152a7420be13dcaf2c142ac27adc1db9395e" -assert "decrypt" in keys[1].usage -assert not keys[1].touch_required - -assert keys[2].fingerprint == "731fbca93ce9821347bf8e696444723371d3c650" -assert "authenticate" in keys[2].usage -assert keys[2].touch_required -``` - - -Cards can be used for signing data: - -```python -signer = card.signer("123456") - -signed = sign(signer, "data to be signed".encode("utf8")) -print(f"Signed data: {signed}") -``` - -As well as for decryption: - -```python -decryptor = card.decryptor("123456") - -sender = Cert.from_file("passwd.pgp") -receiver = Cert.from_file("full-key.asc") - -content = "Red Green Blue" - -encrypted = encrypt(signer = sender.secrets.signer("hunter22"), recipients = [receiver], bytes = content.encode("utf8")) - -print(f"Encrypted data: {encrypted}") - -decrypted = decrypt(decryptor = decryptor, bytes = encrypted) - -assert content == decrypted.bytes.decode("utf8"); -``` - -Note that while this package allows using cards for signing and -decryption, the provisioning process is not supported. [OpenPGP card -tools][] can be used to initialize the card. - -[OpenPGP card tools]: https://crates.io/crates/openpgp-card-tools - ## License This project is licensed under [Apache License, Version 2.0][APL]. diff --git a/ci/build.dockerfile b/ci/build.dockerfile index 6a74fb2..9fd11e8 100644 --- a/ci/build.dockerfile +++ b/ci/build.dockerfile @@ -4,7 +4,7 @@ FROM debian ARG RUST_TOOLCHAIN=stable RUN apt-get update -y -qq && \ - apt-get install -y -qq --no-install-recommends curl python3 python3-venv clang make pkg-config nettle-dev libssl-dev ca-certificates pip pcscd libpcsclite-dev codespell > /dev/null && \ + apt-get install -y -qq --no-install-recommends curl python3 python3-venv clang make pkg-config nettle-dev libssl-dev ca-certificates pip codespell > /dev/null && \ apt-get clean ENV RUSTUP_HOME=/usr/local/rustup \ diff --git a/ci/e2e.dockerfile b/ci/e2e.dockerfile index f92e4ad..5011ae2 100644 --- a/ci/e2e.dockerfile +++ b/ci/e2e.dockerfile @@ -1,9 +1,9 @@ -FROM registry.gitlab.com/openpgp-card/virtual-cards/opcard-rs-tools +FROM rust RUN apt-get update -y -qq && \ - apt-get install -y -qq --no-install-recommends python-is-python3 python3-venv clang make pkg-config nettle-dev libssl-dev ca-certificates pip patchelf pcscd libpcsclite-dev && \ + apt-get install -y -qq --no-install-recommends python-is-python3 python3-venv clang make pkg-config libssl-dev ca-certificates pip patchelf && \ apt-get clean -RUN cargo install --locked tangler openpgp-card-tools +RUN cargo install --locked tangler COPY . /build WORKDIR /build diff --git a/package.nix b/package.nix index 37a876e..573ba16 100644 --- a/package.nix +++ b/package.nix @@ -9,7 +9,6 @@ , bzip2 , nettle , openssl -, pcsclite , stdenv , darwin , libiconv @@ -42,11 +41,9 @@ buildPythonPackage rec { ] ++ lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.CoreFoundation darwin.apple_sdk.frameworks.Security - darwin.apple_sdk.frameworks.PCSC libiconv ] ++ lib.optionals stdenv.isLinux [ nettle - pcsclite ]; pythonImportsCheck = [ "pysequoia" ]; diff --git a/src/card.rs b/src/card.rs deleted file mode 100644 index 61b7d83..0000000 --- a/src/card.rs +++ /dev/null @@ -1,252 +0,0 @@ -use card_backend_pcsc::PcscBackend; -use openpgp_card_sequoia::state::Open; -use openpgp_card_sequoia::types::{Fingerprint, KeyType}; -use openpgp_card_sequoia::Card as CCard; -use pyo3::prelude::*; -use sequoia_openpgp as openpgp; - -use crate::decrypt; -use crate::signer::PySigner; - -#[pyclass] -pub struct Card { - open: CCard, -} - -#[pymethods] -impl Card { - #[staticmethod] - pub fn open(ident: &str) -> anyhow::Result { - let cards = PcscBackend::card_backends(None)?; - Ok(Self { - open: CCard::::open_by_ident(cards, ident)?, - }) - } - - #[getter] - pub fn cardholder(&mut self) -> anyhow::Result> { - let mut transaction = self.open.transaction()?; - Ok(transaction - .cardholder_related_data()? - .name() - .map(|name| String::from_utf8_lossy(name).into())) - } - - #[getter] - pub fn cert_url(&mut self) -> anyhow::Result { - let mut transaction = self.open.transaction()?; - Ok(transaction.url()?) - } - - #[getter] - pub fn ident(&mut self) -> anyhow::Result { - let transaction = self.open.transaction()?; - Ok(transaction.application_identifier()?.ident()) - } - - #[staticmethod] - pub fn all() -> anyhow::Result> { - // Need to suppress errors here to handle the case of - // no-readers being connected. This should be handled by the - // backend. - // - // See: https://gitlab.com/openpgp-card/openpgp-card/-/issues/6 - if let Ok(cards) = PcscBackend::cards(None) { - Ok(cards - .into_iter() - .filter_map(|card| card.ok()) - .filter_map(|card| CCard::::new(card).ok()) - .map(|open| Self { open }) - .collect()) - } else { - Ok(Vec::new()) - } - } - - pub fn signer(&mut self, pin: String) -> anyhow::Result { - use sequoia_openpgp::crypto::Signer; - - struct CardSigner { - public: openpgp::packet::Key< - openpgp::packet::key::PublicParts, - openpgp::packet::key::UnspecifiedRole, - >, - ident: String, - pin: String, - } - - impl openpgp::crypto::Signer for CardSigner { - fn public( - &self, - ) -> &openpgp::packet::Key< - openpgp::packet::key::PublicParts, - openpgp::packet::key::UnspecifiedRole, - > { - &self.public - } - - fn sign( - &mut self, - hash_algo: openpgp::types::HashAlgorithm, - digest: &[u8], - ) -> openpgp::Result { - let cards = PcscBackend::card_backends(None)?; - let mut card = CCard::::open_by_ident(cards, &self.ident)?; - let mut transaction = card.transaction()?; - - let mut user = transaction - .to_signing_card(Some(self.pin.as_bytes())) - .expect("This should not fail"); - - let mut signer = user.signer(&|| {})?; - signer.sign(hash_algo, digest) - } - } - - let public = { - let mut transaction = self.open.transaction()?; - - let mut user = transaction - .to_signing_card(Some(pin.as_bytes())) - .expect("This should not fail"); - - let signer = user.signer(&|| {})?; - signer.public().clone() - }; - Ok(PySigner::new(Box::new(CardSigner { - public, - ident: self.ident()?, - pin, - }))) - } - - pub fn decryptor(&mut self, pin: String) -> anyhow::Result { - use sequoia_openpgp::crypto::Decryptor; - - struct CardDecryptor { - public: openpgp::packet::Key< - openpgp::packet::key::PublicParts, - openpgp::packet::key::UnspecifiedRole, - >, - ident: String, - pin: String, - } - - impl openpgp::crypto::Decryptor for CardDecryptor { - fn public( - &self, - ) -> &openpgp::packet::Key< - openpgp::packet::key::PublicParts, - openpgp::packet::key::UnspecifiedRole, - > { - &self.public - } - fn decrypt( - &mut self, - ciphertext: &openpgp::crypto::mpi::Ciphertext, - plaintext_len: Option, - ) -> openpgp::Result { - let cards = PcscBackend::card_backends(None)?; - let mut card = CCard::::open_by_ident(cards, &self.ident)?; - let mut transaction = card.transaction()?; - - let mut user = transaction - .to_user_card(Some(self.pin.as_bytes())) - .expect("user_card should not fail"); - - let mut decryptor = user.decryptor(&|| {})?; - decryptor.decrypt(ciphertext, plaintext_len) - } - } - - let public = { - let mut transaction = self.open.transaction()?; - - let mut user = transaction - .to_user_card(Some(pin.as_bytes())) - .expect("user_card should not fail"); - - let decryptor = user.decryptor(&|| {})?; - decryptor.public().clone() - }; - Ok(decrypt::PyDecryptor::new(Box::new(CardDecryptor { - public, - ident: self.ident()?, - pin, - }))) - } - - pub fn __repr__(&mut self) -> anyhow::Result { - Ok(format!( - "", - self.ident()?, - self.cardholder()?, - self.cert_url()? - )) - } - - #[getter] - pub fn keys(&mut self) -> anyhow::Result> { - let transaction = self.open.transaction()?; - let card_keys = transaction.fingerprints()?; - let mut keys = Vec::with_capacity(3); - let mut append_key = |key: Option<&Fingerprint>, key_type: KeyType| { - if let Some(key) = key { - let usage = match key_type { - KeyType::Signing => Some("sign"), - KeyType::Decryption => Some("decrypt"), - KeyType::Authentication => Some("authenticate"), - _ => None, - } - .map(Into::into) - .into_iter() - .collect(); - keys.push(CardKey { - fingerprint: hex::encode(key.as_bytes()), - usage, - touch_required: transaction - .user_interaction_flag(key_type) - .unwrap_or_default() - .map(|uif| uif.touch_policy().touch_required()) - .unwrap_or_default(), - }) - } - }; - append_key(card_keys.signature(), KeyType::Signing); - append_key(card_keys.decryption(), KeyType::Decryption); - append_key(card_keys.authentication(), KeyType::Authentication); - Ok(keys) - } -} - -#[pyclass] -pub struct CardKey { - fingerprint: String, - usage: Vec, - touch_required: bool, -} - -#[pymethods] -impl CardKey { - #[getter] - fn fingerprint(&self) -> &String { - &self.fingerprint - } - - #[getter] - fn usage(&self) -> Vec { - self.usage.clone() - } - - #[getter] - fn touch_required(&self) -> bool { - self.touch_required - } - - pub fn __repr__(&self) -> String { - format!( - "", - self.fingerprint, self.usage, self.touch_required - ) - } -} diff --git a/src/lib.rs b/src/lib.rs index fc33007..a12faad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ use openpgp::parse::stream::GoodChecksum; use openpgp::serialize::stream::Armorer; use pyo3::prelude::*; -mod card; mod cert; mod decrypt; mod encrypt; @@ -94,7 +93,6 @@ impl Decrypted { #[pymodule] fn pysequoia(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; - m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_function(wrap_pyfunction!(sign::sign, m)?)?;