From a83a19555ae53027851dab83a4b81bf557c8c12d Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Tue, 17 Sep 2024 11:09:22 +0900 Subject: [PATCH 01/18] signature: add OpenPGP signing mechanism based on Sequoia This adds a new OpenPGP signing mechanism based Sequoia-PGP[1]. As Sequoia-PGP is written in Rust and doesn't provide a stable C FFI, this integration includes a minimal shared library as a "point solution". To build, first follow the instruction in signature/sequoia/README.md and install `libimage_sequoia.so*` into the library path, and then build with the following command from the top-level directory: $ make BUILDTAGS="btrfs_noversion containers_image_sequoia" Note also that, for testing on Fedora, crypto-policies settings might need to be modified to explictly allow SHA-1 and 1024 bit RSA, as the testing keys in signature/fixtures are using those legacy algorithms. 1. https://sequoia-pgp.org/ Signed-off-by: Daiki Ueno --- README.md | 1 + signature/internal/sequoia/gosequoia.c | 200 + signature/internal/sequoia/gosequoia.h | 54 + signature/internal/sequoia/gosequoiafuncs.h | 20 + signature/internal/sequoia/rust/Cargo.lock | 4490 +++++++++++++++++ signature/internal/sequoia/rust/Cargo.toml | 40 + signature/internal/sequoia/rust/README.md | 34 + signature/internal/sequoia/rust/build.rs | 121 + signature/internal/sequoia/rust/src/error.rs | 47 + signature/internal/sequoia/rust/src/lib.rs | 7 + .../internal/sequoia/rust/src/signature.rs | 433 ++ signature/internal/sequoia/sequoia.go | 155 + signature/internal/sequoia/sequoia.h | 73 + signature/internal/sequoia/sequoia_test.go | 228 + signature/mechanism_gpgme.go | 2 +- signature/mechanism_gpgme_test.go | 2 +- signature/mechanism_sequoia.go | 130 + signature/mechanism_test.go | 2 +- 18 files changed, 6036 insertions(+), 3 deletions(-) create mode 100644 signature/internal/sequoia/gosequoia.c create mode 100644 signature/internal/sequoia/gosequoia.h create mode 100644 signature/internal/sequoia/gosequoiafuncs.h create mode 100644 signature/internal/sequoia/rust/Cargo.lock create mode 100644 signature/internal/sequoia/rust/Cargo.toml create mode 100644 signature/internal/sequoia/rust/README.md create mode 100644 signature/internal/sequoia/rust/build.rs create mode 100644 signature/internal/sequoia/rust/src/error.rs create mode 100644 signature/internal/sequoia/rust/src/lib.rs create mode 100644 signature/internal/sequoia/rust/src/signature.rs create mode 100644 signature/internal/sequoia/sequoia.go create mode 100644 signature/internal/sequoia/sequoia.h create mode 100644 signature/internal/sequoia/sequoia_test.go create mode 100644 signature/mechanism_sequoia.go diff --git a/README.md b/README.md index f4aa9e2f96..88cdf256ea 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ or use the build tags described below to avoid the dependencies (e.g. using `go - `containers_image_docker_daemon_stub`: Don’t import the `docker-daemon:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. - `containers_image_openpgp`: Use a Golang-only OpenPGP implementation for signature verification instead of the default cgo/gpgme-based implementation; the primary downside is that creating new signatures with the Golang-only implementation is not supported. +- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations. This requires a support shared library installed on the system. Follow the instructions in [signature/sequoia/rust/README.md](signature/sequoia/rust/README.md). - `containers_image_storage_stub`: Don’t import the `containers-storage:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. - `containers_image_fulcio_stub`: Don't import sigstore/fulcio code, all fulcio operations will return an error code - `containers_image_rekor_stub`: Don't import sigstore/reckor code, all rekor operations will return an error code diff --git a/signature/internal/sequoia/gosequoia.c b/signature/internal/sequoia/gosequoia.c new file mode 100644 index 0000000000..d5314016a6 --- /dev/null +++ b/signature/internal/sequoia/gosequoia.c @@ -0,0 +1,200 @@ +/* + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gosequoia.h" + +#if defined(GO_SEQUOIA_ENABLE_DLOPEN) && GO_SEQUOIA_ENABLE_DLOPEN + +#include +#include +#include +#include + +/* If SEQUOIA_SONAME is defined, dlopen handle can be automatically + * set; otherwise, the caller needs to call + * go_sequoia_ensure_library with soname determined at run time. + */ +#ifdef SEQUOIA_SONAME + +static void +ensure_library (void) +{ + if (go_sequoia_ensure_library (SEQUOIA_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0) + abort (); +} + +#if defined(GO_SEQUOIA_ENABLE_PTHREAD) && GO_SEQUOIA_ENABLE_PTHREAD +#include + +static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT; + +#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library) + +#else /* GO_SEQUOIA_ENABLE_PTHREAD */ + +#define ENSURE_LIBRARY do { \ + if (!go_sequoia_dlhandle) \ + ensure_library(); \ + } while (0) + +#endif /* !GO_SEQUOIA_ENABLE_PTHREAD */ + +#else /* SEQUOIA_SONAME */ + +#define ENSURE_LIBRARY do {} while (0) + +#endif /* !SEQUOIA_SONAME */ + +static void *go_sequoia_dlhandle; + +/* Define redirection symbols */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" + +#if (2 <= __GNUC__ || (4 <= __clang_major__)) +#define FUNC(ret, name, args, cargs) \ + static __typeof__(name)(*go_sequoia_sym_##name); +#else +#define FUNC(ret, name, args, cargs) \ + static ret(*go_sequoia_sym_##name)args; +#endif +#define VOID_FUNC FUNC +#include "gosequoiafuncs.h" +#undef VOID_FUNC +#undef FUNC + +#pragma GCC diagnostic pop + +/* Define redirection wrapper functions */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" + +#define FUNC(ret, name, args, cargs) \ +ret go_##name args \ +{ \ + ENSURE_LIBRARY; \ + assert (go_sequoia_sym_##name); \ + return go_sequoia_sym_##name cargs; \ +} +#define VOID_FUNC(ret, name, args, cargs) \ +ret go_##name args \ +{ \ + ENSURE_LIBRARY; \ + assert (go_sequoia_sym_##name); \ + go_sequoia_sym_##name cargs; \ +} +#include "gosequoiafuncs.h" +#undef VOID_FUNC +#undef FUNC + +#pragma GCC diagnostic pop + +static int +ensure_symbol (const char *name, void **symp) +{ + if (!*symp) + { + void *sym = dlsym (go_sequoia_dlhandle, name); + if (!sym) + return -EINVAL; + *symp = sym; + } + return 0; +} + +int +go_sequoia_ensure_library (const char *soname, int flags) +{ + int err; + + if (!go_sequoia_dlhandle) + { + go_sequoia_dlhandle = dlopen (soname, flags); + if (!go_sequoia_dlhandle) + return -EINVAL; + } + +#define ENSURE_SYMBOL(name) \ + ensure_symbol(#name, (void **)&go_sequoia_sym_##name) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" + +#define FUNC(ret, name, args, cargs) \ + err = ENSURE_SYMBOL(name); \ + if (err < 0) \ + { \ + dlclose (go_sequoia_dlhandle); \ + go_sequoia_dlhandle = NULL; \ + return err; \ + } +#define VOID_FUNC FUNC +#include "gosequoiafuncs.h" +#undef VOID_FUNC +#undef FUNC + +#pragma GCC diagnostic pop + +#undef ENSURE_SYMBOL + return 0; +} + +void +go_sequoia_unload_library (void) +{ + if (go_sequoia_dlhandle) + { + dlclose (go_sequoia_dlhandle); + go_sequoia_dlhandle = NULL; + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" + +#define FUNC(ret, name, args, cargs) \ + go_sequoia_sym_##name = NULL; +#define VOID_FUNC FUNC +#include "gosequoiafuncs.h" +#undef VOID_FUNC +#undef FUNC + +#pragma GCC diagnostic pop +} + +unsigned +go_sequoia_is_usable (void) +{ + return go_sequoia_dlhandle != NULL; +} + +#else /* GO_SEQUOIA_ENABLE_DLOPEN */ + +int +go_sequoia_ensure_library (const char *soname, int flags) +{ + (void) soname; + (void) flags; + return 0; +} + +void +go_sequoia_unload_library (void) +{ +} + +unsigned +go_sequoia_is_usable (void) +{ + /* The library is linked at build time, thus always usable */ + return 1; +} + +#endif /* !GO_SEQUOIA_ENABLE_DLOPEN */ diff --git a/signature/internal/sequoia/gosequoia.h b/signature/internal/sequoia/gosequoia.h new file mode 100644 index 0000000000..477b985bad --- /dev/null +++ b/signature/internal/sequoia/gosequoia.h @@ -0,0 +1,54 @@ +/* + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + */ + +#ifndef GO_SEQUOIA_H_ +#define GO_SEQUOIA_H_ + +#include + +#if defined(GO_SEQUOIA_ENABLE_DLOPEN) && GO_SEQUOIA_ENABLE_DLOPEN + +#define FUNC(ret, name, args, cargs) \ + ret go_##name args; +#define VOID_FUNC FUNC +#include "gosequoiafuncs.h" +#undef VOID_FUNC +#undef FUNC + +#define GO_SEQUOIA_FUNC(name) go_##name + +#else + +#define GO_SEQUOIA_FUNC(name) name + +#endif /* GO_SEQUOIA_ENABLE_DLOPEN */ + +/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary + * symbols are resolved. + * + * Returns 0 on success; negative error code otherwise. + * + * Note that this function is NOT thread-safe; when calling it from + * multi-threaded programs, protect it with a locking mechanism. + */ +int go_sequoia_ensure_library (const char *soname, int flags); + +/* Unload library and reset symbols. + * + * Note that this function is NOT thread-safe; when calling it from + * multi-threaded programs, protect it with a locking mechanism. + */ +void go_sequoia_unload_library (void); + +/* Return 1 if the library is loaded and usable. + * + * Note that this function is NOT thread-safe; when calling it from + * multi-threaded programs, protect it with a locking mechanism. + */ +unsigned go_sequoia_is_usable (void); + +#endif /* GO_SEQUOIA_H_ */ diff --git a/signature/internal/sequoia/gosequoiafuncs.h b/signature/internal/sequoia/gosequoiafuncs.h new file mode 100644 index 0000000000..025bf1a80b --- /dev/null +++ b/signature/internal/sequoia/gosequoiafuncs.h @@ -0,0 +1,20 @@ +/* + * This file was automatically generated from sequoia.h, + * which is covered by the following license: + * SPDX-License-Identifier: Apache-2.0 + */ +VOID_FUNC(void, sequoia_error_free, (struct SequoiaError *err_ptr), (err_ptr)) +FUNC(struct SequoiaMechanism *, sequoia_mechanism_new_from_directory, (const char *dir_ptr, struct SequoiaError **err_ptr), (dir_ptr, err_ptr)) +FUNC(struct SequoiaMechanism *, sequoia_mechanism_new_ephemeral, (struct SequoiaError **err_ptr), (err_ptr)) +VOID_FUNC(void, sequoia_mechanism_free, (struct SequoiaMechanism *mechanism_ptr), (mechanism_ptr)) +VOID_FUNC(void, sequoia_signature_free, (struct SequoiaSignature *signature_ptr), (signature_ptr)) +FUNC(const uint8_t *, sequoia_signature_get_data, (const struct SequoiaSignature *signature_ptr, size_t *data_len), (signature_ptr, data_len)) +VOID_FUNC(void, sequoia_verification_result_free, (struct SequoiaVerificationResult *result_ptr), (result_ptr)) +FUNC(const uint8_t *, sequoia_verification_result_get_content, (const struct SequoiaVerificationResult *result_ptr, size_t *data_len), (result_ptr, data_len)) +FUNC(const char *, sequoia_verification_result_get_signer, (const struct SequoiaVerificationResult *result_ptr), (result_ptr)) +FUNC(struct SequoiaSignature *, sequoia_sign, (struct SequoiaMechanism *mechanism_ptr, const char *key_handle_ptr, const char *password_ptr, const uint8_t *data_ptr, size_t data_len, struct SequoiaError **err_ptr), (mechanism_ptr, key_handle_ptr, password_ptr, data_ptr, data_len, err_ptr)) +FUNC(struct SequoiaVerificationResult *, sequoia_verify, (struct SequoiaMechanism *mechanism_ptr, const uint8_t *signature_ptr, size_t signature_len, struct SequoiaError **err_ptr), (mechanism_ptr, signature_ptr, signature_len, err_ptr)) +VOID_FUNC(void, sequoia_import_result_free, (struct SequoiaImportResult *result_ptr), (result_ptr)) +FUNC(size_t, sequoia_import_result_get_count, (const struct SequoiaImportResult *result_ptr), (result_ptr)) +FUNC(const char *, sequoia_import_result_get_content, (const struct SequoiaImportResult *result_ptr, size_t index, struct SequoiaError **err_ptr), (result_ptr, index, err_ptr)) +FUNC(struct SequoiaImportResult *, sequoia_import_keys, (struct SequoiaMechanism *mechanism_ptr, const uint8_t *blob_ptr, size_t blob_len, struct SequoiaError **err_ptr), (mechanism_ptr, blob_ptr, blob_len, err_ptr)) diff --git a/signature/internal/sequoia/rust/Cargo.lock b/signature/internal/sequoia/rust/Cargo.lock new file mode 100644 index 0000000000..08ea903494 --- /dev/null +++ b/signature/internal/sequoia/rust/Cargo.lock @@ -0,0 +1,4490 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.7", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "async-generic" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf3728566eefa873833159754f5732fb0951d3649e6e5b891cc70d56dd41673" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.9.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.100", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +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.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "botan" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d4c7647d67c53194fa0740404c6c508880aef2bfe99a9868dbb4b86f090377" +dependencies = [ + "botan-sys", +] + +[[package]] +name = "botan-sys" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04285fa0c094cc9961fe435b1b279183db9394844ad82ce483aa6196c0e6da38" + +[[package]] +name = "buffered-reader" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db26bf1f092fd5e05b5ab3be2f290915aeb6f3f20c4e9f86ce0f07f336c2412f" +dependencies = [ + "bzip2", + "flate2", + "libc", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bzip2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +dependencies = [ + "bzip2-sys", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "capnp" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e985a566bdaae9a428a957d12b10c318d41b2afddb54cfbb764878059df636e" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "capnp-futures" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f3ee810b3890498e51028448ac732cdd5009223897124dd2fac6b085b5d867" +dependencies = [ + "capnp", + "futures", +] + +[[package]] +name = "capnp-rpc" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe57ab22a5e121e6fddaf36e837514aab9ae888bcff2baa6fda5630820dfc501" +dependencies = [ + "capnp", + "capnp-futures", + "futures", +] + +[[package]] +name = "capnpc" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ba30e0f08582d53c2f3710cf4bb65ff562614b1ba86906d7391adffe189ec" +dependencies = [ + "capnp", +] + +[[package]] +name = "cast5" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" +dependencies = [ + "cipher", +] + +[[package]] +name = "cbindgen" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d" +dependencies = [ + "clap 3.2.25", + "heck 0.4.1", + "indexmap 1.9.3", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 1.0.109", + "tempfile", + "toml", +] + +[[package]] +name = "cc" +version = "1.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +dependencies = [ + "shlex", +] + +[[package]] +name = "cdylib-link-lines" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98eabef08bbdf5afd0b9c0cabb1ac335f7c70447ef095eed85dffd9628b20bc" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clang" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c044c781163c001b913cd018fc95a628c50d0d2dfea8bca77dad71edb16e37" +dependencies = [ + "clang-sys", + "libc", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "strsim 0.10.0", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap" +version = "4.5.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex 0.7.4", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "cmac" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" +dependencies = [ + "cipher", + "dbl", + "digest", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "rand_core", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "data-encoding" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" + +[[package]] +name = "dbl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys 0.5.0", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.4.6", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users 0.4.6", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "dlwrap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76810e38c6f0f7195a0cac883d832ad514036777490d81d48665d66314debee5" +dependencies = [ + "anyhow", + "clang", + "clang-sys", + "clap 4.5.35", + "regex", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dsa" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" +dependencies = [ + "digest", + "num-bigint-dig", + "num-traits", + "pkcs8", + "rfc6979", + "sha2", + "signature", + "zeroize", +] + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "eax" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" +dependencies = [ + "aead", + "cipher", + "cmac", + "ctr", + "subtle", +] + +[[package]] +name = "ecb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7" +dependencies = [ + "cipher", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array 0.14.7", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if", + "rustix 1.0.5", + "windows-sys 0.59.0", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "generic-array" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c8444bc9d71b935156cc0ccab7f622180808af7867b1daae6547d773591703" +dependencies = [ + "typenum", +] + +[[package]] +name = "gethostname" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" +dependencies = [ + "rustix 0.38.44", + "windows-targets 0.52.6", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.9.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hickory-client" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156579a5cd8d1fc6f0df87cc21b6ee870db978a163a1ba484acd98a4eff5a6de" +dependencies = [ + "cfg-if", + "data-encoding", + "futures-channel", + "futures-util", + "hickory-proto", + "once_cell", + "radix_trie", + "rand", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "hickory-proto" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "openssl", + "rand", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image-sequoia" +version = "0.1.0" +dependencies = [ + "anyhow", + "cbindgen", + "cdylib-link-lines", + "dirs 5.0.1", + "dlwrap", + "libc", + "log", + "regex", + "sequoia-cert-store", + "sequoia-keystore", + "sequoia-openpgp", + "sequoia-policy-config", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array 0.14.7", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools 0.11.0", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.0", + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memsec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nettle" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e6ff4a94e5d34a1fd5abbd39418074646e2fa51b257198701330f22fcd6936" +dependencies = [ + "getrandom 0.2.15", + "libc", + "nettle-sys", + "thiserror 1.0.69", + "typenum", +] + +[[package]] +name = "nettle-sys" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a3f5406064d310d59b1a219d3c5c9a49caf4047b6496032e3f930876488c34" +dependencies = [ + "bindgen", + "cc", + "libc", + "pkg-config", + "tempfile", + "vcpkg", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "ocb3" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" +dependencies = [ + "aead", + "cipher", + "ctr", + "subtle", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openpgp-cert-d" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd47b0b6df1022ca8a9a06791261c3153028abef191fe53aa326b7f443f2d6" +dependencies = [ + "anyhow", + "dirs 6.0.0", + "fd-lock", + "libc", + "sha1collisiondetection", + "sha2", + "tempfile", + "thiserror 2.0.12", + "walkdir", +] + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.9.0", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy 0.8.24", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 2.0.12", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "resolv-conf" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48375394603e3dd4b2d64371f7148fd8c7baa2680e28741f2cb8d23b59e3d4c4" +dependencies = [ + "hostname", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags 2.9.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "sequoia-cert-store" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8987ed37e9931aee509c7ebc10e93b2ee5862849546c8a0c4588f3ed670b74" +dependencies = [ + "anyhow", + "crossbeam", + "dirs 5.0.1", + "gethostname", + "num_cpus", + "openpgp-cert-d", + "rayon", + "rusqlite", + "sequoia-net", + "sequoia-openpgp", + "smallvec", + "thiserror 2.0.12", + "tokio", + "url", +] + +[[package]] +name = "sequoia-directories" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01dd48960c5cf8617ab77e5c9f8ebeb55a1d694e3eabf830fa70453ffa637d5" +dependencies = [ + "anyhow", + "directories", + "same-file", + "tempfile", + "thiserror 1.0.69", +] + +[[package]] +name = "sequoia-ipc" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92579bbd37f62bbcc41e4dce7771fea395037bebaf9b8e10c20b765be8280ab" +dependencies = [ + "anyhow", + "capnp-rpc", + "ctor", + "dirs 5.0.1", + "fs2", + "lalrpop", + "lalrpop-util", + "libc", + "memsec", + "rand", + "sequoia-openpgp", + "socket2", + "tempfile", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "winapi", +] + +[[package]] +name = "sequoia-keystore" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b510811048c0767a0d3196b3bb0719d999eb52a836580d794e97a2586b546347" +dependencies = [ + "anyhow", + "async-generic", + "capnp", + "capnpc", + "dirs 5.0.1", + "env_logger", + "log", + "paste", + "sequoia-directories", + "sequoia-ipc", + "sequoia-keystore-backend", + "sequoia-keystore-softkeys", + "sequoia-openpgp", + "thiserror 2.0.12", + "tokio", + "tokio-util", +] + +[[package]] +name = "sequoia-keystore-backend" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55b047f9b6412c34dc7a26a42f278205cbf1e29516feab1228edccca215f500" +dependencies = [ + "anyhow", + "async-trait", + "env_logger", + "futures", + "log", + "sequoia-openpgp", + "tempfile", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "sequoia-keystore-softkeys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713736e9a5277f8ff829a1efaf99c0f6c07718fe0c199f435406883313ee8742" +dependencies = [ + "anyhow", + "async-trait", + "dirs 5.0.1", + "futures", + "log", + "sequoia-keystore-backend", + "sequoia-openpgp", +] + +[[package]] +name = "sequoia-net" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ef5d37e41f53259cd3c6caac5f135351ee92f76f3ac6ee9cf771ee6e33925" +dependencies = [ + "anyhow", + "base64", + "futures-util", + "hickory-client", + "hickory-resolver", + "http", + "hyper", + "hyper-tls", + "libc", + "percent-encoding", + "reqwest", + "sequoia-openpgp", + "thiserror 1.0.69", + "tokio", + "url", + "z-base-32", +] + +[[package]] +name = "sequoia-openpgp" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "015e5fc3d023418b9db98ca9a7f3e90b305872eeafe5ca45c5c32b5eb335c1e8" +dependencies = [ + "aes", + "aes-gcm", + "anyhow", + "argon2", + "base64", + "block-padding", + "blowfish", + "botan", + "buffered-reader", + "bzip2", + "camellia", + "cast5", + "cfb-mode", + "chrono", + "cipher", + "des", + "digest", + "dsa", + "dyn-clone", + "eax", + "ecb", + "ecdsa", + "ed25519", + "ed25519-dalek", + "flate2", + "getrandom 0.2.15", + "hkdf", + "idea", + "idna", + "lalrpop", + "lalrpop-util", + "libc", + "md-5", + "memsec", + "nettle", + "num-bigint-dig", + "ocb3", + "openssl", + "openssl-sys", + "p256", + "p384", + "p521", + "rand", + "rand_core", + "regex", + "regex-syntax", + "ripemd", + "rsa", + "sha1collisiondetection", + "sha2", + "sha3", + "thiserror 2.0.12", + "twofish", + "typenum", + "win-crypto-ng", + "winapi", + "x25519-dalek", + "xxhash-rust", +] + +[[package]] +name = "sequoia-policy-config" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e016b708d64857b6a97e1a331d9471b73e30ed450d247628e1a0ce236b1e597" +dependencies = [ + "anyhow", + "chrono", + "sequoia-openpgp", + "serde", + "thiserror 1.0.69", + "toml", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1collisiondetection" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f606421e4a6012877e893c399822a4ed4b089164c5969424e1b9d1e66e6964b" +dependencies = [ + "const-oid", + "digest", + "generic-array 1.2.0", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +dependencies = [ + "fastrand", + "getrandom 0.3.2", + "once_cell", + "rustix 1.0.5", + "windows-sys 0.59.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "twofish" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" +dependencies = [ + "cipher", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + +[[package]] +name = "win-crypto-ng" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99abfb435a71e54ab2971d8d8c32f1a7e006cdbf527f71743b1d45b93517bb92" +dependencies = [ + "cipher", + "doc-comment", + "rand_core", + "winapi", + "zeroize", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings 0.4.0", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "zeroize", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "synstructure", +] + +[[package]] +name = "z-base-32" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bf7b4a78668416e1e8a332334e26fb2f377afe707f0c6feaf6ed5f9100133b" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] diff --git a/signature/internal/sequoia/rust/Cargo.toml b/signature/internal/sequoia/rust/Cargo.toml new file mode 100644 index 0000000000..6d78e0b402 --- /dev/null +++ b/signature/internal/sequoia/rust/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "image-sequoia" +version = "0.1.0" +edition = "2021" +license = "LGPL-2.0-or-later" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1" +dirs = "5" +libc = "0.2" +log = "0.4" +sequoia-cert-store = "0.7" +sequoia-keystore = { version = "0.7", default-features = false, features = ["softkeys"] } +sequoia-openpgp = { version = "2", default-features = false, features = ["compression"] } +sequoia-policy-config = "0.8" + +[build-dependencies] +anyhow = "1" +cbindgen = "0.24.0" +cdylib-link-lines = "0.1.4" +dlwrap = "0.3.7" +regex = "1" + +[features] +# To use a different cryptographic backend, e.g., OpenSSL, do: +# +# cargo build --release --no-default-features --features crypto-openssl + +# We explicitly do not want to enable Sequoia's decompression support. +# Hence we only select a crypto backend. +default = ["crypto-openssl"] +crypto-nettle = ["sequoia-openpgp/crypto-nettle"] +crypto-rust = ["sequoia-openpgp/crypto-rust"] +crypto-cng = ["sequoia-openpgp/crypto-cng"] +crypto-openssl = ["sequoia-openpgp/crypto-openssl"] +crypto-botan = ["sequoia-openpgp/crypto-botan"] +crypto-botan2 = ["sequoia-openpgp/crypto-botan2"] diff --git a/signature/internal/sequoia/rust/README.md b/signature/internal/sequoia/rust/README.md new file mode 100644 index 0000000000..5e7e0a1c8d --- /dev/null +++ b/signature/internal/sequoia/rust/README.md @@ -0,0 +1,34 @@ +# image-sequoia + +This directory contains the source code of a C shared library +(`libimage_sequoia.so`) that enables to use [sequoia-pgp] as a signing +backend. + +For building, you need rustc (version 1.79 or later), cargo, and +openssl-devel. For testing, you also need the `sq` command (version +1.3.0 or later). + +## Building + +To build the shared library and bindings, do: + +```console +$ PREFIX=/usr LIBDIR="\${prefix}/lib64" cargo build --release +``` + +## Installing + +Just copy the shared library in the library search path: + +```console +$ sudo cp -a rust/target/release/libimage_sequoia.so* /usr/lib64 +``` + +## Testing + +To test, in the top-level directory of containers image, do: +```console +$ LD_LIBRARY_PATH=$PWD/signature/internal/sequoia/rust/target/release \ + make BUILDTAGS=containers_image_sequoia +``` +[sequoia-pgp]: https://sequoia-pgp.org/ diff --git a/signature/internal/sequoia/rust/build.rs b/signature/internal/sequoia/rust/build.rs new file mode 100644 index 0000000000..1df0142f0d --- /dev/null +++ b/signature/internal/sequoia/rust/build.rs @@ -0,0 +1,121 @@ +extern crate cbindgen; + +use std::env; +use std::path::PathBuf; + +use anyhow::Result; +use regex::Regex; + +fn main() -> Result<(), Box> { + let src = env::current_dir()?; + + let mut build_dir = PathBuf::from(&src); + if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") { + // Note: if CARGO_TARGET_DIR is absolute, this will first + // clear build_dir, which is what we want. + build_dir.push(target_dir); + } else { + build_dir.push("target"); + } + let profile = env::var_os("PROFILE").expect("PROFILE not set"); + build_dir.push(&profile); + + let bindings_dir = build_dir.join("bindings"); + let include = bindings_dir.join("sequoia.h"); + + // Generate ${CARGO_TARGET_DIR}/${PROFILE}/bindings/sequoia.h + cbindgen::Builder::new() + .with_crate(&src) + .with_language(cbindgen::Language::C) + .with_header("// SPDX-License-Identifier: Apache-2.0") + .with_pragma_once(true) + .generate() + .expect("Unable to generate bindings") + .write_to_file(&include); + + // Generate dlwrap files + dlwrap::Builder::new(&include) + .output_dir(&bindings_dir) + .symbol_regex(&Regex::new("^sequoia_")?) + .license("SPDX-License-Identifier: Apache-2.0") + .loader_basename("gosequoia") + .soname("SEQUOIA_SONAME") + .prefix("go_sequoia") + .function_prefix("go") + .header_guard("GO_SEQUOIA_H_") + .include("") + .generate()?; + + let prefix = env::var_os("PREFIX"); + let prefix: &str = match prefix.as_ref().and_then(|s| s.to_str()) { + Some(s) => s, + None => "/usr/local", + }; + let libdir = env::var_os("LIBDIR"); + let libdir: &str = match libdir.as_ref().and_then(|s| s.to_str()) { + Some(s) => s, + None => "${prefix}/lib", + }; + + // Rerun if... + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=Cargo.toml"); + println!("cargo:rerun-if-env-changed=PREFIX"); + println!("cargo:rerun-if-env-changed=LIBDIR"); + println!("cargo:rerun-if-env-changed=PROFILE"); + println!("cargo:rerun-if-env-changed=CARGO_TARGET_DIR"); + + // Set the soname. + let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); + + // We do not care about `_pre` and such. + let major = env::var("CARGO_PKG_VERSION_MAJOR").unwrap(); + let minor = env::var("CARGO_PKG_VERSION_MINOR").unwrap(); + let patch = env::var("CARGO_PKG_VERSION_PATCH").unwrap(); + + // libdir might contain "${prefix}". Replace it with + // the actual prefix value if found. + let libdir_resolved = libdir.replace("${prefix}", prefix); + + let linker_lines = cdylib_link_lines::shared_object_link_args( + "image_sequoia", + &major, + &minor, + &patch, + &arch, + &os, + &env, + PathBuf::from(libdir_resolved), + build_dir.clone(), + ); + + for line in linker_lines { + println!("cargo:rustc-cdylib-link-arg={}", line); + } + + #[cfg(unix)] + { + // Create a symlink. + let mut create = true; + + let mut link = build_dir.clone(); + link.push(format!("libimage_sequoia.so.{}", major)); + + if let Ok(current) = std::fs::read_link(&link) { + if current.to_str() == Some("libimage_sequoia.so") { + // Do nothing. + create = false; + } else { + // Invalid. + std::fs::remove_file(&link)?; + } + } + + if create { + std::os::unix::fs::symlink("libimage_sequoia.so", link)?; + } + } + Ok(()) +} diff --git a/signature/internal/sequoia/rust/src/error.rs b/signature/internal/sequoia/rust/src/error.rs new file mode 100644 index 0000000000..660ed69c27 --- /dev/null +++ b/signature/internal/sequoia/rust/src/error.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: LGPL-2.0-or-later + +#![allow(clippy::missing_safety_doc)] +use libc::c_char; +use std::ffi::CString; +use std::io; + +#[repr(C)] +pub enum SequoiaErrorKind { + Unknown, + InvalidArgument, + IoError, +} + +#[repr(C)] +pub struct SequoiaError { + kind: SequoiaErrorKind, + message: *mut c_char, +} + +impl Drop for SequoiaError { + fn drop(&mut self) { + unsafe { + let _ = CString::from_raw(self.message); + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_error_free(err_ptr: *mut SequoiaError) { + drop(Box::from_raw(err_ptr)) +} + +pub unsafe fn set_error_from(err_ptr: *mut *mut SequoiaError, err: anyhow::Error) { + if !err_ptr.is_null() { + let kind = if err.is::() { + SequoiaErrorKind::IoError + } else { + SequoiaErrorKind::Unknown + }; + + *err_ptr = Box::into_raw(Box::new(SequoiaError { + kind, + message: CString::from_vec_unchecked(err.to_string().into()).into_raw(), + })); + } +} diff --git a/signature/internal/sequoia/rust/src/lib.rs b/signature/internal/sequoia/rust/src/lib.rs new file mode 100644 index 0000000000..1f4f629acd --- /dev/null +++ b/signature/internal/sequoia/rust/src/lib.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.0-or-later + +mod error; +pub use crate::error::*; + +mod signature; +pub use crate::signature::*; diff --git a/signature/internal/sequoia/rust/src/signature.rs b/signature/internal/sequoia/rust/src/signature.rs new file mode 100644 index 0000000000..7b70334500 --- /dev/null +++ b/signature/internal/sequoia/rust/src/signature.rs @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: LGPL-2.0-or-later + +#![allow(clippy::missing_safety_doc)] +use anyhow::Context as _; +use libc::{c_char, size_t}; +use openpgp::cert::prelude::*; +use openpgp::parse::{stream::*, Parse}; +use openpgp::policy::StandardPolicy; +use openpgp::serialize::stream::{LiteralWriter, Message, Signer}; +use openpgp::KeyHandle; +use sequoia_cert_store::{Store as _, StoreUpdate as _}; +use sequoia_openpgp as openpgp; +use sequoia_policy_config::ConfiguredStandardPolicy; +use std::ffi::{CStr, CString, OsStr}; +use std::fs; +use std::io::{Read, Write}; +use std::os::unix::ffi::OsStrExt; +use std::path::Path; +use std::ptr; +use std::slice; +use std::sync::Arc; + +use crate::{set_error_from, SequoiaError}; + +pub struct SequoiaMechanism<'a> { + keystore: sequoia_keystore::Keystore, + certstore: Arc>, + policy: StandardPolicy<'a>, +} + +impl<'a> SequoiaMechanism<'a> { + fn from_directory(dir: impl AsRef) -> Result { + let home_dir = dir.as_ref().to_path_buf(); + + let keystore_dir = home_dir.join("data").join("keystore"); + let context = sequoia_keystore::Context::configure() + .home(&keystore_dir) + .build()?; + let keystore = sequoia_keystore::Keystore::connect(&context)?; + + let certstore_dir = home_dir.join("data").join("pgp.cert.d"); + fs::create_dir_all(&certstore_dir)?; + let certstore = sequoia_cert_store::CertStore::open(&certstore_dir)?; + + let mut policy = ConfiguredStandardPolicy::new(); + policy.parse_default_config()?; + let policy = policy.build(); + + Ok(Self { + keystore, + certstore: Arc::new(certstore), + policy, + }) + } + + fn ephemeral() -> Result { + let context = sequoia_keystore::Context::configure().ephemeral().build()?; + let certstore = Arc::new(sequoia_cert_store::CertStore::empty()); + let mut policy = ConfiguredStandardPolicy::new(); + policy.parse_default_config()?; + let policy = policy.build(); + Ok(Self { + keystore: sequoia_keystore::Keystore::connect(&context)?, + certstore, + policy, + }) + } + + fn import_keys(&mut self, blob: &[u8]) -> Result { + let mut softkeys = None; + for mut backend in self.keystore.backends()?.into_iter() { + if backend.id()? == "softkeys" { + softkeys = Some(backend); + break; + } + } + + let mut softkeys = if let Some(softkeys) = softkeys { + softkeys + } else { + return Err(anyhow::anyhow!("softkeys backend is not configured.")); + }; + + let mut key_handles = vec![]; + for r in CertParser::from_bytes(blob)? { + let cert = match r { + Ok(cert) => cert, + Err(err) => { + log::info!("Error reading cert: {}", err); + continue; + } + }; + + let _ = softkeys.import(&cert)?; + + key_handles.push(CString::new(cert.fingerprint().to_hex().as_bytes()).unwrap()); + self.certstore + .update(Arc::new(sequoia_cert_store::LazyCert::from(cert)))?; + } + Ok(SequoiaImportResult { key_handles }) + } + + fn sign( + &mut self, + key_handle: &str, + password: Option<&str>, + data: &[u8], + ) -> Result, anyhow::Error> { + let primary_key_handle: KeyHandle = key_handle.parse()?; + let certs = self + .certstore + .lookup_by_cert_or_subkey(&primary_key_handle) + .with_context(|| format!("Failed to load {} from certificate store", key_handle))? + .into_iter() + .filter_map(|cert| match cert.to_cert() { + Ok(cert) => Some(cert.clone()), + Err(_) => None, + }) + .collect::>(); + + let mut signing_key_handles: Vec = vec![]; + for cert in certs { + for ka in cert.keys().with_policy(&self.policy, None).for_signing() { + signing_key_handles.push(ka.key().fingerprint().into()); + } + } + + if signing_key_handles.is_empty() { + return Err(anyhow::anyhow!( + "No matching signing key for {}", + key_handle + )); + } + + let mut keys = self.keystore.find_key(signing_key_handles[0].clone())?; + + if keys.is_empty() { + return Err(anyhow::anyhow!("No matching key in keystore")); + } + if let Some(password) = password { + keys[0].unlock(password.into())?; + } + + let mut sink = vec![]; + { + let message = Message::new(&mut sink); + let message = Signer::new(message, &mut keys[0])?.build()?; + let mut message = LiteralWriter::new(message).build()?; + message.write_all(data)?; + message.finalize()?; + } + Ok(sink) + } + + fn verify(&mut self, signature: &[u8]) -> Result { + if signature.is_empty() { + return Err(anyhow::anyhow!("empty signature")); + } + + let h = Helper { + certstore: self.certstore.clone(), + signer: Default::default(), + }; + let mut policy = ConfiguredStandardPolicy::new(); + policy.parse_default_config()?; + let policy = policy.build(); + + let mut v = VerifierBuilder::from_bytes(signature)?.with_policy(&policy, None, h)?; + let mut content = Vec::new(); + v.read_to_end(&mut content)?; + + assert!(v.message_processed()); + + match &v.helper_ref().signer { + Some(signer) => Ok(SequoiaVerificationResult { + content, + signer: CString::new(signer.fingerprint().to_hex().as_bytes()).unwrap(), + }), + None => Err(anyhow::anyhow!("No valid signature")), + } + } +} + +struct Helper<'a> { + certstore: Arc>, + signer: Option, +} + +impl<'a> VerificationHelper for Helper<'a> { + fn get_certs(&mut self, ids: &[openpgp::KeyHandle]) -> openpgp::Result> { + let mut certs = Vec::new(); + for id in ids { + let matches = self.certstore.lookup_by_cert_or_subkey(id); + for lc in matches? { + certs.push(lc.to_cert()?.clone()); + } + } + Ok(certs) + } + + fn check(&mut self, structure: MessageStructure) -> openpgp::Result<()> { + for layer in structure { + match layer { + MessageLayer::Compression { algo } => log::info!("Compressed using {}", algo), + MessageLayer::Encryption { + sym_algo, + aead_algo, + } => { + if let Some(aead_algo) = aead_algo { + log::info!("Encrypted and protected using {}/{}", sym_algo, aead_algo); + } else { + log::info!("Encrypted using {}", sym_algo); + } + } + MessageLayer::SignatureGroup { ref results } => { + let result = results.iter().find(|r| r.is_ok()); + if let Some(result) = result { + self.signer = Some(result.as_ref().unwrap().ka.cert().to_owned()); + return Ok(()); + } + } + } + } + Err(anyhow::anyhow!("No valid signature")) + } +} + +pub struct SequoiaSignature { + data: Vec, +} + +pub struct SequoiaVerificationResult { + content: Vec, + signer: CString, +} + +#[derive(Default)] +pub struct SequoiaImportResult { + key_handles: Vec, +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_mechanism_new_from_directory<'a>( + dir_ptr: *const c_char, + err_ptr: *mut *mut SequoiaError, +) -> *mut SequoiaMechanism<'a> { + let c_dir = CStr::from_ptr(dir_ptr); + let os_dir = OsStr::from_bytes(c_dir.to_bytes()); + match SequoiaMechanism::from_directory(os_dir) { + Ok(mechanism) => Box::into_raw(Box::new(mechanism)), + Err(e) => { + set_error_from(err_ptr, e); + ptr::null_mut() + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_mechanism_new_ephemeral<'a>( + err_ptr: *mut *mut SequoiaError, +) -> *mut SequoiaMechanism<'a> { + match SequoiaMechanism::ephemeral() { + Ok(mechanism) => Box::into_raw(Box::new(mechanism)), + Err(e) => { + set_error_from(err_ptr, e); + ptr::null_mut() + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_mechanism_free(mechanism_ptr: *mut SequoiaMechanism) { + drop(Box::from_raw(mechanism_ptr)) +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_signature_free(signature_ptr: *mut SequoiaSignature) { + drop(Box::from_raw(signature_ptr)) +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_signature_get_data( + signature_ptr: *const SequoiaSignature, + data_len: *mut size_t, +) -> *const u8 { + assert!(!signature_ptr.is_null()); + *data_len = (*signature_ptr).data.len(); + (*signature_ptr).data.as_ptr() +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_verification_result_free( + result_ptr: *mut SequoiaVerificationResult, +) { + assert!(!result_ptr.is_null()); + drop(Box::from_raw(result_ptr)) +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_verification_result_get_content( + result_ptr: *const SequoiaVerificationResult, + data_len: *mut size_t, +) -> *const u8 { + assert!(!result_ptr.is_null()); + *data_len = (*result_ptr).content.len(); + (*result_ptr).content.as_ptr() +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_verification_result_get_signer( + result_ptr: *const SequoiaVerificationResult, +) -> *const c_char { + assert!(!result_ptr.is_null()); + (*result_ptr).signer.as_ptr() +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_sign( + mechanism_ptr: *mut SequoiaMechanism, + key_handle_ptr: *const c_char, + password_ptr: *const c_char, + data_ptr: *const u8, + data_len: size_t, + err_ptr: *mut *mut SequoiaError, +) -> *mut SequoiaSignature { + assert!(!mechanism_ptr.is_null()); + assert!(!key_handle_ptr.is_null()); + assert!(!data_ptr.is_null()); + + let key_handle = match CStr::from_ptr(key_handle_ptr).to_str() { + Ok(key_handle) => key_handle, + Err(e) => { + set_error_from(err_ptr, e.into()); + return ptr::null_mut(); + } + }; + + let password = if password_ptr.is_null() { + None + } else { + match CStr::from_ptr(password_ptr).to_str() { + Ok(password) => Some(password), + Err(e) => { + set_error_from(err_ptr, e.into()); + return ptr::null_mut(); + } + } + }; + + let data = slice::from_raw_parts(data_ptr, data_len); + match (*mechanism_ptr).sign(key_handle, password, data) { + Ok(signature) => Box::into_raw(Box::new(SequoiaSignature { data: signature })), + Err(e) => { + set_error_from(err_ptr, e); + ptr::null_mut() + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_verify( + mechanism_ptr: *mut SequoiaMechanism, + signature_ptr: *const u8, + signature_len: size_t, + err_ptr: *mut *mut SequoiaError, +) -> *mut SequoiaVerificationResult { + assert!(!mechanism_ptr.is_null()); + + let signature = slice::from_raw_parts(signature_ptr, signature_len); + match (*mechanism_ptr).verify(signature) { + Ok(result) => Box::into_raw(Box::new(result)), + Err(e) => { + set_error_from(err_ptr, e); + ptr::null_mut() + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_import_result_free(result_ptr: *mut SequoiaImportResult) { + drop(Box::from_raw(result_ptr)) +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_import_result_get_count( + result_ptr: *const SequoiaImportResult, +) -> size_t { + assert!(!result_ptr.is_null()); + + (*result_ptr).key_handles.len() +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_import_result_get_content( + result_ptr: *const SequoiaImportResult, + index: size_t, + err_ptr: *mut *mut SequoiaError, +) -> *const c_char { + assert!(!result_ptr.is_null()); + + if index >= (*result_ptr).key_handles.len() { + set_error_from(err_ptr, anyhow::anyhow!("No matching key handle")); + return ptr::null(); + } + let key_handle = &(*result_ptr).key_handles[index]; + key_handle.as_ptr() +} + +#[no_mangle] +pub unsafe extern "C" fn sequoia_import_keys( + mechanism_ptr: *mut SequoiaMechanism, + blob_ptr: *const u8, + blob_len: size_t, + err_ptr: *mut *mut SequoiaError, +) -> *mut SequoiaImportResult { + assert!(!mechanism_ptr.is_null()); + + let blob = slice::from_raw_parts(blob_ptr, blob_len); + if blob.is_empty() { + let result = SequoiaImportResult { + ..Default::default() + }; + return Box::into_raw(Box::new(result)); + } + + match (*mechanism_ptr).import_keys(blob) { + Ok(result) => Box::into_raw(Box::new(result)), + Err(e) => { + set_error_from(err_ptr, e); + ptr::null_mut() + } + } +} diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go new file mode 100644 index 0000000000..86785ecb15 --- /dev/null +++ b/signature/internal/sequoia/sequoia.go @@ -0,0 +1,155 @@ +//go:build containers_image_sequoia + +package sequoia + +// #cgo CFLAGS: -I. -DGO_SEQUOIA_ENABLE_DLOPEN=1 +// #include "gosequoia.h" +// #include +// #include +import "C" + +import ( + "errors" + "unsafe" +) + +type SigningMechanism struct { + mechanism *C.SequoiaMechanism +} + +func NewMechanismFromDirectory( + dir string, +) (*SigningMechanism, error) { + var cerr *C.SequoiaError + cDir := C.CString(dir) + defer C.free(unsafe.Pointer(cDir)) + cMechanism := C.go_sequoia_mechanism_new_from_directory(cDir, &cerr) + if cMechanism == nil { + defer C.go_sequoia_error_free(cerr) + return nil, errors.New(C.GoString(cerr.message)) + } + return &SigningMechanism{ + mechanism: cMechanism, + }, nil +} + +func NewEphemeralMechanism() (*SigningMechanism, error) { + var cerr *C.SequoiaError + cMechanism := C.go_sequoia_mechanism_new_ephemeral(&cerr) + if cMechanism == nil { + defer C.go_sequoia_error_free(cerr) + return nil, errors.New(C.GoString(cerr.message)) + } + return &SigningMechanism{ + mechanism: cMechanism, + }, nil +} + +func (m *SigningMechanism) SignWithPassphrase( + input []byte, + keyIdentity string, + passphrase string, +) ([]byte, error) { + var cerr *C.SequoiaError + var cPassphrase *C.char + if passphrase == "" { + cPassphrase = nil + } else { + cPassphrase = C.CString(passphrase) + defer C.free(unsafe.Pointer(cPassphrase)) + } + cKeyIdentity := C.CString(keyIdentity) + defer C.free(unsafe.Pointer(cKeyIdentity)) + sig := C.go_sequoia_sign( + m.mechanism, + cKeyIdentity, + cPassphrase, + (*C.uchar)(unsafe.Pointer(unsafe.SliceData(input))), + C.size_t(len(input)), + &cerr, + ) + if sig == nil { + defer C.go_sequoia_error_free(cerr) + return nil, errors.New(C.GoString(cerr.message)) + } + defer C.go_sequoia_signature_free(sig) + var size C.size_t + cData := C.go_sequoia_signature_get_data(sig, &size) + if size > C.size_t(C.INT_MAX) { + return nil, errors.New("overflow") + } + return C.GoBytes(unsafe.Pointer(cData), C.int(size)), nil +} + +func (m *SigningMechanism) Sign( + input []byte, + keyIdentity string, +) ([]byte, error) { + return m.SignWithPassphrase(input, keyIdentity, "") +} + +func (m *SigningMechanism) Verify( + unverifiedSignature []byte, +) (contents []byte, keyIdentity string, err error) { + var cerr *C.SequoiaError + result := C.go_sequoia_verify( + m.mechanism, + (*C.uchar)(unsafe.Pointer(unsafe.SliceData(unverifiedSignature))), + C.size_t(len(unverifiedSignature)), + &cerr, + ) + if result == nil { + defer C.go_sequoia_error_free(cerr) + return nil, "", errors.New(C.GoString(cerr.message)) + } + defer C.go_sequoia_verification_result_free(result) + var size C.size_t + cContent := C.go_sequoia_verification_result_get_content(result, &size) + if size > C.size_t(C.INT_MAX) { + return nil, "", errors.New("overflow") + } + contents = C.GoBytes(unsafe.Pointer(cContent), C.int(size)) + cSigner := C.go_sequoia_verification_result_get_signer(result) + keyIdentity = C.GoString(cSigner) + return contents, keyIdentity, nil +} + +func (m *SigningMechanism) ImportKeys(blob []byte) ([]string, error) { + var cerr *C.SequoiaError + result := C.go_sequoia_import_keys( + m.mechanism, + (*C.uchar)(unsafe.Pointer(unsafe.SliceData(blob))), + C.size_t(len(blob)), + &cerr, + ) + if result == nil { + defer C.go_sequoia_error_free(cerr) + return nil, errors.New(C.GoString(cerr.message)) + } + defer C.go_sequoia_import_result_free(result) + + keyIdentities := []string{} + count := C.go_sequoia_import_result_get_count(result) + for i := C.size_t(0); i < count; i++ { + cKeyIdentity := C.go_sequoia_import_result_get_content(result, i, &cerr) + keyIdentities = append(keyIdentities, C.GoString(cKeyIdentity)) + } + + return keyIdentities, nil +} + +func (m *SigningMechanism) Close() error { + return nil +} + +func (m *SigningMechanism) SupportsSigning() error { + return nil +} + +func Init() error { + if C.go_sequoia_ensure_library(C.CString("libimage_sequoia.so.0"), + C.RTLD_NOW|C.RTLD_GLOBAL) < 0 { + return errors.New("unable to load libimage_sequoia.so.0") + } + return nil +} diff --git a/signature/internal/sequoia/sequoia.h b/signature/internal/sequoia/sequoia.h new file mode 100644 index 0000000000..b60c566f89 --- /dev/null +++ b/signature/internal/sequoia/sequoia.h @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include +#include + +typedef enum SequoiaErrorKind { + Unknown, + InvalidArgument, + IoError, +} SequoiaErrorKind; + +typedef struct SequoiaImportResult SequoiaImportResult; + +typedef struct SequoiaMechanism SequoiaMechanism; + +typedef struct SequoiaSignature SequoiaSignature; + +typedef struct SequoiaVerificationResult SequoiaVerificationResult; + +typedef struct SequoiaError { + enum SequoiaErrorKind kind; + const char *message; +} SequoiaError; + +void sequoia_error_free(struct SequoiaError *err_ptr); + +struct SequoiaMechanism *sequoia_mechanism_new_from_directory(const char *dir_ptr, + struct SequoiaError **err_ptr); + +struct SequoiaMechanism *sequoia_mechanism_new_ephemeral(struct SequoiaError **err_ptr); + +void sequoia_mechanism_free(struct SequoiaMechanism *mechanism_ptr); + +void sequoia_signature_free(struct SequoiaSignature *signature_ptr); + +const uint8_t *sequoia_signature_get_data(const struct SequoiaSignature *signature_ptr, + size_t *data_len); + +void sequoia_verification_result_free(struct SequoiaVerificationResult *result_ptr); + +const uint8_t *sequoia_verification_result_get_content(const struct SequoiaVerificationResult *result_ptr, + size_t *data_len); + +const char *sequoia_verification_result_get_signer(const struct SequoiaVerificationResult *result_ptr); + +struct SequoiaSignature *sequoia_sign(struct SequoiaMechanism *mechanism_ptr, + const char *key_handle_ptr, + const char *password_ptr, + const uint8_t *data_ptr, + size_t data_len, + struct SequoiaError **err_ptr); + +struct SequoiaVerificationResult *sequoia_verify(struct SequoiaMechanism *mechanism_ptr, + const uint8_t *signature_ptr, + size_t signature_len, + struct SequoiaError **err_ptr); + +void sequoia_import_result_free(struct SequoiaImportResult *result_ptr); + +size_t sequoia_import_result_get_count(const struct SequoiaImportResult *result_ptr); + +const char *sequoia_import_result_get_content(const struct SequoiaImportResult *result_ptr, + size_t index, + struct SequoiaError **err_ptr); + +struct SequoiaImportResult *sequoia_import_keys(struct SequoiaMechanism *mechanism_ptr, + const uint8_t *blob_ptr, + size_t blob_len, + struct SequoiaError **err_ptr); diff --git a/signature/internal/sequoia/sequoia_test.go b/signature/internal/sequoia/sequoia_test.go new file mode 100644 index 0000000000..2700d9b7cb --- /dev/null +++ b/signature/internal/sequoia/sequoia_test.go @@ -0,0 +1,228 @@ +//go:build containers_image_sequoia + +package sequoia_test + +import ( + "bytes" + "errors" + "fmt" + "github.com/containers/image/v5/signature/internal/sequoia" + "io" + "os" + "os/exec" + "regexp" + "testing" +) + +func checkCliVersion(version string) error { + return exec.Command("sq", "--cli-version", version, "version").Run() +} + +func generateKey(dir string, email string) (string, error) { + cmd := exec.Command("sq", "--home", dir, "key", "generate", "--userid", fmt.Sprintf("<%s>", email), "--own-key", "--without-password") + stderr, err := cmd.StderrPipe() + if err != nil { + return "", err + } + + if err := cmd.Start(); err != nil { + return "", err + } + + output, err := io.ReadAll(stderr) + if err != nil { + return "", err + } + + if err := cmd.Wait(); err != nil { + return "", err + } + + re := regexp.MustCompile("(?m)^ *Fingerprint: ([0-9A-F]+)") + matches := re.FindSubmatch(output) + if matches == nil { + return "", errors.New("unable to extract fingerprint") + } + fingerprint := string(matches[1][:]) + return fingerprint, nil +} + +func exportKey(dir string, fingerprint string) ([]byte, error) { + cmd := exec.Command("sq", "--home", dir, "key", "export", "--cert", fingerprint) + return cmd.Output() +} + +func exportCert(dir string, fingerprint string) ([]byte, error) { + cmd := exec.Command("sq", "--home", dir, "cert", "export", "--cert", fingerprint) + return cmd.Output() +} + +func TestNewMechanismFromDirectory(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) + } + dir := t.TempDir() + _, err := sequoia.NewMechanismFromDirectory(dir) + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } + _, err = generateKey(dir, "foo@example.org") + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + _, err = sequoia.NewMechanismFromDirectory(dir) + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } +} + +func TestNewEphemeralMechanism(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) + } + dir := t.TempDir() + fingerprint, err := generateKey(dir, "foo@example.org") + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + output, err := exportCert(dir, fingerprint) + if err != nil { + t.Fatalf("unable to export cert: %v", err) + } + m, err := sequoia.NewEphemeralMechanism() + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } + keyIdentities, err := m.ImportKeys(output) + if err != nil { + t.Fatalf("unable to import keys: %v", err) + } + if len(keyIdentities) != 1 || keyIdentities[0] != fingerprint { + t.Fatalf("keyIdentity differ from the original: %v != %v", + keyIdentities[0], fingerprint) + } +} + +func TestGenerateSignVerify(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) + } + dir := t.TempDir() + fingerprint, err := generateKey(dir, "foo@example.org") + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + m, err := sequoia.NewMechanismFromDirectory(dir) + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } + input := []byte("Hello, world!") + sig, err := m.Sign(input, fingerprint) + if err != nil { + t.Fatalf("unable to sign: %v", err) + } + contents, keyIdentity, err := m.Verify(sig) + if err != nil { + t.Fatalf("unable to verify: %v", err) + } + if !bytes.Equal(contents, input) { + t.Fatalf("contents differ from the original") + } + if keyIdentity != fingerprint { + t.Fatalf("keyIdentity differ from the original") + } +} + +func TestImportSignVerify(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) + } + dir := t.TempDir() + fingerprint, err := generateKey(dir, "foo@example.org") + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + output, err := exportKey(dir, fingerprint) + if err != nil { + t.Fatalf("unable to export key: %v", err) + } + newDir := t.TempDir() + m, err := sequoia.NewMechanismFromDirectory(newDir) + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } + keyIdentities, err := m.ImportKeys(output) + if err != nil { + t.Fatalf("unable to import key: %v", err) + } + if len(keyIdentities) != 1 || keyIdentities[0] != fingerprint { + t.Fatalf("keyIdentity differ from the original: %v != %v", + keyIdentities[0], fingerprint) + } + input := []byte("Hello, world!") + sig, err := m.Sign(input, fingerprint) + if err != nil { + t.Fatalf("unable to sign: %v", err) + } + contents, keyIdentity, err := m.Verify(sig) + if err != nil { + t.Fatalf("unable to verify: %v", err) + } + if !bytes.Equal(contents, input) { + t.Fatalf("contents differ from the original") + } + if keyIdentity != fingerprint { + t.Fatalf("keyIdentity differ from the original") + } +} + +func TestImportSignVerifyEphemeral(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) + } + dir := t.TempDir() + fingerprint, err := generateKey(dir, "foo@example.org") + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + output, err := exportKey(dir, fingerprint) + if err != nil { + t.Fatalf("unable to export key: %v", err) + } + m, err := sequoia.NewEphemeralMechanism() + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } + keyIdentities, err := m.ImportKeys(output) + if err != nil { + t.Fatalf("unable to import key: %v", err) + } + if len(keyIdentities) != 1 || keyIdentities[0] != fingerprint { + t.Fatalf("keyIdentity differ from the original: %v != %v", + keyIdentities[0], fingerprint) + } + input := []byte("Hello, world!") + sig, err := m.Sign(input, fingerprint) + if err != nil { + t.Fatalf("unable to sign: %v", err) + } + contents, keyIdentity, err := m.Verify(sig) + if err != nil { + t.Fatalf("unable to verify: %v", err) + } + if !bytes.Equal(contents, input) { + t.Fatalf("contents differ from the original") + } + if keyIdentity != fingerprint { + t.Fatalf("keyIdentity differ from the original") + } +} + +func TestMain(m *testing.M) { + err := sequoia.Init() + if err != nil { + panic(err) + } + status := m.Run() + os.Exit(status) +} diff --git a/signature/mechanism_gpgme.go b/signature/mechanism_gpgme.go index 8a8c5878a0..5a774ccd84 100644 --- a/signature/mechanism_gpgme.go +++ b/signature/mechanism_gpgme.go @@ -1,4 +1,4 @@ -//go:build !containers_image_openpgp +//go:build !containers_image_openpgp && !containers_image_sequoia package signature diff --git a/signature/mechanism_gpgme_test.go b/signature/mechanism_gpgme_test.go index c5fc77308d..2064007c4b 100644 --- a/signature/mechanism_gpgme_test.go +++ b/signature/mechanism_gpgme_test.go @@ -1,4 +1,4 @@ -//go:build !containers_image_openpgp +//go:build !containers_image_openpgp && !containers_image_sequoia package signature diff --git a/signature/mechanism_sequoia.go b/signature/mechanism_sequoia.go new file mode 100644 index 0000000000..f1825145c7 --- /dev/null +++ b/signature/mechanism_sequoia.go @@ -0,0 +1,130 @@ +//go:build containers_image_sequoia + +package signature + +import ( + "github.com/containers/image/v5/signature/internal/sequoia" + "github.com/containers/storage/pkg/homedir" + "os" + "path" +) + +// A GPG/OpenPGP signing mechanism, implemented using Sequoia. +type sequoiaSigningMechanism struct { + inner *sequoia.SigningMechanism +} + +// newGPGSigningMechanismInDirectory returns a new GPG/OpenPGP signing mechanism, using optionalDir if not empty. +// The caller must call .Close() on the returned SigningMechanism. +func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWithPassphrase, error) { + // For compatibility reasons, we allow both sequoiaHome and + // gpgHome to be the same directory as designated by + // optionalDir or GNUPGHOME. + envHome := os.Getenv("GNUPGHOME") + + gpgHome := optionalDir + if gpgHome == "" { + gpgHome = envHome + if gpgHome == "" { + gpgHome = path.Join(homedir.Get(), ".gnupg") + } + } + + sequoiaHome := optionalDir + if sequoiaHome == "" { + sequoiaHome = envHome + if sequoiaHome == "" { + dataHome, err := homedir.GetDataHome() + if err != nil { + return nil, err + } + sequoiaHome = path.Join(dataHome, "sequoia") + } + } + + mech, err := sequoia.NewMechanismFromDirectory(sequoiaHome) + if err != nil { + return nil, err + } + + // Migrate GnuPG keyrings if exist. + for _, keyring := range []string{"pubring.gpg", "secring.gpg"} { + blob, err := os.ReadFile(path.Join(gpgHome, keyring)) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + } else if _, err := mech.ImportKeys(blob); err != nil { + return nil, err + } + } + + return &sequoiaSigningMechanism{ + inner: mech, + }, nil +} + +// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which +// recognizes _only_ public keys from the supplied blobs, and returns the identities +// of these keys. +// The caller must call .Close() on the returned SigningMechanism. +func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) { + mech, err := sequoia.NewEphemeralMechanism() + if err != nil { + return nil, nil, err + } + keyIdentities := []string{} + for _, blob := range blobs { + ki, err := mech.ImportKeys(blob) + if err != nil { + return nil, nil, err + } + keyIdentities = append(keyIdentities, ki...) + } + + return &sequoiaSigningMechanism{ + inner: mech, + }, keyIdentities, nil +} + +func (m *sequoiaSigningMechanism) Close() error { + return m.inner.Close() +} + +// SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError. +func (m *sequoiaSigningMechanism) SupportsSigning() error { + return m.inner.SupportsSigning() +} + +// Sign creates a (non-detached) signature of input using keyIdentity and passphrase. +// Fails with a SigningNotSupportedError if the mechanism does not support signing. +func (m *sequoiaSigningMechanism) SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error) { + return m.inner.SignWithPassphrase(input, keyIdentity, passphrase) +} + +// Sign creates a (non-detached) signature of input using keyIdentity. +// Fails with a SigningNotSupportedError if the mechanism does not support signing. +func (m *sequoiaSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte, error) { + return m.inner.Sign(input, keyIdentity) +} + +// Verify parses unverifiedSignature and returns the content and the signer's identity +func (m *sequoiaSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) { + return m.inner.Verify(unverifiedSignature) +} + +// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION, +// along with a short identifier of the key used for signing. +// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys) +// is NOT the same as a "key identity" used in other calls to this interface, and +// the values may have no recognizable relationship if the public key is not available. +func (m *sequoiaSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) { + return gpgUntrustedSignatureContents(untrustedSignature) +} + +func init() { + err := sequoia.Init() + if err != nil { + panic("sequoia cannot be loaded: " + err.Error()) + } +} diff --git a/signature/mechanism_test.go b/signature/mechanism_test.go index ef67db6b99..105df0b387 100644 --- a/signature/mechanism_test.go +++ b/signature/mechanism_test.go @@ -1,6 +1,6 @@ package signature -// These tests are expected to pass unmodified for _both_ mechanism_gpgme.go and mechanism_openpgp.go. +// These tests are expected to pass unmodified for _all_ of mechanism_sequoia.go, mechanism_gpgme.go, and mechanism_openpgp.go. import ( "bytes" From 89df1aa198e80047ee21ae842a264315a1995953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 11 Jul 2025 15:50:20 +0200 Subject: [PATCH 02/18] Use github.com/ueno/podman-sequoia instead of a local copy of the code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- README.md | 2 +- signature/internal/sequoia/gosequoiafuncs.h | 1 + signature/internal/sequoia/rust/Cargo.lock | 4490 ----------------- signature/internal/sequoia/rust/Cargo.toml | 40 - signature/internal/sequoia/rust/README.md | 34 - signature/internal/sequoia/rust/build.rs | 121 - signature/internal/sequoia/rust/src/error.rs | 47 - signature/internal/sequoia/rust/src/lib.rs | 7 - .../internal/sequoia/rust/src/signature.rs | 433 -- signature/internal/sequoia/sequoia.go | 4 +- signature/internal/sequoia/sequoia.h | 20 +- signature/internal/sequoia/sequoia_test.go | 93 +- 12 files changed, 22 insertions(+), 5270 deletions(-) delete mode 100644 signature/internal/sequoia/rust/Cargo.lock delete mode 100644 signature/internal/sequoia/rust/Cargo.toml delete mode 100644 signature/internal/sequoia/rust/README.md delete mode 100644 signature/internal/sequoia/rust/build.rs delete mode 100644 signature/internal/sequoia/rust/src/error.rs delete mode 100644 signature/internal/sequoia/rust/src/lib.rs delete mode 100644 signature/internal/sequoia/rust/src/signature.rs diff --git a/README.md b/README.md index 5f341afc36..35958e5a43 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ or use the build tags described below to avoid the dependencies (e.g. using `go - `containers_image_docker_daemon_stub`: Don’t import the `docker-daemon:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. - `containers_image_openpgp`: Use a Golang-only OpenPGP implementation for signature verification instead of the default cgo/gpgme-based implementation; the primary downside is that creating new signatures with the Golang-only implementation is not supported. -- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations. This requires a support shared library installed on the system. Follow the instructions in [signature/sequoia/rust/README.md](signature/sequoia/rust/README.md). +- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations. This requires a support shared library installed on the system. Install https://github.com/ueno/podman-sequoia . - `containers_image_storage_stub`: Don’t import the `containers-storage:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. ## [Contributing](CONTRIBUTING.md) diff --git a/signature/internal/sequoia/gosequoiafuncs.h b/signature/internal/sequoia/gosequoiafuncs.h index 025bf1a80b..3d7ae5fac8 100644 --- a/signature/internal/sequoia/gosequoiafuncs.h +++ b/signature/internal/sequoia/gosequoiafuncs.h @@ -18,3 +18,4 @@ VOID_FUNC(void, sequoia_import_result_free, (struct SequoiaImportResult *result_ FUNC(size_t, sequoia_import_result_get_count, (const struct SequoiaImportResult *result_ptr), (result_ptr)) FUNC(const char *, sequoia_import_result_get_content, (const struct SequoiaImportResult *result_ptr, size_t index, struct SequoiaError **err_ptr), (result_ptr, index, err_ptr)) FUNC(struct SequoiaImportResult *, sequoia_import_keys, (struct SequoiaMechanism *mechanism_ptr, const uint8_t *blob_ptr, size_t blob_len, struct SequoiaError **err_ptr), (mechanism_ptr, blob_ptr, blob_len, err_ptr)) +FUNC(int, sequoia_set_logger_consumer, (void (*consumer)(enum SequoiaLogLevel, const char *), struct SequoiaError **err_ptr), (consumer, err_ptr)) diff --git a/signature/internal/sequoia/rust/Cargo.lock b/signature/internal/sequoia/rust/Cargo.lock deleted file mode 100644 index 08ea903494..0000000000 --- a/signature/internal/sequoia/rust/Cargo.lock +++ /dev/null @@ -1,4490 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array 0.14.7", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "zeroize", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -dependencies = [ - "anstyle", - "once_cell", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" - -[[package]] -name = "argon2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" -dependencies = [ - "base64ct", - "blake2", - "cpufeatures", - "password-hash", -] - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "async-generic" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf3728566eefa873833159754f5732fb0951d3649e6e5b891cc70d56dd41673" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags 2.9.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.100", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -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.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "blowfish" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" -dependencies = [ - "byteorder", - "cipher", -] - -[[package]] -name = "botan" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d4c7647d67c53194fa0740404c6c508880aef2bfe99a9868dbb4b86f090377" -dependencies = [ - "botan-sys", -] - -[[package]] -name = "botan-sys" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04285fa0c094cc9961fe435b1b279183db9394844ad82ce483aa6196c0e6da38" - -[[package]] -name = "buffered-reader" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db26bf1f092fd5e05b5ab3be2f290915aeb6f3f20c4e9f86ce0f07f336c2412f" -dependencies = [ - "bzip2", - "flate2", - "libc", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "bzip2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" -dependencies = [ - "bzip2-sys", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "camellia" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" -dependencies = [ - "byteorder", - "cipher", -] - -[[package]] -name = "capnp" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e985a566bdaae9a428a957d12b10c318d41b2afddb54cfbb764878059df636e" -dependencies = [ - "embedded-io", -] - -[[package]] -name = "capnp-futures" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f3ee810b3890498e51028448ac732cdd5009223897124dd2fac6b085b5d867" -dependencies = [ - "capnp", - "futures", -] - -[[package]] -name = "capnp-rpc" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe57ab22a5e121e6fddaf36e837514aab9ae888bcff2baa6fda5630820dfc501" -dependencies = [ - "capnp", - "capnp-futures", - "futures", -] - -[[package]] -name = "capnpc" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ba30e0f08582d53c2f3710cf4bb65ff562614b1ba86906d7391adffe189ec" -dependencies = [ - "capnp", -] - -[[package]] -name = "cast5" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" -dependencies = [ - "cipher", -] - -[[package]] -name = "cbindgen" -version = "0.24.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d" -dependencies = [ - "clap 3.2.25", - "heck 0.4.1", - "indexmap 1.9.3", - "log", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 1.0.109", - "tempfile", - "toml", -] - -[[package]] -name = "cc" -version = "1.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" -dependencies = [ - "shlex", -] - -[[package]] -name = "cdylib-link-lines" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98eabef08bbdf5afd0b9c0cabb1ac335f7c70447ef095eed85dffd9628b20bc" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfb-mode" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" -dependencies = [ - "cipher", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clang" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c044c781163c001b913cd018fc95a628c50d0d2dfea8bca77dad71edb16e37" -dependencies = [ - "clang-sys", - "libc", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "strsim 0.10.0", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap" -version = "4.5.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" -dependencies = [ - "anstream", - "anstyle", - "clap_lex 0.7.4", - "strsim 0.11.1", -] - -[[package]] -name = "clap_derive" -version = "4.5.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "cmac" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" -dependencies = [ - "cipher", - "dbl", - "digest", -] - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array 0.14.7", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array 0.14.7", - "rand_core", - "typenum", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.100", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "data-encoding" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" - -[[package]] -name = "dbl" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "des" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" -dependencies = [ - "cipher", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "directories" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" -dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys 0.5.0", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.4.6", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.5.0", - "windows-sys 0.59.0", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "dlwrap" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76810e38c6f0f7195a0cac883d832ad514036777490d81d48665d66314debee5" -dependencies = [ - "anyhow", - "clang", - "clang-sys", - "clap 4.5.35", - "regex", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "dsa" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" -dependencies = [ - "digest", - "num-bigint-dig", - "num-traits", - "pkcs8", - "rfc6979", - "sha2", - "signature", - "zeroize", -] - -[[package]] -name = "dyn-clone" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" - -[[package]] -name = "eax" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" -dependencies = [ - "aead", - "cipher", - "cmac", - "ctr", - "subtle", -] - -[[package]] -name = "ecb" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7" -dependencies = [ - "cipher", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array 0.14.7", - "group", - "hkdf", - "pem-rfc7468", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fd-lock" -version = "4.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" -dependencies = [ - "cfg-if", - "rustix 1.0.5", - "windows-sys 0.59.0", -] - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "generic-array" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c8444bc9d71b935156cc0ccab7f622180808af7867b1daae6547d773591703" -dependencies = [ - "typenum", -] - -[[package]] -name = "gethostname" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" -dependencies = [ - "rustix 0.38.44", - "windows-targets 0.52.6", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "h2" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.9.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hickory-client" -version = "0.24.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156579a5cd8d1fc6f0df87cc21b6ee870db978a163a1ba484acd98a4eff5a6de" -dependencies = [ - "cfg-if", - "data-encoding", - "futures-channel", - "futures-util", - "hickory-proto", - "once_cell", - "radix_trie", - "rand", - "thiserror 1.0.69", - "tokio", - "tracing", -] - -[[package]] -name = "hickory-proto" -version = "0.24.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna", - "ipnet", - "once_cell", - "openssl", - "rand", - "thiserror 1.0.69", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "hickory-resolver" -version = "0.24.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" -dependencies = [ - "cfg-if", - "futures-util", - "hickory-proto", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot", - "rand", - "resolv-conf", - "smallvec", - "thiserror 1.0.69", - "tokio", - "tracing", -] - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "hostname" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" -dependencies = [ - "cfg-if", - "libc", - "windows-link", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "libc", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "idea" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" -dependencies = [ - "cipher", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "image-sequoia" -version = "0.1.0" -dependencies = [ - "anyhow", - "cbindgen", - "cdylib-link-lines", - "dirs 5.0.1", - "dlwrap", - "libc", - "log", - "regex", - "sequoia-cert-store", - "sequoia-keystore", - "sequoia-openpgp", - "sequoia-policy-config", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array 0.14.7", -] - -[[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2", - "widestring", - "windows-sys 0.48.0", - "winreg", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jiff" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "libloading" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - -[[package]] -name = "libm" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.9.0", - "libc", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memsec" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nettle" -version = "7.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e6ff4a94e5d34a1fd5abbd39418074646e2fa51b257198701330f22fcd6936" -dependencies = [ - "getrandom 0.2.15", - "libc", - "nettle-sys", - "thiserror 1.0.69", - "typenum", -] - -[[package]] -name = "nettle-sys" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a3f5406064d310d59b1a219d3c5c9a49caf4047b6496032e3f930876488c34" -dependencies = [ - "bindgen", - "cc", - "libc", - "pkg-config", - "tempfile", - "vcpkg", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "ocb3" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" -dependencies = [ - "aead", - "cipher", - "ctr", - "subtle", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "openpgp-cert-d" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd47b0b6df1022ca8a9a06791261c3153028abef191fe53aa326b7f443f2d6" -dependencies = [ - "anyhow", - "dirs 6.0.0", - "fd-lock", - "libc", - "sha1collisiondetection", - "sha2", - "tempfile", - "thiserror 2.0.12", - "walkdir", -] - -[[package]] -name = "openssl" -version = "0.10.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" -dependencies = [ - "bitflags 2.9.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p521" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" -dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core", - "sha2", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.9.0", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy 0.8.24", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror 1.0.69", -] - -[[package]] -name = "redox_users" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror 2.0.12", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "reqwest" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-registry", -] - -[[package]] -name = "resolv-conf" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48375394603e3dd4b2d64371f7148fd8c7baa2680e28741f2cb8d23b59e3d4c4" -dependencies = [ - "hostname", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.15", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest", -] - -[[package]] -name = "rsa" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rusqlite" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" -dependencies = [ - "bitflags 2.9.0", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.9.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" -dependencies = [ - "bitflags 2.9.0", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" - -[[package]] -name = "rustls-webpki" -version = "0.103.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array 0.14.7", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - -[[package]] -name = "sequoia-cert-store" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8987ed37e9931aee509c7ebc10e93b2ee5862849546c8a0c4588f3ed670b74" -dependencies = [ - "anyhow", - "crossbeam", - "dirs 5.0.1", - "gethostname", - "num_cpus", - "openpgp-cert-d", - "rayon", - "rusqlite", - "sequoia-net", - "sequoia-openpgp", - "smallvec", - "thiserror 2.0.12", - "tokio", - "url", -] - -[[package]] -name = "sequoia-directories" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01dd48960c5cf8617ab77e5c9f8ebeb55a1d694e3eabf830fa70453ffa637d5" -dependencies = [ - "anyhow", - "directories", - "same-file", - "tempfile", - "thiserror 1.0.69", -] - -[[package]] -name = "sequoia-ipc" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92579bbd37f62bbcc41e4dce7771fea395037bebaf9b8e10c20b765be8280ab" -dependencies = [ - "anyhow", - "capnp-rpc", - "ctor", - "dirs 5.0.1", - "fs2", - "lalrpop", - "lalrpop-util", - "libc", - "memsec", - "rand", - "sequoia-openpgp", - "socket2", - "tempfile", - "thiserror 2.0.12", - "tokio", - "tokio-util", - "winapi", -] - -[[package]] -name = "sequoia-keystore" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b510811048c0767a0d3196b3bb0719d999eb52a836580d794e97a2586b546347" -dependencies = [ - "anyhow", - "async-generic", - "capnp", - "capnpc", - "dirs 5.0.1", - "env_logger", - "log", - "paste", - "sequoia-directories", - "sequoia-ipc", - "sequoia-keystore-backend", - "sequoia-keystore-softkeys", - "sequoia-openpgp", - "thiserror 2.0.12", - "tokio", - "tokio-util", -] - -[[package]] -name = "sequoia-keystore-backend" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55b047f9b6412c34dc7a26a42f278205cbf1e29516feab1228edccca215f500" -dependencies = [ - "anyhow", - "async-trait", - "env_logger", - "futures", - "log", - "sequoia-openpgp", - "tempfile", - "thiserror 2.0.12", - "tokio", -] - -[[package]] -name = "sequoia-keystore-softkeys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713736e9a5277f8ff829a1efaf99c0f6c07718fe0c199f435406883313ee8742" -dependencies = [ - "anyhow", - "async-trait", - "dirs 5.0.1", - "futures", - "log", - "sequoia-keystore-backend", - "sequoia-openpgp", -] - -[[package]] -name = "sequoia-net" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ef5d37e41f53259cd3c6caac5f135351ee92f76f3ac6ee9cf771ee6e33925" -dependencies = [ - "anyhow", - "base64", - "futures-util", - "hickory-client", - "hickory-resolver", - "http", - "hyper", - "hyper-tls", - "libc", - "percent-encoding", - "reqwest", - "sequoia-openpgp", - "thiserror 1.0.69", - "tokio", - "url", - "z-base-32", -] - -[[package]] -name = "sequoia-openpgp" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015e5fc3d023418b9db98ca9a7f3e90b305872eeafe5ca45c5c32b5eb335c1e8" -dependencies = [ - "aes", - "aes-gcm", - "anyhow", - "argon2", - "base64", - "block-padding", - "blowfish", - "botan", - "buffered-reader", - "bzip2", - "camellia", - "cast5", - "cfb-mode", - "chrono", - "cipher", - "des", - "digest", - "dsa", - "dyn-clone", - "eax", - "ecb", - "ecdsa", - "ed25519", - "ed25519-dalek", - "flate2", - "getrandom 0.2.15", - "hkdf", - "idea", - "idna", - "lalrpop", - "lalrpop-util", - "libc", - "md-5", - "memsec", - "nettle", - "num-bigint-dig", - "ocb3", - "openssl", - "openssl-sys", - "p256", - "p384", - "p521", - "rand", - "rand_core", - "regex", - "regex-syntax", - "ripemd", - "rsa", - "sha1collisiondetection", - "sha2", - "sha3", - "thiserror 2.0.12", - "twofish", - "typenum", - "win-crypto-ng", - "winapi", - "x25519-dalek", - "xxhash-rust", -] - -[[package]] -name = "sequoia-policy-config" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e016b708d64857b6a97e1a331d9471b73e30ed450d247628e1a0ce236b1e597" -dependencies = [ - "anyhow", - "chrono", - "sequoia-openpgp", - "serde", - "thiserror 1.0.69", - "toml", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1collisiondetection" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f606421e4a6012877e893c399822a4ed4b089164c5969424e1b9d1e66e6964b" -dependencies = [ - "const-oid", - "digest", - "generic-array 1.2.0", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" - -[[package]] -name = "socket2" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" -dependencies = [ - "fastrand", - "getrandom 0.3.2", - "once_cell", - "rustix 1.0.5", - "windows-sys 0.59.0", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.44.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" -dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "twofish" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" -dependencies = [ - "cipher", -] - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.100", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "widestring" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" - -[[package]] -name = "win-crypto-ng" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99abfb435a71e54ab2971d8d8c32f1a7e006cdbf527f71743b1d45b93517bb92" -dependencies = [ - "cipher", - "doc-comment", - "rand_core", - "winapi", - "zeroize", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings 0.4.0", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core", - "zeroize", -] - -[[package]] -name = "xxhash-rust" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "synstructure", -] - -[[package]] -name = "z-base-32" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bf7b4a78668416e1e8a332334e26fb2f377afe707f0c6feaf6ed5f9100133b" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] diff --git a/signature/internal/sequoia/rust/Cargo.toml b/signature/internal/sequoia/rust/Cargo.toml deleted file mode 100644 index 6d78e0b402..0000000000 --- a/signature/internal/sequoia/rust/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "image-sequoia" -version = "0.1.0" -edition = "2021" -license = "LGPL-2.0-or-later" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -anyhow = "1" -dirs = "5" -libc = "0.2" -log = "0.4" -sequoia-cert-store = "0.7" -sequoia-keystore = { version = "0.7", default-features = false, features = ["softkeys"] } -sequoia-openpgp = { version = "2", default-features = false, features = ["compression"] } -sequoia-policy-config = "0.8" - -[build-dependencies] -anyhow = "1" -cbindgen = "0.24.0" -cdylib-link-lines = "0.1.4" -dlwrap = "0.3.7" -regex = "1" - -[features] -# To use a different cryptographic backend, e.g., OpenSSL, do: -# -# cargo build --release --no-default-features --features crypto-openssl - -# We explicitly do not want to enable Sequoia's decompression support. -# Hence we only select a crypto backend. -default = ["crypto-openssl"] -crypto-nettle = ["sequoia-openpgp/crypto-nettle"] -crypto-rust = ["sequoia-openpgp/crypto-rust"] -crypto-cng = ["sequoia-openpgp/crypto-cng"] -crypto-openssl = ["sequoia-openpgp/crypto-openssl"] -crypto-botan = ["sequoia-openpgp/crypto-botan"] -crypto-botan2 = ["sequoia-openpgp/crypto-botan2"] diff --git a/signature/internal/sequoia/rust/README.md b/signature/internal/sequoia/rust/README.md deleted file mode 100644 index 5e7e0a1c8d..0000000000 --- a/signature/internal/sequoia/rust/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# image-sequoia - -This directory contains the source code of a C shared library -(`libimage_sequoia.so`) that enables to use [sequoia-pgp] as a signing -backend. - -For building, you need rustc (version 1.79 or later), cargo, and -openssl-devel. For testing, you also need the `sq` command (version -1.3.0 or later). - -## Building - -To build the shared library and bindings, do: - -```console -$ PREFIX=/usr LIBDIR="\${prefix}/lib64" cargo build --release -``` - -## Installing - -Just copy the shared library in the library search path: - -```console -$ sudo cp -a rust/target/release/libimage_sequoia.so* /usr/lib64 -``` - -## Testing - -To test, in the top-level directory of containers image, do: -```console -$ LD_LIBRARY_PATH=$PWD/signature/internal/sequoia/rust/target/release \ - make BUILDTAGS=containers_image_sequoia -``` -[sequoia-pgp]: https://sequoia-pgp.org/ diff --git a/signature/internal/sequoia/rust/build.rs b/signature/internal/sequoia/rust/build.rs deleted file mode 100644 index 1df0142f0d..0000000000 --- a/signature/internal/sequoia/rust/build.rs +++ /dev/null @@ -1,121 +0,0 @@ -extern crate cbindgen; - -use std::env; -use std::path::PathBuf; - -use anyhow::Result; -use regex::Regex; - -fn main() -> Result<(), Box> { - let src = env::current_dir()?; - - let mut build_dir = PathBuf::from(&src); - if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") { - // Note: if CARGO_TARGET_DIR is absolute, this will first - // clear build_dir, which is what we want. - build_dir.push(target_dir); - } else { - build_dir.push("target"); - } - let profile = env::var_os("PROFILE").expect("PROFILE not set"); - build_dir.push(&profile); - - let bindings_dir = build_dir.join("bindings"); - let include = bindings_dir.join("sequoia.h"); - - // Generate ${CARGO_TARGET_DIR}/${PROFILE}/bindings/sequoia.h - cbindgen::Builder::new() - .with_crate(&src) - .with_language(cbindgen::Language::C) - .with_header("// SPDX-License-Identifier: Apache-2.0") - .with_pragma_once(true) - .generate() - .expect("Unable to generate bindings") - .write_to_file(&include); - - // Generate dlwrap files - dlwrap::Builder::new(&include) - .output_dir(&bindings_dir) - .symbol_regex(&Regex::new("^sequoia_")?) - .license("SPDX-License-Identifier: Apache-2.0") - .loader_basename("gosequoia") - .soname("SEQUOIA_SONAME") - .prefix("go_sequoia") - .function_prefix("go") - .header_guard("GO_SEQUOIA_H_") - .include("") - .generate()?; - - let prefix = env::var_os("PREFIX"); - let prefix: &str = match prefix.as_ref().and_then(|s| s.to_str()) { - Some(s) => s, - None => "/usr/local", - }; - let libdir = env::var_os("LIBDIR"); - let libdir: &str = match libdir.as_ref().and_then(|s| s.to_str()) { - Some(s) => s, - None => "${prefix}/lib", - }; - - // Rerun if... - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=Cargo.toml"); - println!("cargo:rerun-if-env-changed=PREFIX"); - println!("cargo:rerun-if-env-changed=LIBDIR"); - println!("cargo:rerun-if-env-changed=PROFILE"); - println!("cargo:rerun-if-env-changed=CARGO_TARGET_DIR"); - - // Set the soname. - let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let os = env::var("CARGO_CFG_TARGET_OS").unwrap(); - let env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); - - // We do not care about `_pre` and such. - let major = env::var("CARGO_PKG_VERSION_MAJOR").unwrap(); - let minor = env::var("CARGO_PKG_VERSION_MINOR").unwrap(); - let patch = env::var("CARGO_PKG_VERSION_PATCH").unwrap(); - - // libdir might contain "${prefix}". Replace it with - // the actual prefix value if found. - let libdir_resolved = libdir.replace("${prefix}", prefix); - - let linker_lines = cdylib_link_lines::shared_object_link_args( - "image_sequoia", - &major, - &minor, - &patch, - &arch, - &os, - &env, - PathBuf::from(libdir_resolved), - build_dir.clone(), - ); - - for line in linker_lines { - println!("cargo:rustc-cdylib-link-arg={}", line); - } - - #[cfg(unix)] - { - // Create a symlink. - let mut create = true; - - let mut link = build_dir.clone(); - link.push(format!("libimage_sequoia.so.{}", major)); - - if let Ok(current) = std::fs::read_link(&link) { - if current.to_str() == Some("libimage_sequoia.so") { - // Do nothing. - create = false; - } else { - // Invalid. - std::fs::remove_file(&link)?; - } - } - - if create { - std::os::unix::fs::symlink("libimage_sequoia.so", link)?; - } - } - Ok(()) -} diff --git a/signature/internal/sequoia/rust/src/error.rs b/signature/internal/sequoia/rust/src/error.rs deleted file mode 100644 index 660ed69c27..0000000000 --- a/signature/internal/sequoia/rust/src/error.rs +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.0-or-later - -#![allow(clippy::missing_safety_doc)] -use libc::c_char; -use std::ffi::CString; -use std::io; - -#[repr(C)] -pub enum SequoiaErrorKind { - Unknown, - InvalidArgument, - IoError, -} - -#[repr(C)] -pub struct SequoiaError { - kind: SequoiaErrorKind, - message: *mut c_char, -} - -impl Drop for SequoiaError { - fn drop(&mut self) { - unsafe { - let _ = CString::from_raw(self.message); - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_error_free(err_ptr: *mut SequoiaError) { - drop(Box::from_raw(err_ptr)) -} - -pub unsafe fn set_error_from(err_ptr: *mut *mut SequoiaError, err: anyhow::Error) { - if !err_ptr.is_null() { - let kind = if err.is::() { - SequoiaErrorKind::IoError - } else { - SequoiaErrorKind::Unknown - }; - - *err_ptr = Box::into_raw(Box::new(SequoiaError { - kind, - message: CString::from_vec_unchecked(err.to_string().into()).into_raw(), - })); - } -} diff --git a/signature/internal/sequoia/rust/src/lib.rs b/signature/internal/sequoia/rust/src/lib.rs deleted file mode 100644 index 1f4f629acd..0000000000 --- a/signature/internal/sequoia/rust/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.0-or-later - -mod error; -pub use crate::error::*; - -mod signature; -pub use crate::signature::*; diff --git a/signature/internal/sequoia/rust/src/signature.rs b/signature/internal/sequoia/rust/src/signature.rs deleted file mode 100644 index 7b70334500..0000000000 --- a/signature/internal/sequoia/rust/src/signature.rs +++ /dev/null @@ -1,433 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.0-or-later - -#![allow(clippy::missing_safety_doc)] -use anyhow::Context as _; -use libc::{c_char, size_t}; -use openpgp::cert::prelude::*; -use openpgp::parse::{stream::*, Parse}; -use openpgp::policy::StandardPolicy; -use openpgp::serialize::stream::{LiteralWriter, Message, Signer}; -use openpgp::KeyHandle; -use sequoia_cert_store::{Store as _, StoreUpdate as _}; -use sequoia_openpgp as openpgp; -use sequoia_policy_config::ConfiguredStandardPolicy; -use std::ffi::{CStr, CString, OsStr}; -use std::fs; -use std::io::{Read, Write}; -use std::os::unix::ffi::OsStrExt; -use std::path::Path; -use std::ptr; -use std::slice; -use std::sync::Arc; - -use crate::{set_error_from, SequoiaError}; - -pub struct SequoiaMechanism<'a> { - keystore: sequoia_keystore::Keystore, - certstore: Arc>, - policy: StandardPolicy<'a>, -} - -impl<'a> SequoiaMechanism<'a> { - fn from_directory(dir: impl AsRef) -> Result { - let home_dir = dir.as_ref().to_path_buf(); - - let keystore_dir = home_dir.join("data").join("keystore"); - let context = sequoia_keystore::Context::configure() - .home(&keystore_dir) - .build()?; - let keystore = sequoia_keystore::Keystore::connect(&context)?; - - let certstore_dir = home_dir.join("data").join("pgp.cert.d"); - fs::create_dir_all(&certstore_dir)?; - let certstore = sequoia_cert_store::CertStore::open(&certstore_dir)?; - - let mut policy = ConfiguredStandardPolicy::new(); - policy.parse_default_config()?; - let policy = policy.build(); - - Ok(Self { - keystore, - certstore: Arc::new(certstore), - policy, - }) - } - - fn ephemeral() -> Result { - let context = sequoia_keystore::Context::configure().ephemeral().build()?; - let certstore = Arc::new(sequoia_cert_store::CertStore::empty()); - let mut policy = ConfiguredStandardPolicy::new(); - policy.parse_default_config()?; - let policy = policy.build(); - Ok(Self { - keystore: sequoia_keystore::Keystore::connect(&context)?, - certstore, - policy, - }) - } - - fn import_keys(&mut self, blob: &[u8]) -> Result { - let mut softkeys = None; - for mut backend in self.keystore.backends()?.into_iter() { - if backend.id()? == "softkeys" { - softkeys = Some(backend); - break; - } - } - - let mut softkeys = if let Some(softkeys) = softkeys { - softkeys - } else { - return Err(anyhow::anyhow!("softkeys backend is not configured.")); - }; - - let mut key_handles = vec![]; - for r in CertParser::from_bytes(blob)? { - let cert = match r { - Ok(cert) => cert, - Err(err) => { - log::info!("Error reading cert: {}", err); - continue; - } - }; - - let _ = softkeys.import(&cert)?; - - key_handles.push(CString::new(cert.fingerprint().to_hex().as_bytes()).unwrap()); - self.certstore - .update(Arc::new(sequoia_cert_store::LazyCert::from(cert)))?; - } - Ok(SequoiaImportResult { key_handles }) - } - - fn sign( - &mut self, - key_handle: &str, - password: Option<&str>, - data: &[u8], - ) -> Result, anyhow::Error> { - let primary_key_handle: KeyHandle = key_handle.parse()?; - let certs = self - .certstore - .lookup_by_cert_or_subkey(&primary_key_handle) - .with_context(|| format!("Failed to load {} from certificate store", key_handle))? - .into_iter() - .filter_map(|cert| match cert.to_cert() { - Ok(cert) => Some(cert.clone()), - Err(_) => None, - }) - .collect::>(); - - let mut signing_key_handles: Vec = vec![]; - for cert in certs { - for ka in cert.keys().with_policy(&self.policy, None).for_signing() { - signing_key_handles.push(ka.key().fingerprint().into()); - } - } - - if signing_key_handles.is_empty() { - return Err(anyhow::anyhow!( - "No matching signing key for {}", - key_handle - )); - } - - let mut keys = self.keystore.find_key(signing_key_handles[0].clone())?; - - if keys.is_empty() { - return Err(anyhow::anyhow!("No matching key in keystore")); - } - if let Some(password) = password { - keys[0].unlock(password.into())?; - } - - let mut sink = vec![]; - { - let message = Message::new(&mut sink); - let message = Signer::new(message, &mut keys[0])?.build()?; - let mut message = LiteralWriter::new(message).build()?; - message.write_all(data)?; - message.finalize()?; - } - Ok(sink) - } - - fn verify(&mut self, signature: &[u8]) -> Result { - if signature.is_empty() { - return Err(anyhow::anyhow!("empty signature")); - } - - let h = Helper { - certstore: self.certstore.clone(), - signer: Default::default(), - }; - let mut policy = ConfiguredStandardPolicy::new(); - policy.parse_default_config()?; - let policy = policy.build(); - - let mut v = VerifierBuilder::from_bytes(signature)?.with_policy(&policy, None, h)?; - let mut content = Vec::new(); - v.read_to_end(&mut content)?; - - assert!(v.message_processed()); - - match &v.helper_ref().signer { - Some(signer) => Ok(SequoiaVerificationResult { - content, - signer: CString::new(signer.fingerprint().to_hex().as_bytes()).unwrap(), - }), - None => Err(anyhow::anyhow!("No valid signature")), - } - } -} - -struct Helper<'a> { - certstore: Arc>, - signer: Option, -} - -impl<'a> VerificationHelper for Helper<'a> { - fn get_certs(&mut self, ids: &[openpgp::KeyHandle]) -> openpgp::Result> { - let mut certs = Vec::new(); - for id in ids { - let matches = self.certstore.lookup_by_cert_or_subkey(id); - for lc in matches? { - certs.push(lc.to_cert()?.clone()); - } - } - Ok(certs) - } - - fn check(&mut self, structure: MessageStructure) -> openpgp::Result<()> { - for layer in structure { - match layer { - MessageLayer::Compression { algo } => log::info!("Compressed using {}", algo), - MessageLayer::Encryption { - sym_algo, - aead_algo, - } => { - if let Some(aead_algo) = aead_algo { - log::info!("Encrypted and protected using {}/{}", sym_algo, aead_algo); - } else { - log::info!("Encrypted using {}", sym_algo); - } - } - MessageLayer::SignatureGroup { ref results } => { - let result = results.iter().find(|r| r.is_ok()); - if let Some(result) = result { - self.signer = Some(result.as_ref().unwrap().ka.cert().to_owned()); - return Ok(()); - } - } - } - } - Err(anyhow::anyhow!("No valid signature")) - } -} - -pub struct SequoiaSignature { - data: Vec, -} - -pub struct SequoiaVerificationResult { - content: Vec, - signer: CString, -} - -#[derive(Default)] -pub struct SequoiaImportResult { - key_handles: Vec, -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_mechanism_new_from_directory<'a>( - dir_ptr: *const c_char, - err_ptr: *mut *mut SequoiaError, -) -> *mut SequoiaMechanism<'a> { - let c_dir = CStr::from_ptr(dir_ptr); - let os_dir = OsStr::from_bytes(c_dir.to_bytes()); - match SequoiaMechanism::from_directory(os_dir) { - Ok(mechanism) => Box::into_raw(Box::new(mechanism)), - Err(e) => { - set_error_from(err_ptr, e); - ptr::null_mut() - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_mechanism_new_ephemeral<'a>( - err_ptr: *mut *mut SequoiaError, -) -> *mut SequoiaMechanism<'a> { - match SequoiaMechanism::ephemeral() { - Ok(mechanism) => Box::into_raw(Box::new(mechanism)), - Err(e) => { - set_error_from(err_ptr, e); - ptr::null_mut() - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_mechanism_free(mechanism_ptr: *mut SequoiaMechanism) { - drop(Box::from_raw(mechanism_ptr)) -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_signature_free(signature_ptr: *mut SequoiaSignature) { - drop(Box::from_raw(signature_ptr)) -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_signature_get_data( - signature_ptr: *const SequoiaSignature, - data_len: *mut size_t, -) -> *const u8 { - assert!(!signature_ptr.is_null()); - *data_len = (*signature_ptr).data.len(); - (*signature_ptr).data.as_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_verification_result_free( - result_ptr: *mut SequoiaVerificationResult, -) { - assert!(!result_ptr.is_null()); - drop(Box::from_raw(result_ptr)) -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_verification_result_get_content( - result_ptr: *const SequoiaVerificationResult, - data_len: *mut size_t, -) -> *const u8 { - assert!(!result_ptr.is_null()); - *data_len = (*result_ptr).content.len(); - (*result_ptr).content.as_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_verification_result_get_signer( - result_ptr: *const SequoiaVerificationResult, -) -> *const c_char { - assert!(!result_ptr.is_null()); - (*result_ptr).signer.as_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_sign( - mechanism_ptr: *mut SequoiaMechanism, - key_handle_ptr: *const c_char, - password_ptr: *const c_char, - data_ptr: *const u8, - data_len: size_t, - err_ptr: *mut *mut SequoiaError, -) -> *mut SequoiaSignature { - assert!(!mechanism_ptr.is_null()); - assert!(!key_handle_ptr.is_null()); - assert!(!data_ptr.is_null()); - - let key_handle = match CStr::from_ptr(key_handle_ptr).to_str() { - Ok(key_handle) => key_handle, - Err(e) => { - set_error_from(err_ptr, e.into()); - return ptr::null_mut(); - } - }; - - let password = if password_ptr.is_null() { - None - } else { - match CStr::from_ptr(password_ptr).to_str() { - Ok(password) => Some(password), - Err(e) => { - set_error_from(err_ptr, e.into()); - return ptr::null_mut(); - } - } - }; - - let data = slice::from_raw_parts(data_ptr, data_len); - match (*mechanism_ptr).sign(key_handle, password, data) { - Ok(signature) => Box::into_raw(Box::new(SequoiaSignature { data: signature })), - Err(e) => { - set_error_from(err_ptr, e); - ptr::null_mut() - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_verify( - mechanism_ptr: *mut SequoiaMechanism, - signature_ptr: *const u8, - signature_len: size_t, - err_ptr: *mut *mut SequoiaError, -) -> *mut SequoiaVerificationResult { - assert!(!mechanism_ptr.is_null()); - - let signature = slice::from_raw_parts(signature_ptr, signature_len); - match (*mechanism_ptr).verify(signature) { - Ok(result) => Box::into_raw(Box::new(result)), - Err(e) => { - set_error_from(err_ptr, e); - ptr::null_mut() - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_import_result_free(result_ptr: *mut SequoiaImportResult) { - drop(Box::from_raw(result_ptr)) -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_import_result_get_count( - result_ptr: *const SequoiaImportResult, -) -> size_t { - assert!(!result_ptr.is_null()); - - (*result_ptr).key_handles.len() -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_import_result_get_content( - result_ptr: *const SequoiaImportResult, - index: size_t, - err_ptr: *mut *mut SequoiaError, -) -> *const c_char { - assert!(!result_ptr.is_null()); - - if index >= (*result_ptr).key_handles.len() { - set_error_from(err_ptr, anyhow::anyhow!("No matching key handle")); - return ptr::null(); - } - let key_handle = &(*result_ptr).key_handles[index]; - key_handle.as_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn sequoia_import_keys( - mechanism_ptr: *mut SequoiaMechanism, - blob_ptr: *const u8, - blob_len: size_t, - err_ptr: *mut *mut SequoiaError, -) -> *mut SequoiaImportResult { - assert!(!mechanism_ptr.is_null()); - - let blob = slice::from_raw_parts(blob_ptr, blob_len); - if blob.is_empty() { - let result = SequoiaImportResult { - ..Default::default() - }; - return Box::into_raw(Box::new(result)); - } - - match (*mechanism_ptr).import_keys(blob) { - Ok(result) => Box::into_raw(Box::new(result)), - Err(e) => { - set_error_from(err_ptr, e); - ptr::null_mut() - } - } -} diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index 86785ecb15..6646b43f43 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -147,9 +147,9 @@ func (m *SigningMechanism) SupportsSigning() error { } func Init() error { - if C.go_sequoia_ensure_library(C.CString("libimage_sequoia.so.0"), + if C.go_sequoia_ensure_library(C.CString("libpodman_sequoia.so.0"), C.RTLD_NOW|C.RTLD_GLOBAL) < 0 { - return errors.New("unable to load libimage_sequoia.so.0") + return errors.New("unable to load libpodman_sequoia.so.0") } return nil } diff --git a/signature/internal/sequoia/sequoia.h b/signature/internal/sequoia/sequoia.h index b60c566f89..e0e2189267 100644 --- a/signature/internal/sequoia/sequoia.h +++ b/signature/internal/sequoia/sequoia.h @@ -8,11 +8,20 @@ #include typedef enum SequoiaErrorKind { - Unknown, - InvalidArgument, - IoError, + SEQUOIA_ERROR_KIND_UNKNOWN, + SEQUOIA_ERROR_KIND_INVALID_ARGUMENT, + SEQUOIA_ERROR_KIND_IO_ERROR, } SequoiaErrorKind; +typedef enum SequoiaLogLevel { + SEQUOIA_LOG_LEVEL_UNKNOWN, + SEQUOIA_LOG_LEVEL_ERROR, + SEQUOIA_LOG_LEVEL_WARN, + SEQUOIA_LOG_LEVEL_INFO, + SEQUOIA_LOG_LEVEL_DEBUG, + SEQUOIA_LOG_LEVEL_TRACE, +} SequoiaLogLevel; + typedef struct SequoiaImportResult SequoiaImportResult; typedef struct SequoiaMechanism SequoiaMechanism; @@ -23,7 +32,7 @@ typedef struct SequoiaVerificationResult SequoiaVerificationResult; typedef struct SequoiaError { enum SequoiaErrorKind kind; - const char *message; + char *message; } SequoiaError; void sequoia_error_free(struct SequoiaError *err_ptr); @@ -71,3 +80,6 @@ struct SequoiaImportResult *sequoia_import_keys(struct SequoiaMechanism *mechani const uint8_t *blob_ptr, size_t blob_len, struct SequoiaError **err_ptr); + +int sequoia_set_logger_consumer(void (*consumer)(enum SequoiaLogLevel level, const char *message), + struct SequoiaError **err_ptr); diff --git a/signature/internal/sequoia/sequoia_test.go b/signature/internal/sequoia/sequoia_test.go index 2700d9b7cb..f46d4dbd6b 100644 --- a/signature/internal/sequoia/sequoia_test.go +++ b/signature/internal/sequoia/sequoia_test.go @@ -6,12 +6,13 @@ import ( "bytes" "errors" "fmt" - "github.com/containers/image/v5/signature/internal/sequoia" "io" "os" "os/exec" "regexp" "testing" + + "github.com/containers/image/v5/signature/internal/sequoia" ) func checkCliVersion(version string) error { @@ -47,11 +48,6 @@ func generateKey(dir string, email string) (string, error) { return fingerprint, nil } -func exportKey(dir string, fingerprint string) ([]byte, error) { - cmd := exec.Command("sq", "--home", dir, "key", "export", "--cert", fingerprint) - return cmd.Output() -} - func exportCert(dir string, fingerprint string) ([]byte, error) { cmd := exec.Command("sq", "--home", dir, "cert", "export", "--cert", fingerprint) return cmd.Output() @@ -133,91 +129,6 @@ func TestGenerateSignVerify(t *testing.T) { } } -func TestImportSignVerify(t *testing.T) { - if err := checkCliVersion("1.3.0"); err != nil { - t.Skipf("sq not usable: %v", err) - } - dir := t.TempDir() - fingerprint, err := generateKey(dir, "foo@example.org") - if err != nil { - t.Fatalf("unable to generate key: %v", err) - } - output, err := exportKey(dir, fingerprint) - if err != nil { - t.Fatalf("unable to export key: %v", err) - } - newDir := t.TempDir() - m, err := sequoia.NewMechanismFromDirectory(newDir) - if err != nil { - t.Fatalf("unable to initialize a mechanism: %v", err) - } - keyIdentities, err := m.ImportKeys(output) - if err != nil { - t.Fatalf("unable to import key: %v", err) - } - if len(keyIdentities) != 1 || keyIdentities[0] != fingerprint { - t.Fatalf("keyIdentity differ from the original: %v != %v", - keyIdentities[0], fingerprint) - } - input := []byte("Hello, world!") - sig, err := m.Sign(input, fingerprint) - if err != nil { - t.Fatalf("unable to sign: %v", err) - } - contents, keyIdentity, err := m.Verify(sig) - if err != nil { - t.Fatalf("unable to verify: %v", err) - } - if !bytes.Equal(contents, input) { - t.Fatalf("contents differ from the original") - } - if keyIdentity != fingerprint { - t.Fatalf("keyIdentity differ from the original") - } -} - -func TestImportSignVerifyEphemeral(t *testing.T) { - if err := checkCliVersion("1.3.0"); err != nil { - t.Skipf("sq not usable: %v", err) - } - dir := t.TempDir() - fingerprint, err := generateKey(dir, "foo@example.org") - if err != nil { - t.Fatalf("unable to generate key: %v", err) - } - output, err := exportKey(dir, fingerprint) - if err != nil { - t.Fatalf("unable to export key: %v", err) - } - m, err := sequoia.NewEphemeralMechanism() - if err != nil { - t.Fatalf("unable to initialize a mechanism: %v", err) - } - keyIdentities, err := m.ImportKeys(output) - if err != nil { - t.Fatalf("unable to import key: %v", err) - } - if len(keyIdentities) != 1 || keyIdentities[0] != fingerprint { - t.Fatalf("keyIdentity differ from the original: %v != %v", - keyIdentities[0], fingerprint) - } - input := []byte("Hello, world!") - sig, err := m.Sign(input, fingerprint) - if err != nil { - t.Fatalf("unable to sign: %v", err) - } - contents, keyIdentity, err := m.Verify(sig) - if err != nil { - t.Fatalf("unable to verify: %v", err) - } - if !bytes.Equal(contents, input) { - t.Fatalf("contents differ from the original") - } - if keyIdentity != fingerprint { - t.Fatalf("keyIdentity differ from the original") - } -} - func TestMain(m *testing.M) { err := sequoia.Init() if err != nil { From 211ffc85fb8621bb914baae64a29339a7d361fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 9 Jun 2025 17:10:43 +0200 Subject: [PATCH 03/18] Allow using sequoia in macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use the correct library name - Allow specifying a library path at compile time Example usage: > make BUILDTAGS="btrfs_noversion containers_image_sequoia" SEQUOIA_SONAME_DIR=$(pwd)/signature/internal/sequoia/rust/target/release Signed-off-by: Miloslav Trmač --- Makefile | 3 ++- README.md | 2 +- signature/internal/sequoia/sequoia.go | 25 +++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 94a2f0d44a..9f57cc2b06 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,10 @@ endif # when cross compiling _for_ a Darwin or windows host, then we must use openpgp BUILD_TAGS_WINDOWS_CROSS = containers_image_openpgp BUILD_TAGS_DARWIN_CROSS = containers_image_openpgp +SEQUOIA_SONAME_DIR = BUILDTAGS = -BUILDFLAGS := -tags "$(BUILDTAGS)" +BUILDFLAGS := -tags "$(BUILDTAGS)" -ldflags '-X github.com/containers/image/v5/signature/internal/sequoia.sequoiaLibraryDir='"$(SEQUOIA_SONAME_DIR)" # Extra flags passed to go test TESTFLAGS := diff --git a/README.md b/README.md index 35958e5a43..be0c709e72 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ or use the build tags described below to avoid the dependencies (e.g. using `go - `containers_image_docker_daemon_stub`: Don’t import the `docker-daemon:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. - `containers_image_openpgp`: Use a Golang-only OpenPGP implementation for signature verification instead of the default cgo/gpgme-based implementation; the primary downside is that creating new signatures with the Golang-only implementation is not supported. -- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations. This requires a support shared library installed on the system. Install https://github.com/ueno/podman-sequoia . +- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations. This requires a support shared library installed on the system. Install https://github.com/ueno/podman-sequoia , and potentially update build configuration to point at it (compare `SEQUOIA_SONAME_DIR` in `Makefile`). - `containers_image_storage_stub`: Don’t import the `containers-storage:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. ## [Contributing](CONTRIBUTING.md) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index 6646b43f43..dec02b4f18 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -10,9 +10,18 @@ import "C" import ( "errors" + "fmt" + "path/filepath" + "runtime" "unsafe" ) +// sequoiaLibraryDir is the path to the directory where libpodman_sequoia is installed, +// if it is not in the platform’s default library path. +// You can override this at build time with +// -ldflags '-X github.com/containers/image/v5/signature/sequoia.sequoiaLibraryDir=$your_path' +var sequoiaLibraryDir = "" + type SigningMechanism struct { mechanism *C.SequoiaMechanism } @@ -147,9 +156,21 @@ func (m *SigningMechanism) SupportsSigning() error { } func Init() error { - if C.go_sequoia_ensure_library(C.CString("libpodman_sequoia.so.0"), + var soName string + switch runtime.GOOS { + case "linux": + soName = "libpodman_sequoia.so.0" + case "darwin": + soName = "libpodman_sequoia.dylib" + default: + return fmt.Errorf("Unhandled OS %q in sequoia initialization", runtime.GOOS) + } + if sequoiaLibraryDir != "" { + soName = filepath.Join(sequoiaLibraryDir, soName) + } + if C.go_sequoia_ensure_library(C.CString(soName), C.RTLD_NOW|C.RTLD_GLOBAL) < 0 { - return errors.New("unable to load libpodman_sequoia.so.0") + return fmt.Errorf("unable to load %q", soName) } return nil } From ad7f039157d955a8f62770b71d398db11007cfa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 25 Jul 2025 21:34:00 +0200 Subject: [PATCH 04/18] Update the documentation of sequoiaSigningMechanism.Verify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... to match the recent more specific subkey validation semantics. Should not change behavior. Signed-off-by: Miloslav Trmač --- signature/mechanism_sequoia.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/signature/mechanism_sequoia.go b/signature/mechanism_sequoia.go index f1825145c7..69a0237ad3 100644 --- a/signature/mechanism_sequoia.go +++ b/signature/mechanism_sequoia.go @@ -3,10 +3,11 @@ package signature import ( - "github.com/containers/image/v5/signature/internal/sequoia" - "github.com/containers/storage/pkg/homedir" "os" "path" + + "github.com/containers/image/v5/signature/internal/sequoia" + "github.com/containers/storage/pkg/homedir" ) // A GPG/OpenPGP signing mechanism, implemented using Sequoia. @@ -108,7 +109,10 @@ func (m *sequoiaSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte return m.inner.Sign(input, keyIdentity) } -// Verify parses unverifiedSignature and returns the content and the signer's identity +// Verify parses unverifiedSignature and returns the content and the signer's identity. +// For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity +// is expected to be one of the values returned by NewEphemeralGPGSigningMechanism, +// or the mechanism should implement signingMechanismWithVerificationIdentityLookup. func (m *sequoiaSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) { return m.inner.Verify(unverifiedSignature) } From 79eb8840d7b87dac8c245c757cfa441fdb18c424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 7 Jul 2025 23:02:12 +0200 Subject: [PATCH 05/18] Don't leak SequoiaMechanism instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 1 + 1 file changed, 1 insertion(+) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index dec02b4f18..4948eb8535 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -148,6 +148,7 @@ func (m *SigningMechanism) ImportKeys(blob []byte) ([]string, error) { } func (m *SigningMechanism) Close() error { + C.go_sequoia_mechanism_free(m.mechanism) return nil } From 6da5b5d5d4fce0e33421b86aa3d09d294165e54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 11 Jul 2025 16:59:39 +0200 Subject: [PATCH 06/18] Add missing error handling to go_sequoia_import_result_get_content . MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index 4948eb8535..c785a9480e 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -140,7 +140,12 @@ func (m *SigningMechanism) ImportKeys(blob []byte) ([]string, error) { keyIdentities := []string{} count := C.go_sequoia_import_result_get_count(result) for i := C.size_t(0); i < count; i++ { + var cerr *C.SequoiaError cKeyIdentity := C.go_sequoia_import_result_get_content(result, i, &cerr) + if cerr != nil { + defer C.go_sequoia_error_free(cerr) + return nil, errors.New(C.GoString(cerr.message)) + } keyIdentities = append(keyIdentities, C.GoString(cKeyIdentity)) } From 164ef4104524984a4476345e5abeaa767d1d7080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 11 Jul 2025 17:01:49 +0200 Subject: [PATCH 07/18] Fix a memory leak when loading libpodman_sequoia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index c785a9480e..c9269e0885 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -174,7 +174,9 @@ func Init() error { if sequoiaLibraryDir != "" { soName = filepath.Join(sequoiaLibraryDir, soName) } - if C.go_sequoia_ensure_library(C.CString(soName), + cSOName := C.CString(soName) + defer C.free(unsafe.Pointer(cSOName)) + if C.go_sequoia_ensure_library(cSOName, C.RTLD_NOW|C.RTLD_GLOBAL) < 0 { return fmt.Errorf("unable to load %q", soName) } From 2d9475ed596c444a389d7efb2cbe0e980ded91a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 27 Jun 2025 14:30:07 +0200 Subject: [PATCH 08/18] Modify signature/internal/sequoia tests to run in the same package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should not change test behavior, merely to be more similar to the rest of the codebase. Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia_test.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/signature/internal/sequoia/sequoia_test.go b/signature/internal/sequoia/sequoia_test.go index f46d4dbd6b..1b73a5922d 100644 --- a/signature/internal/sequoia/sequoia_test.go +++ b/signature/internal/sequoia/sequoia_test.go @@ -1,6 +1,6 @@ //go:build containers_image_sequoia -package sequoia_test +package sequoia import ( "bytes" @@ -11,8 +11,6 @@ import ( "os/exec" "regexp" "testing" - - "github.com/containers/image/v5/signature/internal/sequoia" ) func checkCliVersion(version string) error { @@ -58,7 +56,7 @@ func TestNewMechanismFromDirectory(t *testing.T) { t.Skipf("sq not usable: %v", err) } dir := t.TempDir() - _, err := sequoia.NewMechanismFromDirectory(dir) + _, err := NewMechanismFromDirectory(dir) if err != nil { t.Fatalf("unable to initialize a mechanism: %v", err) } @@ -66,7 +64,7 @@ func TestNewMechanismFromDirectory(t *testing.T) { if err != nil { t.Fatalf("unable to generate key: %v", err) } - _, err = sequoia.NewMechanismFromDirectory(dir) + _, err = NewMechanismFromDirectory(dir) if err != nil { t.Fatalf("unable to initialize a mechanism: %v", err) } @@ -85,7 +83,7 @@ func TestNewEphemeralMechanism(t *testing.T) { if err != nil { t.Fatalf("unable to export cert: %v", err) } - m, err := sequoia.NewEphemeralMechanism() + m, err := NewEphemeralMechanism() if err != nil { t.Fatalf("unable to initialize a mechanism: %v", err) } @@ -108,7 +106,7 @@ func TestGenerateSignVerify(t *testing.T) { if err != nil { t.Fatalf("unable to generate key: %v", err) } - m, err := sequoia.NewMechanismFromDirectory(dir) + m, err := NewMechanismFromDirectory(dir) if err != nil { t.Fatalf("unable to initialize a mechanism: %v", err) } @@ -130,7 +128,7 @@ func TestGenerateSignVerify(t *testing.T) { } func TestMain(m *testing.M) { - err := sequoia.Init() + err := Init() if err != nil { panic(err) } From d673d2ace72558b5f9b36bb3a603305eeebe3498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Wed, 25 Jun 2025 21:32:32 +0200 Subject: [PATCH 09/18] Add a ~representative test of the typical workflow to sequoia.SigningMechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia_test.go | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/signature/internal/sequoia/sequoia_test.go b/signature/internal/sequoia/sequoia_test.go index 1b73a5922d..01f200cee3 100644 --- a/signature/internal/sequoia/sequoia_test.go +++ b/signature/internal/sequoia/sequoia_test.go @@ -11,6 +11,9 @@ import ( "os/exec" "regexp" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func checkCliVersion(version string) error { @@ -127,6 +130,40 @@ func TestGenerateSignVerify(t *testing.T) { } } +func TestSignThenVerifyEphemeral(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) + } + dir := t.TempDir() + fingerprint, err := generateKey(dir, "foo@example.org") + require.NoError(t, err) + publicKey, err := exportCert(dir, fingerprint) + require.NoError(t, err) + m1, err := NewMechanismFromDirectory(dir) + require.NoError(t, err) + defer m1.Close() + + input := []byte("Hello, world!") + sig, err := m1.Sign(input, fingerprint) + require.NoError(t, err) + + m2, err := NewEphemeralMechanism() + require.NoError(t, err) + defer m2.Close() + + _, _, err = m2.Verify(sig) // With no public key, verification should fail + assert.Error(t, err) + + keyIdentities, err := m2.ImportKeys(publicKey) + require.NoError(t, err) + require.Len(t, keyIdentities, 1) + require.Equal(t, fingerprint, keyIdentities[0]) + contents, keyIdentity, err := m2.Verify(sig) + require.NoError(t, err) + assert.Equal(t, input, contents) + assert.Equal(t, keyIdentity, fingerprint) +} + func TestMain(m *testing.M) { err := Init() if err != nil { From 80364d75a2a3d43e4eb86e322b0ef920ae103670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 7 Jul 2025 23:02:52 +0200 Subject: [PATCH 10/18] Remove SupportsSigning from sequoia.SigningMechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can be handled in callers - and it's better to do based on .Init() outcomes. Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 4 ---- signature/mechanism_sequoia.go | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index c9269e0885..2c9b66806a 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -157,10 +157,6 @@ func (m *SigningMechanism) Close() error { return nil } -func (m *SigningMechanism) SupportsSigning() error { - return nil -} - func Init() error { var soName string switch runtime.GOOS { diff --git a/signature/mechanism_sequoia.go b/signature/mechanism_sequoia.go index 69a0237ad3..4c08ac472c 100644 --- a/signature/mechanism_sequoia.go +++ b/signature/mechanism_sequoia.go @@ -94,7 +94,7 @@ func (m *sequoiaSigningMechanism) Close() error { // SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError. func (m *sequoiaSigningMechanism) SupportsSigning() error { - return m.inner.SupportsSigning() + return nil } // Sign creates a (non-detached) signature of input using keyIdentity and passphrase. From 89eaf0f7bb020ef5af4e31595ecee490a816735d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 30 Jun 2025 19:57:15 +0200 Subject: [PATCH 11/18] Move sequoia initialization out of init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Allow using c/image without loading sequoia if GO_SEQUOIA_ENABLE_DLOPEN is used, and nothing uses the Sequoia code at runtime. - Allow adding ~independent users of signature/internal/sequoia, without having to coordinate to call Init at least once. We will add signature/simplesequoia to benefit from this. Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 8 +++++++- signature/mechanism_sequoia.go | 15 ++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index 2c9b66806a..7f05bfe729 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -13,6 +13,7 @@ import ( "fmt" "path/filepath" "runtime" + "sync" "unsafe" ) @@ -157,7 +158,8 @@ func (m *SigningMechanism) Close() error { return nil } -func Init() error { +// initOnce should only be called by Init. +func initOnce() error { var soName string switch runtime.GOOS { case "linux": @@ -178,3 +180,7 @@ func Init() error { } return nil } + +// Init ensures the libpodman_sequoia library is available. +// It is safe to call from arbitrary goroutines. +var Init = sync.OnceValue(initOnce) diff --git a/signature/mechanism_sequoia.go b/signature/mechanism_sequoia.go index 4c08ac472c..3c8ef52c19 100644 --- a/signature/mechanism_sequoia.go +++ b/signature/mechanism_sequoia.go @@ -18,6 +18,10 @@ type sequoiaSigningMechanism struct { // newGPGSigningMechanismInDirectory returns a new GPG/OpenPGP signing mechanism, using optionalDir if not empty. // The caller must call .Close() on the returned SigningMechanism. func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWithPassphrase, error) { + if err := sequoia.Init(); err != nil { + return nil, err + } + // For compatibility reasons, we allow both sequoiaHome and // gpgHome to be the same directory as designated by // optionalDir or GNUPGHOME. @@ -70,6 +74,10 @@ func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWith // of these keys. // The caller must call .Close() on the returned SigningMechanism. func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) { + if err := sequoia.Init(); err != nil { + return nil, nil, err + } + mech, err := sequoia.NewEphemeralMechanism() if err != nil { return nil, nil, err @@ -125,10 +133,3 @@ func (m *sequoiaSigningMechanism) Verify(unverifiedSignature []byte) (contents [ func (m *sequoiaSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) { return gpgUntrustedSignatureContents(untrustedSignature) } - -func init() { - err := sequoia.Init() - if err != nil { - panic("sequoia cannot be loaded: " + err.Error()) - } -} From b57076c9a92c12072ad25c93ed837ccb9f02745f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 30 Jun 2025 22:28:43 +0200 Subject: [PATCH 12/18] Allow using the default Sequoia home MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't reasonably unit-test the $HOME variant; tested manually. Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index 7f05bfe729..e088e4fdea 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -27,12 +27,17 @@ type SigningMechanism struct { mechanism *C.SequoiaMechanism } +// NewMechanismFromDirectory initializes a mechanism using (user-managed) Sequoia state +// in dir, which can be "" to indicate the default (using $SEQUOIA_HOME or the default home directory location). func NewMechanismFromDirectory( dir string, ) (*SigningMechanism, error) { var cerr *C.SequoiaError - cDir := C.CString(dir) - defer C.free(unsafe.Pointer(cDir)) + var cDir *C.char + if dir != "" { + cDir = C.CString(dir) + defer C.free(unsafe.Pointer(cDir)) + } cMechanism := C.go_sequoia_mechanism_new_from_directory(cDir, &cerr) if cMechanism == nil { defer C.go_sequoia_error_free(cerr) From bee9da73290aca15e1c9b7ec8ba443415d992125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 24 Jun 2025 01:16:38 +0200 Subject: [PATCH 13/18] Direct Rust logging to logrus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default, the Rust logging output is silently discarded. Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index e088e4fdea..ae175bcf70 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -6,6 +6,8 @@ package sequoia // #include "gosequoia.h" // #include // #include +// typedef void (*sequoia_logger_consumer_t) (enum SequoiaLogLevel level, char *message); +// extern void sequoia_logrus_logger (enum SequoiaLogLevel level, char *message); import "C" import ( @@ -15,6 +17,8 @@ import ( "runtime" "sync" "unsafe" + + "github.com/sirupsen/logrus" ) // sequoiaLibraryDir is the path to the directory where libpodman_sequoia is installed, @@ -163,6 +167,28 @@ func (m *SigningMechanism) Close() error { return nil } +//export sequoia_logrus_logger +func sequoia_logrus_logger(level C.enum_SequoiaLogLevel, message *C.char) { + var logrusLevel logrus.Level + switch level { + case C.SEQUOIA_LOG_LEVEL_ERROR: + logrusLevel = logrus.ErrorLevel + case C.SEQUOIA_LOG_LEVEL_WARN: + logrusLevel = logrus.WarnLevel + case C.SEQUOIA_LOG_LEVEL_INFO: + logrusLevel = logrus.InfoLevel + case C.SEQUOIA_LOG_LEVEL_DEBUG: + logrusLevel = logrus.DebugLevel + case C.SEQUOIA_LOG_LEVEL_TRACE: + logrusLevel = logrus.TraceLevel + case C.SEQUOIA_LOG_LEVEL_UNKNOWN: + fallthrough + default: + logrusLevel = logrus.ErrorLevel // Should never happen + } + logrus.StandardLogger().Log(logrusLevel, C.GoString(message)) +} + // initOnce should only be called by Init. func initOnce() error { var soName string @@ -183,6 +209,12 @@ func initOnce() error { C.RTLD_NOW|C.RTLD_GLOBAL) < 0 { return fmt.Errorf("unable to load %q", soName) } + + var cerr *C.SequoiaError + if C.go_sequoia_set_logger_consumer(C.sequoia_logger_consumer_t(C.sequoia_logrus_logger), &cerr) != 0 { + defer C.go_sequoia_error_free(cerr) + return fmt.Errorf("initializing logging: %s", C.GoString(cerr.message)) + } return nil } From 0af8bd22078de14a279457603cae153c10dd11ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 14 Jul 2025 17:22:19 +0200 Subject: [PATCH 14/18] Close mechanisms in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia_test.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/signature/internal/sequoia/sequoia_test.go b/signature/internal/sequoia/sequoia_test.go index 01f200cee3..f26ec68e36 100644 --- a/signature/internal/sequoia/sequoia_test.go +++ b/signature/internal/sequoia/sequoia_test.go @@ -59,18 +59,16 @@ func TestNewMechanismFromDirectory(t *testing.T) { t.Skipf("sq not usable: %v", err) } dir := t.TempDir() - _, err := NewMechanismFromDirectory(dir) - if err != nil { - t.Fatalf("unable to initialize a mechanism: %v", err) - } + m, err := NewMechanismFromDirectory(dir) + require.NoError(t, err) + m.Close() _, err = generateKey(dir, "foo@example.org") if err != nil { t.Fatalf("unable to generate key: %v", err) } - _, err = NewMechanismFromDirectory(dir) - if err != nil { - t.Fatalf("unable to initialize a mechanism: %v", err) - } + m, err = NewMechanismFromDirectory(dir) + require.NoError(t, err) + m.Close() } func TestNewEphemeralMechanism(t *testing.T) { @@ -87,9 +85,8 @@ func TestNewEphemeralMechanism(t *testing.T) { t.Fatalf("unable to export cert: %v", err) } m, err := NewEphemeralMechanism() - if err != nil { - t.Fatalf("unable to initialize a mechanism: %v", err) - } + require.NoError(t, err) + defer m.Close() keyIdentities, err := m.ImportKeys(output) if err != nil { t.Fatalf("unable to import keys: %v", err) @@ -113,6 +110,7 @@ func TestGenerateSignVerify(t *testing.T) { if err != nil { t.Fatalf("unable to initialize a mechanism: %v", err) } + defer m.Close() input := []byte("Hello, world!") sig, err := m.Sign(input, fingerprint) if err != nil { From fd6ca715582bbcdf61bbeff188fb4efff17bdc65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 14 Jul 2025 17:24:44 +0200 Subject: [PATCH 15/18] Improve test coverage of signature/internal/sequoia/sequoia.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing tests, or add comments where that's not practical. Should not change behavior. Signed-off-by: Miloslav Trmač --- signature/internal/sequoia/sequoia.go | 14 +-- signature/internal/sequoia/sequoia_test.go | 107 ++++++++++++++++----- 2 files changed, 88 insertions(+), 33 deletions(-) diff --git a/signature/internal/sequoia/sequoia.go b/signature/internal/sequoia/sequoia.go index ae175bcf70..361c1a6c7f 100644 --- a/signature/internal/sequoia/sequoia.go +++ b/signature/internal/sequoia/sequoia.go @@ -95,7 +95,7 @@ func (m *SigningMechanism) SignWithPassphrase( var size C.size_t cData := C.go_sequoia_signature_get_data(sig, &size) if size > C.size_t(C.INT_MAX) { - return nil, errors.New("overflow") + return nil, errors.New("overflow") // Coverage: This should not reasonably happen, and we don’t want to generate gigabytes of input to test this. } return C.GoBytes(unsafe.Pointer(cData), C.int(size)), nil } @@ -125,7 +125,7 @@ func (m *SigningMechanism) Verify( var size C.size_t cContent := C.go_sequoia_verification_result_get_content(result, &size) if size > C.size_t(C.INT_MAX) { - return nil, "", errors.New("overflow") + return nil, "", errors.New("overflow") // Coverage: This should not reasonably happen, and we don’t want to generate gigabytes of input to test this. } contents = C.GoBytes(unsafe.Pointer(cContent), C.int(size)) cSigner := C.go_sequoia_verification_result_get_signer(result) @@ -153,7 +153,7 @@ func (m *SigningMechanism) ImportKeys(blob []byte) ([]string, error) { var cerr *C.SequoiaError cKeyIdentity := C.go_sequoia_import_result_get_content(result, i, &cerr) if cerr != nil { - defer C.go_sequoia_error_free(cerr) + defer C.go_sequoia_error_free(cerr) // Coverage: this can fail only if i is out of range. return nil, errors.New(C.GoString(cerr.message)) } keyIdentities = append(keyIdentities, C.GoString(cKeyIdentity)) @@ -170,7 +170,7 @@ func (m *SigningMechanism) Close() error { //export sequoia_logrus_logger func sequoia_logrus_logger(level C.enum_SequoiaLogLevel, message *C.char) { var logrusLevel logrus.Level - switch level { + switch level { // Coverage: We are not in control of whether / how the Rust code chooses to log things. case C.SEQUOIA_LOG_LEVEL_ERROR: logrusLevel = logrus.ErrorLevel case C.SEQUOIA_LOG_LEVEL_WARN: @@ -198,7 +198,7 @@ func initOnce() error { case "darwin": soName = "libpodman_sequoia.dylib" default: - return fmt.Errorf("Unhandled OS %q in sequoia initialization", runtime.GOOS) + return fmt.Errorf("Unhandled OS %q in sequoia initialization", runtime.GOOS) // Coverage: This is ~by definition not reached in tests. } if sequoiaLibraryDir != "" { soName = filepath.Join(sequoiaLibraryDir, soName) @@ -207,12 +207,12 @@ func initOnce() error { defer C.free(unsafe.Pointer(cSOName)) if C.go_sequoia_ensure_library(cSOName, C.RTLD_NOW|C.RTLD_GLOBAL) < 0 { - return fmt.Errorf("unable to load %q", soName) + return fmt.Errorf("unable to load %q", soName) // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle. } var cerr *C.SequoiaError if C.go_sequoia_set_logger_consumer(C.sequoia_logger_consumer_t(C.sequoia_logrus_logger), &cerr) != 0 { - defer C.go_sequoia_error_free(cerr) + defer C.go_sequoia_error_free(cerr) // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle. return fmt.Errorf("initializing logging: %s", C.GoString(cerr.message)) } return nil diff --git a/signature/internal/sequoia/sequoia_test.go b/signature/internal/sequoia/sequoia_test.go index f26ec68e36..afd2db4fc9 100644 --- a/signature/internal/sequoia/sequoia_test.go +++ b/signature/internal/sequoia/sequoia_test.go @@ -9,6 +9,7 @@ import ( "io" "os" "os/exec" + "path/filepath" "regexp" "testing" @@ -20,8 +21,19 @@ func checkCliVersion(version string) error { return exec.Command("sq", "--cli-version", version, "version").Run() } -func generateKey(dir string, email string) (string, error) { - cmd := exec.Command("sq", "--home", dir, "key", "generate", "--userid", fmt.Sprintf("<%s>", email), "--own-key", "--without-password") +func generateKey(t *testing.T, dir string, email, passphrase string) (string, error) { + args := []string{"--home", dir, "key", "generate", "--userid", fmt.Sprintf("<%s>", email), "--own-key"} + if passphrase != "" { + pwFile := filepath.Join(t.TempDir(), "passphrase") + err := os.WriteFile(pwFile, []byte(passphrase), 0o600) + if err != nil { + return "", err + } + args = append(args, "--new-password-file", pwFile) + } else { + args = append(args, "--without-password") + } + cmd := exec.Command("sq", args...) stderr, err := cmd.StderrPipe() if err != nil { return "", err @@ -62,13 +74,17 @@ func TestNewMechanismFromDirectory(t *testing.T) { m, err := NewMechanismFromDirectory(dir) require.NoError(t, err) m.Close() - _, err = generateKey(dir, "foo@example.org") + _, err = generateKey(t, dir, "foo@example.org", "") if err != nil { t.Fatalf("unable to generate key: %v", err) } m, err = NewMechanismFromDirectory(dir) require.NoError(t, err) m.Close() + + t.Setenv("SEQUOIA_CRYPTO_POLICY", "this/does/not/exist") // Both unreadable files, and relative paths, should cause an error. + _, err = NewMechanismFromDirectory(dir) + assert.Error(t, err) } func TestNewEphemeralMechanism(t *testing.T) { @@ -76,7 +92,7 @@ func TestNewEphemeralMechanism(t *testing.T) { t.Skipf("sq not usable: %v", err) } dir := t.TempDir() - fingerprint, err := generateKey(dir, "foo@example.org") + fingerprint, err := generateKey(t, dir, "foo@example.org", "") if err != nil { t.Fatalf("unable to generate key: %v", err) } @@ -95,36 +111,65 @@ func TestNewEphemeralMechanism(t *testing.T) { t.Fatalf("keyIdentity differ from the original: %v != %v", keyIdentities[0], fingerprint) } + + t.Setenv("SEQUOIA_CRYPTO_POLICY", "this/does/not/exist") // Both unreadable files, and relative paths, should cause an error. + _, err = NewEphemeralMechanism() + assert.Error(t, err) } -func TestGenerateSignVerify(t *testing.T) { +func TestSignWithPassphrase(t *testing.T) { if err := checkCliVersion("1.3.0"); err != nil { t.Skipf("sq not usable: %v", err) } + + // Success is tested in TestGenerateSignVerify and TestSignThenVerifyEphemeral + + // Invalid passphrase dir := t.TempDir() - fingerprint, err := generateKey(dir, "foo@example.org") - if err != nil { - t.Fatalf("unable to generate key: %v", err) - } + fingerprint, err := generateKey(t, dir, "foo@example.org", "valid-passphrase") + require.NoError(t, err) m, err := NewMechanismFromDirectory(dir) - if err != nil { - t.Fatalf("unable to initialize a mechanism: %v", err) - } + require.NoError(t, err) defer m.Close() - input := []byte("Hello, world!") - sig, err := m.Sign(input, fingerprint) - if err != nil { - t.Fatalf("unable to sign: %v", err) - } - contents, keyIdentity, err := m.Verify(sig) - if err != nil { - t.Fatalf("unable to verify: %v", err) - } - if !bytes.Equal(contents, input) { - t.Fatalf("contents differ from the original") + _, err = m.SignWithPassphrase([]byte("input"), fingerprint, "invalid-passphrase") + assert.Error(t, err) +} + +func TestGenerateSignVerify(t *testing.T) { + if err := checkCliVersion("1.3.0"); err != nil { + t.Skipf("sq not usable: %v", err) } - if keyIdentity != fingerprint { - t.Fatalf("keyIdentity differ from the original") + for _, passphrase := range []string{"", "test-passphrase"} { + dir := t.TempDir() + fingerprint, err := generateKey(t, dir, "foo@example.org", passphrase) + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + m, err := NewMechanismFromDirectory(dir) + if err != nil { + t.Fatalf("unable to initialize a mechanism: %v", err) + } + defer m.Close() + input := []byte("Hello, world!") + var sig []byte + if passphrase != "" { + sig, err = m.SignWithPassphrase(input, fingerprint, passphrase) + } else { + sig, err = m.Sign(input, fingerprint) + } + if err != nil { + t.Fatalf("unable to sign: %v", err) + } + contents, keyIdentity, err := m.Verify(sig) + if err != nil { + t.Fatalf("unable to verify: %v", err) + } + if !bytes.Equal(contents, input) { + t.Fatalf("contents differ from the original") + } + if keyIdentity != fingerprint { + t.Fatalf("keyIdentity differ from the original") + } } } @@ -133,7 +178,7 @@ func TestSignThenVerifyEphemeral(t *testing.T) { t.Skipf("sq not usable: %v", err) } dir := t.TempDir() - fingerprint, err := generateKey(dir, "foo@example.org") + fingerprint, err := generateKey(t, dir, "foo@example.org", "") require.NoError(t, err) publicKey, err := exportCert(dir, fingerprint) require.NoError(t, err) @@ -162,6 +207,16 @@ func TestSignThenVerifyEphemeral(t *testing.T) { assert.Equal(t, keyIdentity, fingerprint) } +func TestImportKeys(t *testing.T) { + // Success is tested in TestNewEphemeralMechanism and TestSignThenVerifyEphemeral + m, err := NewEphemeralMechanism() + require.NoError(t, err) + defer m.Close() + + _, err = m.ImportKeys([]byte("This is not a key at all")) + assert.Error(t, err) +} + func TestMain(m *testing.M) { err := Init() if err != nil { From a79ed91009a84449ff6f581ed99dda5a8dfa3f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Wed, 25 Jun 2025 22:59:05 +0200 Subject: [PATCH 16/18] With sequoia, still use GPGME for existing signing, and add a new Signer API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- README.md | 2 +- signature/mechanism_gpgme.go | 78 ++----- signature/mechanism_gpgme_only.go | 64 ++++++ signature/mechanism_sequoia.go | 89 ++------ signature/simplesequoia/mechanism.go | 52 +++++ signature/simplesequoia/signer.go | 88 ++++++++ signature/simplesequoia/signer_stub.go | 2 + signature/simplesequoia/signer_test.go | 201 ++++++++++++++++++ signature/simplesequoia/testdata/.gitignore | 1 + .../testdata/data/keystore/keystore.cookie | 0 ...5825285B785E1DB13BF36D2D11A19ABA41C6AE.pgp | Bin 0 -> 2170 bytes ...DDE898DF4E48755C8C2B7AF6F908B6FA48A229.pgp | Bin 0 -> 1970 bytes .../1f/5825285b785e1db13bf36d2d11a19aba41c6ae | Bin 0 -> 2037 bytes .../4d/8bcd544b7573eefaad18c278473e5f255d10b8 | Bin 0 -> 492 bytes .../50/dde898df4e48755c8c2b7af6f908b6fa48a229 | Bin 0 -> 2021 bytes .../68/de230c4a009f5ee5fbb27984642d0130b86046 | Bin 0 -> 696 bytes .../testdata/data/pgp.cert.d/trust-root | Bin 0 -> 529 bytes .../testdata/data/pgp.cert.d/writelock | 0 .../simplesequoia/testdata/no-passphrase.pub | 38 ++++ .../testdata/with-passphrase.pub | 39 ++++ 20 files changed, 520 insertions(+), 134 deletions(-) create mode 100644 signature/mechanism_gpgme_only.go create mode 100644 signature/simplesequoia/mechanism.go create mode 100644 signature/simplesequoia/signer.go create mode 100644 signature/simplesequoia/signer_test.go create mode 100644 signature/simplesequoia/testdata/.gitignore create mode 100644 signature/simplesequoia/testdata/data/keystore/keystore.cookie create mode 100644 signature/simplesequoia/testdata/data/keystore/softkeys/1F5825285B785E1DB13BF36D2D11A19ABA41C6AE.pgp create mode 100644 signature/simplesequoia/testdata/data/keystore/softkeys/50DDE898DF4E48755C8C2B7AF6F908B6FA48A229.pgp create mode 100644 signature/simplesequoia/testdata/data/pgp.cert.d/1f/5825285b785e1db13bf36d2d11a19aba41c6ae create mode 100644 signature/simplesequoia/testdata/data/pgp.cert.d/4d/8bcd544b7573eefaad18c278473e5f255d10b8 create mode 100644 signature/simplesequoia/testdata/data/pgp.cert.d/50/dde898df4e48755c8c2b7af6f908b6fa48a229 create mode 100644 signature/simplesequoia/testdata/data/pgp.cert.d/68/de230c4a009f5ee5fbb27984642d0130b86046 create mode 100644 signature/simplesequoia/testdata/data/pgp.cert.d/trust-root create mode 100644 signature/simplesequoia/testdata/data/pgp.cert.d/writelock create mode 100644 signature/simplesequoia/testdata/no-passphrase.pub create mode 100644 signature/simplesequoia/testdata/with-passphrase.pub diff --git a/README.md b/README.md index be0c709e72..56c66b7f34 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ or use the build tags described below to avoid the dependencies (e.g. using `go - `containers_image_docker_daemon_stub`: Don’t import the `docker-daemon:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. - `containers_image_openpgp`: Use a Golang-only OpenPGP implementation for signature verification instead of the default cgo/gpgme-based implementation; the primary downside is that creating new signatures with the Golang-only implementation is not supported. -- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations. This requires a support shared library installed on the system. Install https://github.com/ueno/podman-sequoia , and potentially update build configuration to point at it (compare `SEQUOIA_SONAME_DIR` in `Makefile`). +- `containers_image_sequoia`: Use Sequoia-PGP for signature verification instead of the default cgo/gpgme-based or the Golang-only OpenPGP implementations, and enable the `signature/simplesequoia` subpackage. This requires a support shared library installed on the system. Install https://github.com/ueno/podman-sequoia , and potentially update build configuration to point at it (compare `SEQUOIA_SONAME_DIR` in `Makefile`). - `containers_image_storage_stub`: Don’t import the `containers-storage:` transport in `github.com/containers/image/transports/alltransports`, to decrease the amount of required dependencies. Use a stub which reports that the transport is not supported instead. ## [Contributing](CONTRIBUTING.md) diff --git a/signature/mechanism_gpgme.go b/signature/mechanism_gpgme.go index a3f3dbf131..fe83661d12 100644 --- a/signature/mechanism_gpgme.go +++ b/signature/mechanism_gpgme.go @@ -1,7 +1,10 @@ -//go:build !containers_image_openpgp && !containers_image_sequoia +//go:build !containers_image_openpgp package signature +// This is shared by mechanism_gpgme_only.go and mechanism_sequoia.go; in both situations +// newGPGSigningMechanismInDirectory is implemented using GPGME. + import ( "bytes" "errors" @@ -18,53 +21,24 @@ type gpgmeSigningMechanism struct { ephemeralDir string // If not "", a directory to be removed on Close() } -// newGPGSigningMechanismInDirectory returns a new GPG/OpenPGP signing mechanism, using optionalDir if not empty. -// The caller must call .Close() on the returned SigningMechanism. -func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWithPassphrase, error) { - ctx, err := newGPGMEContext(optionalDir) - if err != nil { - return nil, err - } +// newGPGMESigningMechanism returns a new GPG/OpenPGP signing mechanism for ctx. +// The caller must call .Close() on the returned SigningMechanism; if ephemeralDir is set, +// the .Close() call will remove its contents. +func newGPGMESigningMechanism(ctx *gpgme.Context, ephemeralDir string) signingMechanismWithPassphrase { return &gpgmeSigningMechanism{ ctx: ctx, - ephemeralDir: "", - }, nil + ephemeralDir: ephemeralDir, + } } -// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which -// recognizes _only_ public keys from the supplied blobs, and returns the identities -// of these keys. +// newGPGSigningMechanismInDirectory returns a new GPG/OpenPGP signing mechanism, using optionalDir if not empty. // The caller must call .Close() on the returned SigningMechanism. -func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) { - dir, err := os.MkdirTemp("", "containers-ephemeral-gpg-") - if err != nil { - return nil, nil, err - } - removeDir := true - defer func() { - if removeDir { - os.RemoveAll(dir) - } - }() - ctx, err := newGPGMEContext(dir) +func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWithPassphrase, error) { + ctx, err := newGPGMEContext(optionalDir) if err != nil { - return nil, nil, err - } - mech := &gpgmeSigningMechanism{ - ctx: ctx, - ephemeralDir: dir, - } - keyIdentities := []string{} - for _, blob := range blobs { - ki, err := mech.importKeysFromBytes(blob) - if err != nil { - return nil, nil, err - } - keyIdentities = append(keyIdentities, ki...) + return nil, err } - - removeDir = false - return mech, keyIdentities, nil + return newGPGMESigningMechanism(ctx, ""), nil } // newGPGMEContext returns a new *gpgme.Context, using optionalDir if not empty. @@ -94,28 +68,6 @@ func (m *gpgmeSigningMechanism) Close() error { return nil } -// importKeysFromBytes imports public keys from the supplied blob and returns their identities. -// The blob is assumed to have an appropriate format (the caller is expected to know which one). -// NOTE: This may modify long-term state (e.g. key storage in a directory underlying the mechanism); -// but we do not make this public, it can only be used through newEphemeralGPGSigningMechanism. -func (m *gpgmeSigningMechanism) importKeysFromBytes(blob []byte) ([]string, error) { - inputData, err := gpgme.NewDataBytes(blob) - if err != nil { - return nil, err - } - res, err := m.ctx.Import(inputData) - if err != nil { - return nil, err - } - keyIdentities := []string{} - for _, i := range res.Imports { - if i.Result == nil { - keyIdentities = append(keyIdentities, i.Fingerprint) - } - } - return keyIdentities, nil -} - // SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError. func (m *gpgmeSigningMechanism) SupportsSigning() error { return nil diff --git a/signature/mechanism_gpgme_only.go b/signature/mechanism_gpgme_only.go new file mode 100644 index 0000000000..0f971ac6a4 --- /dev/null +++ b/signature/mechanism_gpgme_only.go @@ -0,0 +1,64 @@ +//go:build !containers_image_openpgp && !containers_image_sequoia + +package signature + +import ( + "os" + + "github.com/proglottis/gpgme" +) + +// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which +// recognizes _only_ public keys from the supplied blobs, and returns the identities +// of these keys. +// The caller must call .Close() on the returned SigningMechanism. +func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) { + dir, err := os.MkdirTemp("", "containers-ephemeral-gpg-") + if err != nil { + return nil, nil, err + } + removeDir := true + defer func() { + if removeDir { + os.RemoveAll(dir) + } + }() + ctx, err := newGPGMEContext(dir) + if err != nil { + return nil, nil, err + } + keyIdentities := []string{} + for _, blob := range blobs { + ki, err := importKeysFromBytes(ctx, blob) + if err != nil { + return nil, nil, err + } + keyIdentities = append(keyIdentities, ki...) + } + + mech := newGPGMESigningMechanism(ctx, dir) + removeDir = false + return mech, keyIdentities, nil +} + +// importKeysFromBytes imports public keys from the supplied blob and returns their identities. +// The blob is assumed to have an appropriate format (the caller is expected to know which one). +// NOTE: This may modify long-term state (e.g. key storage in a directory underlying the mechanism); +// but we do not make this public, it can only be used through newEphemeralGPGSigningMechanism. +func importKeysFromBytes(ctx *gpgme.Context, blob []byte) ([]string, error) { + inputData, err := gpgme.NewDataBytes(blob) + if err != nil { + return nil, err + } + res, err := ctx.Import(inputData) + if err != nil { + return nil, err + } + keyIdentities := []string{} + for _, i := range res.Imports { + if i.Result == nil { + keyIdentities = append(keyIdentities, i.Fingerprint) + } + } + return keyIdentities, nil +} diff --git a/signature/mechanism_sequoia.go b/signature/mechanism_sequoia.go index 3c8ef52c19..76a08b5f7d 100644 --- a/signature/mechanism_sequoia.go +++ b/signature/mechanism_sequoia.go @@ -3,72 +3,17 @@ package signature import ( - "os" - "path" - "github.com/containers/image/v5/signature/internal/sequoia" - "github.com/containers/storage/pkg/homedir" ) -// A GPG/OpenPGP signing mechanism, implemented using Sequoia. -type sequoiaSigningMechanism struct { +// A GPG/OpenPGP signing mechanism, implemented using Sequoia and only supporting verification. +// Legacy users who reach newGPGSigningMechanismInDirectory will use GPGME. +// Signing using Sequoia is preferable, but should happen via signature/simplesequoia.NewSigner, not using +// the legacy mechanism API. +type sequoiaEphemeralSigningMechanism struct { inner *sequoia.SigningMechanism } -// newGPGSigningMechanismInDirectory returns a new GPG/OpenPGP signing mechanism, using optionalDir if not empty. -// The caller must call .Close() on the returned SigningMechanism. -func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWithPassphrase, error) { - if err := sequoia.Init(); err != nil { - return nil, err - } - - // For compatibility reasons, we allow both sequoiaHome and - // gpgHome to be the same directory as designated by - // optionalDir or GNUPGHOME. - envHome := os.Getenv("GNUPGHOME") - - gpgHome := optionalDir - if gpgHome == "" { - gpgHome = envHome - if gpgHome == "" { - gpgHome = path.Join(homedir.Get(), ".gnupg") - } - } - - sequoiaHome := optionalDir - if sequoiaHome == "" { - sequoiaHome = envHome - if sequoiaHome == "" { - dataHome, err := homedir.GetDataHome() - if err != nil { - return nil, err - } - sequoiaHome = path.Join(dataHome, "sequoia") - } - } - - mech, err := sequoia.NewMechanismFromDirectory(sequoiaHome) - if err != nil { - return nil, err - } - - // Migrate GnuPG keyrings if exist. - for _, keyring := range []string{"pubring.gpg", "secring.gpg"} { - blob, err := os.ReadFile(path.Join(gpgHome, keyring)) - if err != nil { - if !os.IsNotExist(err) { - return nil, err - } - } else if _, err := mech.ImportKeys(blob); err != nil { - return nil, err - } - } - - return &sequoiaSigningMechanism{ - inner: mech, - }, nil -} - // newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which // recognizes _only_ public keys from the supplied blobs, and returns the identities // of these keys. @@ -91,37 +36,41 @@ func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassph keyIdentities = append(keyIdentities, ki...) } - return &sequoiaSigningMechanism{ + return &sequoiaEphemeralSigningMechanism{ inner: mech, }, keyIdentities, nil } -func (m *sequoiaSigningMechanism) Close() error { +func (m *sequoiaEphemeralSigningMechanism) Close() error { return m.inner.Close() } // SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError. -func (m *sequoiaSigningMechanism) SupportsSigning() error { - return nil +func (m *sequoiaEphemeralSigningMechanism) SupportsSigning() error { + // This code is externally reachable via NewEphemeralGPGSigningMechanism(), but that API provides no way to + // import or generate a key. + return SigningNotSupportedError("caller error: Attempt to sign using a mechanism created via NewEphemeralGPGSigningMechanism().") } // Sign creates a (non-detached) signature of input using keyIdentity and passphrase. // Fails with a SigningNotSupportedError if the mechanism does not support signing. -func (m *sequoiaSigningMechanism) SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error) { - return m.inner.SignWithPassphrase(input, keyIdentity, passphrase) +func (m *sequoiaEphemeralSigningMechanism) SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error) { + // This code is externally reachable via NewEphemeralGPGSigningMechanism(), but that API provides no way to + // import or generate a key. + return nil, SigningNotSupportedError("caller error: Attempt to sign using a mechanism created via NewEphemeralGPGSigningMechanism().") } // Sign creates a (non-detached) signature of input using keyIdentity. // Fails with a SigningNotSupportedError if the mechanism does not support signing. -func (m *sequoiaSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte, error) { - return m.inner.Sign(input, keyIdentity) +func (m *sequoiaEphemeralSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte, error) { + return m.SignWithPassphrase(input, keyIdentity, "") } // Verify parses unverifiedSignature and returns the content and the signer's identity. // For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity // is expected to be one of the values returned by NewEphemeralGPGSigningMechanism, // or the mechanism should implement signingMechanismWithVerificationIdentityLookup. -func (m *sequoiaSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) { +func (m *sequoiaEphemeralSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) { return m.inner.Verify(unverifiedSignature) } @@ -130,6 +79,6 @@ func (m *sequoiaSigningMechanism) Verify(unverifiedSignature []byte) (contents [ // WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys) // is NOT the same as a "key identity" used in other calls to this interface, and // the values may have no recognizable relationship if the public key is not available. -func (m *sequoiaSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) { +func (m *sequoiaEphemeralSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) { return gpgUntrustedSignatureContents(untrustedSignature) } diff --git a/signature/simplesequoia/mechanism.go b/signature/simplesequoia/mechanism.go new file mode 100644 index 0000000000..a6ee4a2b81 --- /dev/null +++ b/signature/simplesequoia/mechanism.go @@ -0,0 +1,52 @@ +//go:build containers_image_sequoia + +package simplesequoia + +// This implements a signature.signingMechanismWithPassphrase that only supports signing. +// +// FIXME: Consider restructuring the simple signing signature creation code path +// not to require this indirection and all those unimplemented methods. + +import ( + "github.com/containers/image/v5/signature/internal/sequoia" +) + +// A GPG/OpenPGP signing mechanism, implemented using Sequoia. +type sequoiaSigningOnlyMechanism struct { + inner *sequoia.SigningMechanism +} + +func (m *sequoiaSigningOnlyMechanism) Close() error { + panic("Should never be called") +} + +// SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError. +func (m *sequoiaSigningOnlyMechanism) SupportsSigning() error { + panic("Should never be called") +} + +// Sign creates a (non-detached) signature of input using keyIdentity and passphrase. +// Fails with a SigningNotSupportedError if the mechanism does not support signing. +func (m *sequoiaSigningOnlyMechanism) SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error) { + return m.inner.SignWithPassphrase(input, keyIdentity, passphrase) +} + +// Sign creates a (non-detached) signature of input using keyIdentity. +// Fails with a SigningNotSupportedError if the mechanism does not support signing. +func (m *sequoiaSigningOnlyMechanism) Sign(input []byte, keyIdentity string) ([]byte, error) { + panic("Should never be called") +} + +// Verify parses unverifiedSignature and returns the content and the signer's identity +func (m *sequoiaSigningOnlyMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) { + panic("Should never be called") +} + +// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION, +// along with a short identifier of the key used for signing. +// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys) +// is NOT the same as a "key identity" used in other calls to this interface, and +// the values may have no recognizable relationship if the public key is not available. +func (m *sequoiaSigningOnlyMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) { + panic("Should never be called") +} diff --git a/signature/simplesequoia/signer.go b/signature/simplesequoia/signer.go new file mode 100644 index 0000000000..64b6610aa1 --- /dev/null +++ b/signature/simplesequoia/signer.go @@ -0,0 +1,88 @@ +//go:build containers_image_sequoia + +package simplesequoia + +import ( + "context" + "errors" + "fmt" + + "github.com/containers/image/v5/docker/reference" + internalSig "github.com/containers/image/v5/internal/signature" + internalSigner "github.com/containers/image/v5/internal/signer" + "github.com/containers/image/v5/signature" + "github.com/containers/image/v5/signature/internal/sequoia" + "github.com/containers/image/v5/signature/signer" +) + +// simpleSequoiaSigner is a signer.SignerImplementation implementation for simple signing signatures using Sequoia. +type simpleSequoiaSigner struct { + mech *sequoia.SigningMechanism + sequoiaHome string // "" if using the system’s default + keyFingerprint string + passphrase string // "" if not provided. +} + +// NewSigner returns a signature.Signer which creates “simple signing” signatures using the user’s default +// Sequoia PGP configuration. +// +// The set of options must identify a key to sign with, probably using a WithKeyFingerprint. +// +// The caller must call Close() on the returned Signer. +func NewSigner(opts ...Option) (*signer.Signer, error) { + s := simpleSequoiaSigner{} + for _, o := range opts { + if err := o(&s); err != nil { + return nil, err + } + } + if s.keyFingerprint == "" { + return nil, errors.New("no key identity provided for simple signing") + } + + if err := sequoia.Init(); err != nil { + return nil, err // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle. + } + mech, err := sequoia.NewMechanismFromDirectory(s.sequoiaHome) + if err != nil { + return nil, fmt.Errorf("initializing Sequoia: %w", err) + } + s.mech = mech + succeeded := false + defer func() { + if !succeeded { + s.mech.Close() // Coverage: This is currently unreachable. + } + }() + + // Ideally, we should look up (and unlock?) the key at this point already. FIXME: is that possible? Anyway, low-priority. + + succeeded = true + return internalSigner.NewSigner(&s), nil +} + +// ProgressMessage returns a human-readable sentence that makes sense to write before starting to create a single signature. +func (s *simpleSequoiaSigner) ProgressMessage() string { + return "Signing image using Sequoia-PGP simple signing" +} + +// SignImageManifest creates a new signature for manifest m as dockerReference. +func (s *simpleSequoiaSigner) SignImageManifest(ctx context.Context, m []byte, dockerReference reference.Named) (internalSig.Signature, error) { + if reference.IsNameOnly(dockerReference) { + return nil, fmt.Errorf("reference %s can’t be signed, it has neither a tag nor a digest", dockerReference.String()) + } + wrapped := sequoiaSigningOnlyMechanism{ + inner: s.mech, + } + simpleSig, err := signature.SignDockerManifestWithOptions(m, dockerReference.String(), &wrapped, s.keyFingerprint, &signature.SignOptions{ + Passphrase: s.passphrase, + }) + if err != nil { + return nil, err + } + return internalSig.SimpleSigningFromBlob(simpleSig), nil +} + +func (s *simpleSequoiaSigner) Close() error { + return s.mech.Close() +} diff --git a/signature/simplesequoia/signer_stub.go b/signature/simplesequoia/signer_stub.go index 49fe487eb0..8d2b56dae8 100644 --- a/signature/simplesequoia/signer_stub.go +++ b/signature/simplesequoia/signer_stub.go @@ -1,3 +1,5 @@ +//go:build !containers_image_sequoia + package simplesequoia import ( diff --git a/signature/simplesequoia/signer_test.go b/signature/simplesequoia/signer_test.go new file mode 100644 index 0000000000..7e58787a09 --- /dev/null +++ b/signature/simplesequoia/signer_test.go @@ -0,0 +1,201 @@ +//go:build containers_image_sequoia + +package simplesequoia + +import ( + "context" + "os" + "testing" + + "github.com/containers/image/v5/docker/reference" + internalSig "github.com/containers/image/v5/internal/signature" + internalSigner "github.com/containers/image/v5/internal/signer" + "github.com/containers/image/v5/signature" + "github.com/opencontainers/go-digest" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + // testImageManifestDigest is the Docker manifest digest of "image.manifest.json" + testImageManifestDigest = digest.Digest("sha256:20bf21ed457b390829cdbeec8795a7bea1626991fda603e0d01b4e7f60427e55") + + testSequoiaHome = "./testdata" + // testKeyFingerprint is a fingerprint of a test key in testSequoiaHome, generated using + // > sq --home $(pwd)/signature/simplesequoia/testdata key generate --name 'Skopeo Sequoia testing key' --own-key --expiration=never + testKeyFingerprint = "50DDE898DF4E48755C8C2B7AF6F908B6FA48A229" + // testKeyFingerprintWithPassphrase is a fingerprint of a test key in testSequoiaHome, generated using + // > sq --home $(pwd)/signature/simplesequoia/testdata key generate --name 'Skopeo Sequoia testing key with passphrase' --own-key --expiration=never + testKeyFingerprintWithPassphrase = "1F5825285B785E1DB13BF36D2D11A19ABA41C6AE" + // testPassphrase is the passphrase for testKeyFingerprintWithPassphrase. + testPassphrase = "WithPassphrase123" +) + +func TestNewSigner(t *testing.T) { + // An option causes an error + _, err := NewSigner(WithSequoiaHome(testSequoiaHome), WithKeyFingerprint(testKeyFingerprint), WithPassphrase("\n")) + assert.Error(t, err) + + // WithKeyFingerprint is missing + _, err = NewSigner(WithSequoiaHome(testSequoiaHome), WithPassphrase("something")) + assert.Error(t, err) + + // A smoke test + s, err := NewSigner(WithSequoiaHome(testSequoiaHome), WithKeyFingerprint(testKeyFingerprint)) + require.NoError(t, err) + err = s.Close() + assert.NoError(t, err) + + t.Setenv("SEQUOIA_CRYPTO_POLICY", "this/does/not/exist") // Both unreadable files, and relative paths, should cause an error. + _, err = NewSigner(WithSequoiaHome(testSequoiaHome), WithKeyFingerprint(testKeyFingerprint)) + assert.Error(t, err) +} + +func TestSimpleSignerProgressMessage(t *testing.T) { + // Just a smoke test + s, err := NewSigner(WithSequoiaHome(testSequoiaHome), WithKeyFingerprint(testKeyFingerprint)) + require.NoError(t, err) + defer func() { + err = s.Close() + assert.NoError(t, err) + }() + + _ = internalSigner.ProgressMessage(s) +} + +func TestSimpleSignerSignImageManifest(t *testing.T) { + manifest, err := os.ReadFile("../fixtures/image.manifest.json") + require.NoError(t, err) + testImageSignatureReference, err := reference.ParseNormalizedNamed("example.com/testing/manifest:notlatest") + require.NoError(t, err) + + // Successful signing + for _, c := range []struct { + name string + publicKeyPath string + fingerprint string + opts []Option + }{ + { + name: "No passphrase", + publicKeyPath: "./testdata/no-passphrase.pub", + fingerprint: testKeyFingerprint, + }, + { + name: "With passphrase", + publicKeyPath: "./testdata/with-passphrase.pub", + fingerprint: testKeyFingerprintWithPassphrase, + opts: []Option{WithPassphrase(testPassphrase)}, + }, + } { + s, err := NewSigner(append([]Option{WithSequoiaHome(testSequoiaHome), WithKeyFingerprint(c.fingerprint)}, c.opts...)...) + require.NoError(t, err, c.name) + defer s.Close() + + sig, err := internalSigner.SignImageManifest(context.Background(), s, manifest, testImageSignatureReference) + require.NoError(t, err, c.name) + simpleSig, ok := sig.(internalSig.SimpleSigning) + require.True(t, ok) + + publicKey, err := os.ReadFile(c.publicKeyPath) + require.NoError(t, err) + mech, importedFingerprint, err := signature.NewEphemeralGPGSigningMechanism(publicKey) + require.NoError(t, err) + assert.Equal(t, []string{c.fingerprint}, importedFingerprint) + defer mech.Close() + + verified, err := signature.VerifyDockerManifestSignature(simpleSig.UntrustedSignature(), manifest, testImageSignatureReference.String(), mech, c.fingerprint) + require.NoError(t, err) + assert.Equal(t, testImageSignatureReference.String(), verified.DockerReference) + assert.Equal(t, testImageManifestDigest, verified.DockerManifestDigest) + } + + invalidManifest, err := os.ReadFile("../fixtures/v2s1-invalid-signatures.manifest.json") + require.NoError(t, err) + invalidReference, err := reference.ParseNormalizedNamed("no-tag") + require.NoError(t, err) + for _, c := range []struct { + name string + opts []Option + // NOTE: We DO NOT promise that things that don't fail during NewSigner won't start failing there. + // Actually we’d prefer failures to be identified early. This field only records current expected behavior, not the _desired_ end state. + creationFails bool + creationErrorContains string + manifest []byte + ref reference.Named + }{ + { + name: "No key to sign with", + opts: []Option{WithSequoiaHome(testSequoiaHome)}, + creationFails: true, + }, + { + name: "Invalid passphrase", + opts: []Option{ + WithSequoiaHome(testSequoiaHome), + WithKeyFingerprint(testKeyFingerprintWithPassphrase), + WithPassphrase(testPassphrase + "\n"), + }, + creationFails: true, + creationErrorContains: "invalid passphrase", + ref: testImageSignatureReference, + }, + { + name: "Wrong passphrase", + opts: []Option{ + WithSequoiaHome(testSequoiaHome), + WithKeyFingerprint(testKeyFingerprintWithPassphrase), + WithPassphrase("wrong"), + }, + ref: testImageSignatureReference, + }, + { + name: "No passphrase", + opts: []Option{WithKeyFingerprint(testKeyFingerprintWithPassphrase)}, + ref: testImageSignatureReference, + }, + { + name: "Error computing Docker manifest", + opts: []Option{ + WithSequoiaHome(testSequoiaHome), + WithKeyFingerprint(testKeyFingerprint), + }, + manifest: invalidManifest, + ref: testImageSignatureReference, + }, + { + name: "Invalid reference", + opts: []Option{ + WithSequoiaHome(testSequoiaHome), + WithKeyFingerprint(testKeyFingerprint), + }, + ref: invalidReference, + }, + { + name: "Error signing", + opts: []Option{ + WithSequoiaHome(testSequoiaHome), + WithKeyFingerprint("this fingerprint doesn't exist"), + }, + ref: testImageSignatureReference, + }, + } { + s, err := NewSigner(c.opts...) + if c.creationFails { + assert.Error(t, err, c.name) + if c.creationErrorContains != "" { + assert.ErrorContains(t, err, c.creationErrorContains, c.name) + } + } else { + require.NoError(t, err, c.name) + defer s.Close() + + m := manifest + if c.manifest != nil { + m = c.manifest + } + _, err = internalSigner.SignImageManifest(context.Background(), s, m, c.ref) + assert.Error(t, err, c.name) + } + } +} diff --git a/signature/simplesequoia/testdata/.gitignore b/signature/simplesequoia/testdata/.gitignore new file mode 100644 index 0000000000..5dc6c4dd6d --- /dev/null +++ b/signature/simplesequoia/testdata/.gitignore @@ -0,0 +1 @@ +/data/pgp.cert.d/_sequoia* diff --git a/signature/simplesequoia/testdata/data/keystore/keystore.cookie b/signature/simplesequoia/testdata/data/keystore/keystore.cookie new file mode 100644 index 0000000000..e69de29bb2 diff --git a/signature/simplesequoia/testdata/data/keystore/softkeys/1F5825285B785E1DB13BF36D2D11A19ABA41C6AE.pgp b/signature/simplesequoia/testdata/data/keystore/softkeys/1F5825285B785E1DB13BF36D2D11A19ABA41C6AE.pgp new file mode 100644 index 0000000000000000000000000000000000000000..86462c6b64ac57df02c285e5da86fc8585d09eef GIT binary patch literal 2170 zcmbtV`#anB7k__}kV`X{>e8VkdP5{=UEAu2ulv{9PNFpJ5KR_TB_tj~?*wD(g=y>3 zNog@MB|4Orh+^9pReI5ydr?%~Ybs>4k6-qz&$oMa{(y7N>%1R@$b}j+v@ZLJA5|Dv7d2QQ!pGdDR9v{g|~F5Ir~kUM05D^kxGcP z(EWgff1uQ2G0|ePphed*mPywk@Hh-OsdR32ANV>n60Js7zn)%6X()2u09H#E5O|DW zzFi21&)^4gLU_hJR%kdUkU{3MxyGC@_Ln-Xoyiej=iS~rk{~uIFO^BATxYioi0e5` z2AtQDYWSxZ6f6UR>7sFZ2)y?;gTs+NIwgB%j;{>@;CK&EL>2>|(J#D-`NSkzf?Sk& z?CY9=LnWQxj{m3WU={_{1c6EESkhca*qlo9pewFXK4pKfXN@i{B}62hBw4 zF%Fl-AyD5hNZ_-0{J;=4;TTImhzR5d5V#B;j~fui;IU*<6@66pB9Aw=@kgeF z>R~`}pwDFAV9#!KRcE8z$P5tF`kaUQ@3kC9;hDF2dIRl<#=mn#v*28B`OkDlxoekA zO2Kx+*O!dH5_*3(da0~y*Nf=g4_94rlT@` z2JsmV1MPT!%75;NTl;rJ%*)C;vM5=dZ-qh6wa>rgFSUICi@U_kMpC;a50(L|79liO z*y5~>ptafk?oE1)|5&Q5Jo1wZ7lXfLo0X_wm$ZHF7D2u$wj;2_NqJw7MiFI&D&2Hr zOB5YNbpKj2}SCh#4A2D*>iiZNHduP~lOfvrE5p_~E`3SO(#*N@$oL zlvC#fSs$x}cFpJ?)(_@l`Pr>$SHH8mZBdrQZ!)@+XVSTDTh5b($JGb9cZOFPr$W+xO^JDBR^I0R;jtgUlDoo>=n? zFV-EoMB3(qt2LwxddLYv^dt${$;Nz83Bnk#Y;=V|85QsXHyGw)J#%ZII?*&~D!mtx zlI3=ycTtxM0imAXCp=~Na&f$ScOvEdEbYS7xZ#cb>_Z175K6ZW*_ib1Q?AFn`;=Ea zA*IzX zduksw3A3dU%+6nw?0>5lOJiLpO@zvQ>vg;eb1H1!N)JaWJn)rHj;eXD6PXSk?8paR z7Un5K(+heFr5ooQ9HO4)5?3>JB^cH+_MZoX+s>_TLcd~LhLfCcl4-Cp*~tgypNOW@ z@3Ea)PTP%Z!7{KPyk}b)Skh>>pAH{wwr^xUb1@W*YQ}b(5}(nu;y08^_O>oblroH47mNlgn}$)7GX&?gvFWildIqB}J3u zR*@ywS+tW&!XuQ2OBw2Pn&TmtBidQ@@XLABe{5U*{v zSp_~m48XE|7$JBjE5s)xh{a^%*wo{ptRNr5;J{!U>qHabj;MwNzH>gdw%@6H{z!kLy>hGdTuCSo9vbc~@&f>qq}N>KNR-7_t_UpazVWqik1 z7)Mer=<9_#){^L~U@8ks`uss`2$dZY#08ynhx1HT_l(75Ee5NQ)-0gV5Cy`mVX1=^hQbBAJOL@_T zw2`*ps`uFYiiqX%01)$mgjU&q1s{8gcDo1aP3Ih~+5+=7d;1elN4)z|hn?f-MX-b( zw}&T)?B!oN=NGJvx!AXL!aRq}=x%D8OdO99qmaTc<+?Jub$IqEXz$>MKdWmYtgtJz zawp@t7wXH}Dzs~7Q>D4)cWIg2nv0x!G*f!VqRX*)-@K`5OMs+^He1E1fGZ3!4mN;;}v_8sU#|P8WRC>k(TAG#Yt=pHH$mlv)4y+*$zDDXl zYq>?_AiCbFe>3k}&4c++#aJOJ=O2rLnUOb6XmU5#HyHs}bhQw;R90F$@Zr0>Nns@W<$3IdPEO89Q| zs+A0jt_-9vR&L{DO;obFlc;yyeGW*EfqiurIYvNY{j!z9V(IjinjL>#LRP}7xunNa z)aPGpR%^_=PN@<@;QgM;*y<(>BCJ3KEf`?#8(xWVb#E^*k7ZU42rRQs3-vL6Tgt&^>Is|1)JNTV7RjKwx35-RWodG8c^B_Co{m^qbDZ z9FM#1H{xHK(^S=enC*K+E81_ISF6?iaC>`ly`Fnc88V-;`>FqVOMU)KM;9yy`(L&! zC9a|Up*K&ym2IXS@&GLIzz3{90h7C?ChE1PxH|NJQ@>jA%t&XK-#Iga&dsOPHaD=S2=TG3g zN92A^&vBuwA1M3l;Mn~{B?K%7`BjJ1wu43FlK39=MmS~eZVf%nnAA$Tg~RHl-s8Z^ s;P4OCl-EE)m9a=8koM9&H2%!vlqp`3nN8~sUy4@^Jv?8vv)vW`FCb1O(*OVf literal 0 HcmV?d00001 diff --git a/signature/simplesequoia/testdata/data/pgp.cert.d/1f/5825285b785e1db13bf36d2d11a19aba41c6ae b/signature/simplesequoia/testdata/data/pgp.cert.d/1f/5825285b785e1db13bf36d2d11a19aba41c6ae new file mode 100644 index 0000000000000000000000000000000000000000..eb6dd1f4cc25a75626a4f1350ad539ee06804630 GIT binary patch literal 2037 zcmbuAdpOg39LK-EnQUu`bevR}N->69N*CFja!ZIQoWf*nZf$LIY)SRR;?TvVQmHm7 zQ$(iFjhS#x$K=vQ$*n~p<&r!yc1Fkf<2>~oJ$?WGem>vV=ly-ZKUEfRYM641CemmY z1czQY%!MEod}c>wuSpyK_4(VSG7v*{vwEYBYRZK%bgO$?N^X?Yh()vEx|%2ut$cX$ zveIm%3Q`THo^kFDp(@W|KA1c@0K+7OvG99nED|f2wufoLB=3!&1(R@e3f+XpplsEy zYfg#WEx2jZ9iMAjTqqU}IDK3y&8?)>7|`AeOO<{?AzW=_ zC(UXOwk7bvk{(Q4-*Pru*IeiVBv{W-8l6nTcz$^xhDBzwg7;7`p=1swGMGih&`C@t zoys6F$zqWzTth*A=tsy!B)Xl8jWWficc1;q1s46bcHv`KzUA$H@?hj1%|X>E^0UzY zz+dhLV=5NLt)_1pWe#rPZW9MgCpH!2ZGuMeQB3M;(cLb4PcX5jXURLMaHy-jbg%Y_ zXwOWwS?cdROEnOf5`EK`S*|K#5ge|j0Q&6<5G)obapi2J8rxxmzy40Ol9{UMo^%kN zm4CTo;~n>#ypC}}{lLTcqg3~2E@t}emmlpCC^X!XC?Rf+V7~u+eSvtoJOJ0c!MMiV zg6*T5M|j!M&ZI!;{)|V$bQ5={(bRdF%^AuV@?!`b3o#eQxZch8vR`;VMw)&vyol6T zZDp4M-_Tv2bMfk2u?S3IF#g3rs>KH3AhVJH`gGn7K*{_y4i~%f!r7!SL7DpR zzPLP(PquM82Ds`BAb0ODb?t0ht3KDkD2tsALh4>H5t}bu+QdEdS)eCvgx7w}i4xA? z_TpQLjuRZyPi_l`duzaZimJTcB!?hGYgf`uR*nofOZTwz$rgL5Gk)4t= z7Iu_kQJ{(*U*vx;5As*F?S>`v%R1UL@(7B#>YOuKwcat}j>Pm?#&mfAJd7Z~cQLUJ zB7R6fcsf@mEKD7c_PMKwu>v*aa_V0=Z-Nz&hkAu+4W($GT5*YXd{no-DoskR&m*kG zs*j&YNb@7Ad^0^z=OIu!YdD{Rl(^~XynFikHBI5`I`sBF{ z#g%cWQ{AsxeO9bmTo=NNjlA~iIoTbNbIBeCzAD?}(`aU()d=~H?4{iSv5w<0(`A`kz+v+Mln}OWM-VTv+Uy) z)D!x2c>sKg5V+;*b?LfU;^>(pEeAbghwe%Jb;Td9w)*c{21Pht=MW(9HpFtY=&3c+ zFsWikva!COX1Sp+rwtd+MfMx3G*eLDl#Lq$CXCWZgdPqvc)npa+AFIJs^AYA51ea< zr}CWlw~y)2A;8rOn8Tc`b3+LI|N#p;Bu-wfE+sruJT% z7oY(S2 zhMXR)*j6*_bK=6d`GrE8x^dAFAop#52HU!i*6{P6RtAfn1ex6K+!s)wYEashqn%2q HWPrZ`MD0XQ literal 0 HcmV?d00001 diff --git a/signature/simplesequoia/testdata/data/pgp.cert.d/4d/8bcd544b7573eefaad18c278473e5f255d10b8 b/signature/simplesequoia/testdata/data/pgp.cert.d/4d/8bcd544b7573eefaad18c278473e5f255d10b8 new file mode 100644 index 0000000000000000000000000000000000000000..8dae8b8d8bd6ffb3e6f1c662c2fbd869681a2173 GIT binary patch literal 492 zcmX?R%wki*utSVfn~jl$@s>M3BO|-Rn&RZ}HQTp&SNFcTZV|O&Q*w$`=S+jQc|z5{ zUYPI67dv!-k40XLi=lzF38a~+g@Kuylbutb!rd-jHCAAUy9fga$T27sC+3tm~P(OU2?Ymy3E$109C9R|6L zXIah)_~a)i<|u>|l@^yM1m)+K96BJ#A`J9mGlgE%3H-|uCRSKh(691w=JXFi>-aKX z`j;~>CS>V8U-whx5ZH?|8437u!*quKY1_K={olQn&ERJ~s5SqKWzXKrJJxreS140n uS?2A3XCouSf$OEGv|^UVPjdcdJz>f0BhoSxE`Bcj%Q0JBM?rb*TTTF$Qn%0m literal 0 HcmV?d00001 diff --git a/signature/simplesequoia/testdata/data/pgp.cert.d/50/dde898df4e48755c8c2b7af6f908b6fa48a229 b/signature/simplesequoia/testdata/data/pgp.cert.d/50/dde898df4e48755c8c2b7af6f908b6fa48a229 new file mode 100644 index 0000000000000000000000000000000000000000..b9fee9bb2484133d7f5d83134b3e3c053ecbd9dd GIT binary patch literal 2021 zcmbuAc{tR09LK-E@pFusV#p*LjiYj87Fk!tsCFnv7{@3~jtR}|jB;N~mb8kcWI{w_ z%N;p#Wu};Nh9^fJRIY5hV?81(%t~wj*r%S=)A#@H`}2K$-rx7<)4Uh9qX z3!sp~Nb&ipGV0UwSW!1=n;{Rj-EpR1oYli`c^rJnI;db_Ioc>3U(XFcKg zE$X<+nClmuI=3b#aeJTU2xBtdvUQL2F1u})YgZAF5*0zDLkKw}Rvxw*dVOug($wGS zl3K`mApmA?1HQe7vpbh09hiZ7Al@)f9bLZi_Tq74ymoxw+rW!ERSc4&B*`xfDh6;al&GD~3R6+6h?#*IATns1~5F9I^lIO`)Dy3^nIT z05_~2lPt<Y2sGc3U%lU*2MoG-q8NfQPnVNo?5OPsB4xr3BNSH2>`b z!=^JFGu2>~)T%4XkJy_MQy`F_b$NO~jVm-8lRL~=Q9`klw*M^KCT(LBX7SpL5Dqwv zU=8E!zZgjIXb*KrqxvLqqX0eW!^==NGPxMe@3jCAr2h>b5Nuv-xGFt-MtP zuVF>>QEnx=y4r4bZ1gf% z#!i^S(PQQ!uWYh&Wx_A_?VZ$3C)2yxtDr$QQ(IJYQ!lobG@ z@~~Fl%X!Qr-+Sd6*Jt!XeUFy#GvpoFgtI*x7-xgP|?3iAJ&ZZbW^SET7);QPRg-FN!*ES|9N8Q}^&C`wA_Q<)#NzTx3 zgkJsnpcr+`%?fLkDP${UHwbq51AM6bYG0>&A8HJYOX42wVpgup1F%#HR&X9fxr}W! zp;J!0YJUr>e#!i~7oA=17j=kAcb-vO9l#RG(t5_{M;2u`vIbW+2hcXDb*E!;#r`60!lt#$&Ci13F|vl=<@wG$j#L92x{-DiO74!*^_ve z7eWV;)9om-gGIkvkKd0$2_w?cpM{sy2TSN>UKRD%Aj-RYHMB%cQVXdBk5f*lVj+rP rc%_;$1^83}y+k7EFzv+F-?CUmqL~8oiQPfV=Op}(FI4Prvxol%@?bOI literal 0 HcmV?d00001 diff --git a/signature/simplesequoia/testdata/data/pgp.cert.d/68/de230c4a009f5ee5fbb27984642d0130b86046 b/signature/simplesequoia/testdata/data/pgp.cert.d/68/de230c4a009f5ee5fbb27984642d0130b86046 new file mode 100644 index 0000000000000000000000000000000000000000..6a58a268c8f53a2ee18e5a387a2a420fdb94b5df GIT binary patch literal 696 zcmX?R%wki*utSVfn~jl$@s>M3BO|**^?8Z^(**;Vd35-mm%W%=(;+l7ajoGjeW~S+ z#}8lbZa8#+k40XLi=lzF38a~+g@KuylbutbB}JFfU`K+Ry9fga$T27sC+3tmF-TD8fie=9Cs4e|xS}Y&$FKj)yX7zE74-U^- zm(5@~E9#z_ms*rqlA5BBpQn(USyH5%o0xp)fFO%7(4Wl|`t$FrX!#9|le)QtZlAt; z&v4x~%?VlhYQG)5%R28@Fuy$x_UBAS0$$x6$jGq&3`5rJ84{nKU1V=EdDD4Srr$tr zpIpP^H?JN|e*HwFn2}*h=D|9BY3;+A^W}N&Dl{d2O}d^hcW|R(_QYe1PZB!V4jo`& z5diwB4B@BN|BRdh74CNNs<8q)h>g3e@5`pPPH*YhWW7<{`Cg6c+=mt)I_M0 y$&E9&eAD;9$efYk>XgI>9FFqZANu4>Hzuz>VfKI1;eDdBJ|tRuacL{0asU80_Yfrj literal 0 HcmV?d00001 diff --git a/signature/simplesequoia/testdata/data/pgp.cert.d/trust-root b/signature/simplesequoia/testdata/data/pgp.cert.d/trust-root new file mode 100644 index 0000000000000000000000000000000000000000..addf38a5618ffc2f03e6a94c693942fc3ceaf5a2 GIT binary patch literal 529 zcmX>a!D3UwutSVfn~jl$@s>M3BO|-Rn&RZ}HQTp&SNFcTZV|O&Q*w$`=S+jQc|z5{ zUYPI67h_=fpM3dT`I$H3_k=!9o%7^i{pXJ%NnTGk-1a!b8~wn~EVoj4=Ai?8Eb?Mp z3=OPJARCxk7?`;^**OI&-0k93V+D4&i!gwI9D_n}Vor%eUVcepNoIatv0ia%VQGG5 zqHaNYfnI)5y6wlyMWKr#ILeI+_*-i|nz$cNcpzn1AY)>GNI3MVVhyt>7YEa9MkYB< zF+~>N?z17@rN!@lt(783_h8x+tp)$GCaJJ>tm0_XVUXK+mgTH~PkwS@jzUOL zX>o}{P=0>Np#y>}!ay%JQ|LvVz`q<}VufV|{VE@4PX7?JjxY12e>nqVLYD6Hbw5=O zfxS4Bk$^8ZOlSC?wyjIw|J_^J41VT=TJyhH_Uyg9V}0j&g)-%pW#0aGHZn3CxL$fn iD`si@B Date: Mon, 14 Jul 2025 17:44:03 +0200 Subject: [PATCH 17/18] Improve test coverage of signature/*_sequoia.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should not change behavior. Signed-off-by: Miloslav Trmač --- signature/mechanism_sequoia.go | 2 +- signature/mechanism_sequoia_test.go | 36 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 signature/mechanism_sequoia_test.go diff --git a/signature/mechanism_sequoia.go b/signature/mechanism_sequoia.go index 76a08b5f7d..fea5ada67e 100644 --- a/signature/mechanism_sequoia.go +++ b/signature/mechanism_sequoia.go @@ -20,7 +20,7 @@ type sequoiaEphemeralSigningMechanism struct { // The caller must call .Close() on the returned SigningMechanism. func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) { if err := sequoia.Init(); err != nil { - return nil, nil, err + return nil, nil, err // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle. } mech, err := sequoia.NewEphemeralMechanism() diff --git a/signature/mechanism_sequoia_test.go b/signature/mechanism_sequoia_test.go new file mode 100644 index 0000000000..134d4d343e --- /dev/null +++ b/signature/mechanism_sequoia_test.go @@ -0,0 +1,36 @@ +//go:build containers_image_sequoia + +package signature + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSequoiaNewEphemeralGPGSigningMechanism(t *testing.T) { + // Success is tested in the generic TestNewEphemeralGPGSigningMechanism. + + t.Setenv("SEQUOIA_CRYPTO_POLICY", "this/does/not/exist") // Both unreadable files, and relative paths, should cause an error. + _, _, err := NewEphemeralGPGSigningMechanism([]byte{}) + assert.Error(t, err) +} + +func TestSequoiaSigningMechanismSupportsSigning(t *testing.T) { + mech, _, err := NewEphemeralGPGSigningMechanism([]byte{}) + require.NoError(t, err) + defer mech.Close() + err = mech.SupportsSigning() + assert.Error(t, err) + assert.IsType(t, SigningNotSupportedError(""), err) +} + +func TestSequoiaSigningMechanismSign(t *testing.T) { + mech, _, err := NewEphemeralGPGSigningMechanism([]byte{}) + require.NoError(t, err) + defer mech.Close() + _, err = mech.Sign([]byte{}, TestKeyFingerprint) + assert.Error(t, err) + assert.IsType(t, SigningNotSupportedError(""), err) +} From 8cec77c201ca5edf4ae9f3e5dafaaa3a8eef6eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 3 Jul 2025 19:58:07 +0200 Subject: [PATCH 18/18] Test containers_image_sequoia in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI images come from https://github.com/containers/automation_images/pull/411 . Signed-off-by: Miloslav Trmač --- .cirrus.yml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 15287bb47c..30a91d769a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -30,8 +30,14 @@ env: SKOPEO_PR: # Google-cloud VM Images - IMAGE_SUFFIX: "c20250721t181111z-f42f41d13" + # If you are updating IMAGE_SUFFIX: We are currently using rawhide for + # the containers_image_sequoia tests because the rust-podman-sequoia + # package is not available in earlier releases; once we update to a future + # Fedora release (or if the package is backported), switch back from Rawhide + # to the latest Fedora release. + IMAGE_SUFFIX: "c20250812t173301z-f42f41d13" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" + RAWHIDE_CACHE_IMAGE_NAME: "rawhide-${IMAGE_SUFFIX}" # Container FQIN's (include bleeding-edge development-level container deps.) FEDORA_CONTAINER_FQIN: "quay.io/libpod/fedora_podman:${IMAGE_SUFFIX}" @@ -55,9 +61,12 @@ validate_task: # Required to be 200gig, do not modify - has i/o performance impact # according to gcloud CLI tool warning messages. disk: 200 - image_name: ${FEDORA_CACHE_IMAGE_NAME} + # Eventually, hard-code FEDORA_CACHE_IMAGE_NAME here again and remove the + # VM_IMAGE_NAME parameter. + image_name: ${VM_IMAGE_NAME} env: HOME: "/root" # default unset, needed by golangci-lint. + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} script: | git remote update make tools @@ -68,6 +77,8 @@ validate_task: cross_task: only_if: ¬_docs $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' gce_instance: *fedora_vm + env: + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} script: make cross @@ -81,9 +92,15 @@ test_task: - name: "Test" env: BUILDTAGS: '' + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} - name: "Test w/ opengpg" env: BUILDTAGS: &withopengpg 'containers_image_openpgp' + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} + - name: "Test w/ Sequoia (currently Rawhide)" + env: + BUILDTAGS: &withsequoia 'containers_image_sequoia' + VM_IMAGE_NAME: ${RAWHIDE_CACHE_IMAGE_NAME} script: ${GOSRC}/${SCRIPT_BASE}/runner.sh image_tests @@ -102,9 +119,15 @@ test_skopeo_task: - name: "Skopeo Test" env: BUILDTAGS: '' + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} - name: "Skopeo Test w/ opengpg" env: BUILDTAGS: *withopengpg + VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME} + - name: "Skopeo Test w/ Sequoia (currently Rawhide)" + env: + BUILDTAGS: *withsequoia + VM_IMAGE_NAME: ${RAWHIDE_CACHE_IMAGE_NAME} setup_script: >- "${GOSRC}/${SCRIPT_BASE}/runner.sh" setup vendor_script: >- @@ -133,6 +156,7 @@ meta_task: # Space-separated list of images used by this repository state IMGNAMES: | ${FEDORA_CACHE_IMAGE_NAME} + ${RAWHIDE_CACHE_IMAGE_NAME} BUILDID: "${CIRRUS_BUILD_ID}" REPOREF: "${CIRRUS_REPO_NAME}" GCPJSON: ENCRYPTED[04306103eee1933f87deb8a5af6514a7e3164aa589d6079abc0451eb2360879430ed020d6e025ca64ef667138ce9d786]