]> git.proxmox.com Git - proxmox-acme-rs.git/commitdiff
This repository was moved into the `proxmox.git` repository master
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Mon, 4 Dec 2023 10:48:43 +0000 (11:48 +0100)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Mon, 4 Dec 2023 10:48:43 +0000 (11:48 +0100)
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
25 files changed:
.cargo/config [deleted file]
.gitignore [deleted file]
Cargo.toml [deleted file]
Makefile [deleted file]
README [new file with mode: 0644]
debian/changelog [deleted file]
debian/control [deleted file]
debian/copyright [deleted file]
debian/debcargo.toml [deleted file]
debian/source/format [deleted file]
rustfmt.toml [deleted file]
src/account.rs [deleted file]
src/authorization.rs [deleted file]
src/b64u.rs [deleted file]
src/client.rs [deleted file]
src/directory.rs [deleted file]
src/eab.rs [deleted file]
src/error.rs [deleted file]
src/json.rs [deleted file]
src/jws.rs [deleted file]
src/key.rs [deleted file]
src/lib.rs [deleted file]
src/order.rs [deleted file]
src/request.rs [deleted file]
src/util.rs [deleted file]

diff --git a/.cargo/config b/.cargo/config
deleted file mode 100644 (file)
index 3b5b6e4..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-[source]
-[source.debian-packages]
-directory = "/usr/share/cargo/registry"
-[source.crates-io]
-replace-with = "debian-packages"
diff --git a/.gitignore b/.gitignore
deleted file mode 100644 (file)
index 96ef6c0..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/target
-Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644 (file)
index ce60b02..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-[package]
-name = "proxmox-acme-rs"
-version = "0.4.0"
-authors = ["Wolfgang Bumiller <w.bumiller@proxmox.com>"]
-edition = "2021"
-license = "AGPL-3"
-description = "ACME client library"
-exclude = [
-    "build",
-    "debian",
-]
-
-[dependencies]
-base64 = "0.13.0"
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-openssl = "0.10.29"
-
-# For the client
-native-tls = { version = "0.2", optional = true }
-
-[dependencies.ureq]
-optional = true
-version = "2.4"
-default-features = false
-features = [ "native-tls", "gzip" ]
-
-[features]
-default = []
-client = ["ureq", "native-tls"]
-
-[dev-dependencies]
-anyhow = "1.0"
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index 6d738f2..0000000
--- a/Makefile
+++ /dev/null
@@ -1,45 +0,0 @@
-.PHONY: all
-all: check
-
-.PHONY: check
-check:
-       cargo test --all-features
-
-.PHONY: dinstall
-dinstall: deb
-       sudo -k dpkg -i build/librust-*.deb
-
-.PHONY: build
-build:
-       rm -rf build
-       rm -f debian/control
-       mkdir build
-       debcargo package \
-           --config "$(PWD)/debian/debcargo.toml" \
-           --changelog-ready \
-           --no-overlay-write-back \
-           --directory "$(PWD)/build/proxmox-acme-rs" \
-           "proxmox-acme-rs" \
-           "$$(dpkg-parsechangelog -l "debian/changelog" -SVersion | sed -e 's/-.*//')"
-       echo system >build/rust-toolchain
-       rm -f build/proxmox-acme-rs/Cargo.lock
-       find build/proxmox-acme-rs/debian -name '*.hint' -delete
-       cp build/proxmox-acme-rs/debian/control debian/control
-
-.PHONY: deb
-deb: build
-       (cd build/proxmox-acme-rs && CARGO=/usr/bin/cargo RUSTC=/usr/bin/rustc dpkg-buildpackage -b -uc -us)
-       lintian build/*.deb
-
-.PHONY: clean
-clean:
-       rm -rf build *.deb *.buildinfo *.changes *.orig.tar.gz
-       cargo clean
-
-upload: deb
-       cd build; \
-           dcmd --deb rust-proxmox-acme-rs_*.changes \
-           | grep -v '.changes$$' \
-           | tar -cf "rust-proxmox-acme-rs-debs.tar" -T-; \
-           cat "rust-proxmox-acme-rs-debs.tar" | ssh -X repoman@repo.proxmox.com upload --product devel --dist bullseye; \
-           rm -f rust-proxmox-acme-rs-debs.tar
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e87b585
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+This repository was moved into the `proxmox.git` repository.
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644 (file)
index 88590ca..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-rust-proxmox-acme-rs (0.4.0) pve; urgency=medium
-
-  * switch from curl to ureq with native-tls
-
-  * bump edition to 2021
-
- -- Proxmox Support Team <support@proxmox.com>  Tue, 01 Feb 2022 10:19:29 +0100
-
-rust-proxmox-acme-rs (0.3.2) pve; urgency=medium
-
-  * rebuild with base64 0.13
-
- -- Proxmox Support Team <support@proxmox.com>  Thu, 18 Nov 2021 12:49:25 +0100
-
-rust-proxmox-acme-rs (0.3.1) pve; urgency=medium
-
-  * add proxy support
-
- -- Proxmox Support Team <support@proxmox.com>  Thu, 18 Nov 2021 09:46:34 +0100
-
-rust-proxmox-acme-rs (0.3.0) pve; urgency=medium
-
-  * directory: make metadata optional
-
- -- Proxmox Support Team <support@proxmox.com>  Thu, 21 Oct 2021 13:10:27 +0200
-
-rust-proxmox-acme-rs (0.2.2-1) pve; urgency=medium
-
-  * improve crate documentation
-
-  * mark `Error` as 'must_use'
-
-  * make status types `Copy`
-
-  * add Client::directory_url() to get the URL without querying the whole
-    directory
-
- -- Proxmox Support Team <support@proxmox.com>  Fri, 07 May 2021 13:53:08 +0200
-
-rust-proxmox-acme-rs (0.2.1-1) pve; urgency=medium
-
-  * make revocation workflow accessible without client
-
- -- Proxmox Support Team <support@proxmox.com>  Wed, 14 Apr 2021 14:56:49 +0200
-
-rust-proxmox-acme-rs (0.2.0-1) pve; urgency=medium
-
-  * add 'status' and 'url' as fixed members to `Challenge`
-
-  * expose some workflow helpers in a more consistentw ay
-
-  * add `util::Csr` for CSR generation
-
- -- Proxmox Support Team <support@proxmox.com>  Mon, 12 Apr 2021 13:06:19 +0200
-
-rust-proxmox-acme-rs (0.1.4-1) pve; urgency=medium
-
-  * collect extra account fields (such as 'created' from let's encrypt)
-    in the AccountData struct
-
- -- Proxmox Support Team <support@proxmox.com>  Wed, 17 Mar 2021 15:28:09 +0100
-
-rust-proxmox-acme-rs (0.1.3-1) pve; urgency=medium
-
-  * fix padding in ecdsa signatures
-
- -- Proxmox Support Team <support@proxmox.com>  Wed, 17 Mar 2021 13:34:10 +0100
-
-rust-proxmox-acme-rs (0.1.2-1) pve; urgency=medium
-
-  * include Content-length header in requests
-
- -- Proxmox Support Team <support@proxmox.com>  Fri, 12 Mar 2021 15:43:01 +0100
-
-rust-proxmox-acme-rs (0.1.1-1) pve; urgency=medium
-
-  * make AccountData fields public
-
- -- Proxmox Support Team <support@proxmox.com>  Tue, 09 Mar 2021 13:22:55 +0100
-
-rust-proxmox-acme-rs (0.1.0-1) pve; urgency=medium
-
-  * initial release
-
- -- Proxmox Support Team <support@proxmox.com>  Tue, 09 Mar 2021 13:01:56 +0100
diff --git a/debian/control b/debian/control
deleted file mode 100644 (file)
index 760f015..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-Source: rust-proxmox-acme-rs
-Section: rust
-Priority: optional
-Build-Depends: debhelper (>= 12),
- dh-cargo (>= 25),
- cargo:native <!nocheck>,
- rustc:native <!nocheck>,
- libstd-rust-dev <!nocheck>,
- librust-base64-0.13+default-dev <!nocheck>,
- librust-openssl-0.10+default-dev (>= 0.10.29-~~) <!nocheck>,
- librust-serde-1+default-dev <!nocheck>,
- librust-serde-1+derive-dev <!nocheck>,
- librust-serde-json-1+default-dev <!nocheck>
-Maintainer: Proxmox Support Team <support@proxmox.com>
-Standards-Version: 4.6.1
-Vcs-Git: 
-Vcs-Browser: 
-X-Cargo-Crate: proxmox-acme-rs
-Rules-Requires-Root: no
-
-Package: librust-proxmox-acme-rs-dev
-Architecture: any
-Multi-Arch: same
-Depends:
- ${misc:Depends},
- librust-base64-0.13+default-dev,
- librust-openssl-0.10+default-dev (>= 0.10.29-~~),
- librust-serde-1+default-dev,
- librust-serde-1+derive-dev,
- librust-serde-json-1+default-dev
-Suggests:
- librust-proxmox-acme-rs+client-dev (= ${binary:Version}),
- librust-proxmox-acme-rs+native-tls-dev (= ${binary:Version}),
- librust-proxmox-acme-rs+ureq-dev (= ${binary:Version})
-Provides:
- librust-proxmox-acme-rs+default-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0+default-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4+default-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4.0-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4.0+default-dev (= ${binary:Version})
-Description: ACME client library - Rust source code
- This package contains the source for the Rust proxmox-acme-rs crate, packaged
- by debcargo for use with cargo and dh-cargo.
-
-Package: librust-proxmox-acme-rs+client-dev
-Architecture: any
-Multi-Arch: same
-Depends:
- ${misc:Depends},
- librust-proxmox-acme-rs-dev (= ${binary:Version}),
- librust-proxmox-acme-rs+ureq-dev (= ${binary:Version}),
- librust-proxmox-acme-rs+native-tls-dev (= ${binary:Version})
-Provides:
- librust-proxmox-acme-rs-0+client-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4+client-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4.0+client-dev (= ${binary:Version})
-Description: ACME client library - feature "client"
- This metapackage enables feature "client" for the Rust proxmox-acme-rs crate,
- by pulling in any additional dependencies needed by that feature.
-
-Package: librust-proxmox-acme-rs+native-tls-dev
-Architecture: any
-Multi-Arch: same
-Depends:
- ${misc:Depends},
- librust-proxmox-acme-rs-dev (= ${binary:Version}),
- librust-native-tls-0.2+default-dev
-Provides:
- librust-proxmox-acme-rs-0+native-tls-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4+native-tls-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4.0+native-tls-dev (= ${binary:Version})
-Description: ACME client library - feature "native-tls"
- This metapackage enables feature "native-tls" for the Rust proxmox-acme-rs
- crate, by pulling in any additional dependencies needed by that feature.
-
-Package: librust-proxmox-acme-rs+ureq-dev
-Architecture: any
-Multi-Arch: same
-Depends:
- ${misc:Depends},
- librust-proxmox-acme-rs-dev (= ${binary:Version}),
- librust-ureq-2+gzip-dev (>= 2.4-~~),
- librust-ureq-2+native-tls-dev (>= 2.4-~~)
-Provides:
- librust-proxmox-acme-rs-0+ureq-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4+ureq-dev (= ${binary:Version}),
- librust-proxmox-acme-rs-0.4.0+ureq-dev (= ${binary:Version})
-Description: ACME client library - feature "ureq"
- This metapackage enables feature "ureq" for the Rust proxmox-acme-rs crate, by
- pulling in any additional dependencies needed by that feature.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644 (file)
index 477c305..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Copyright (C) 2020-2021 Proxmox Server Solutions GmbH
-
-This software is written by Proxmox Server Solutions GmbH <support@proxmox.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/debian/debcargo.toml b/debian/debcargo.toml
deleted file mode 100644 (file)
index 703440f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-overlay = "."
-crate_src_path = ".."
-maintainer = "Proxmox Support Team <support@proxmox.com>"
-
-[source]
-# TODO: update once public
-vcs_git = ""
-vcs_browser = ""
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644 (file)
index 89ae9db..0000000
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (native)
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 100644 (file)
index 32a9786..0000000
+++ /dev/null
@@ -1 +0,0 @@
-edition = "2018"
diff --git a/src/account.rs b/src/account.rs
deleted file mode 100644 (file)
index 9f3af26..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-//! ACME Account management and creation. The [`Account`] type also contains most of the ACME API
-//! entry point helpers.
-
-use std::collections::HashMap;
-use std::convert::TryFrom;
-
-use openssl::pkey::{PKey, Private};
-use serde::{Deserialize, Serialize};
-use serde_json::Value;
-
-use crate::authorization::{Authorization, GetAuthorization};
-use crate::b64u;
-use crate::directory::Directory;
-use crate::eab::ExternalAccountBinding;
-use crate::jws::Jws;
-use crate::key::{Jwk, PublicKey};
-use crate::order::{NewOrder, Order, OrderData};
-use crate::request::Request;
-use crate::Error;
-
-/// An ACME Account.
-///
-/// This contains the location URL, the account data and the private key for an account.
-/// This can directly be serialized via serde to persist the account.
-///
-/// In order to register a new account with an ACME provider, see the [`Account::creator`] method.
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Account {
-    /// Account location URL.
-    pub location: String,
-
-    /// Acme account data.
-    pub data: AccountData,
-
-    /// base64url encoded PEM formatted private key.
-    pub private_key: String,
-}
-
-impl Account {
-    /// Rebuild an account from its components.
-    pub fn from_parts(location: String, private_key: String, data: AccountData) -> Self {
-        Self {
-            location,
-            data,
-            private_key,
-        }
-    }
-
-    /// Builds an [`AccountCreator`]. This handles creation of the private key and account data as
-    /// well as handling the response sent by the server for the registration request.
-    pub fn creator() -> AccountCreator {
-        AccountCreator::default()
-    }
-
-    /// Place a new order. This will build a [`NewOrder`] representing an in flight order creation
-    /// request.
-    ///
-    /// The returned `NewOrder`'s `request` option is *guaranteed* to be `Some(Request)`.
-    pub fn new_order(
-        &self,
-        order: &OrderData,
-        directory: &Directory,
-        nonce: &str,
-    ) -> Result<NewOrder, Error> {
-        let key = PKey::private_key_from_pem(self.private_key.as_bytes())?;
-
-        if order.identifiers.is_empty() {
-            return Err(Error::EmptyOrder);
-        }
-
-        let url = directory.new_order_url();
-        let body = serde_json::to_string(&Jws::new(
-            &key,
-            Some(self.location.clone()),
-            url.to_owned(),
-            nonce.to_owned(),
-            order,
-        )?)?;
-
-        let request = Request {
-            url: url.to_owned(),
-            method: "POST",
-            content_type: crate::request::JSON_CONTENT_TYPE,
-            body,
-            expected: crate::request::CREATED,
-        };
-
-        Ok(NewOrder::new(request))
-    }
-
-    /// Prepare a "POST-as-GET" request to fetch data. Low level helper.
-    pub fn get_request(&self, url: &str, nonce: &str) -> Result<Request, Error> {
-        let key = PKey::private_key_from_pem(self.private_key.as_bytes())?;
-        let body = serde_json::to_string(&Jws::new_full(
-            &key,
-            Some(self.location.clone()),
-            url.to_owned(),
-            nonce.to_owned(),
-            String::new(),
-        )?)?;
-
-        Ok(Request {
-            url: url.to_owned(),
-            method: "POST",
-            content_type: crate::request::JSON_CONTENT_TYPE,
-            body,
-            expected: 200,
-        })
-    }
-
-    /// Prepare a JSON POST request. Low level helper.
-    pub fn post_request<T: Serialize>(
-        &self,
-        url: &str,
-        nonce: &str,
-        data: &T,
-    ) -> Result<Request, Error> {
-        let key = PKey::private_key_from_pem(self.private_key.as_bytes())?;
-        let body = serde_json::to_string(&Jws::new(
-            &key,
-            Some(self.location.clone()),
-            url.to_owned(),
-            nonce.to_owned(),
-            data,
-        )?)?;
-
-        Ok(Request {
-            url: url.to_owned(),
-            method: "POST",
-            content_type: crate::request::JSON_CONTENT_TYPE,
-            body,
-            expected: 200,
-        })
-    }
-
-    /// Prepare a JSON POST request.
-    fn post_request_raw_payload(
-        &self,
-        url: &str,
-        nonce: &str,
-        payload: String,
-    ) -> Result<Request, Error> {
-        let key = PKey::private_key_from_pem(self.private_key.as_bytes())?;
-        let body = serde_json::to_string(&Jws::new_full(
-            &key,
-            Some(self.location.clone()),
-            url.to_owned(),
-            nonce.to_owned(),
-            payload,
-        )?)?;
-
-        Ok(Request {
-            url: url.to_owned(),
-            method: "POST",
-            content_type: crate::request::JSON_CONTENT_TYPE,
-            body,
-            expected: 200,
-        })
-    }
-
-    /// Get the "key authorization" for a token.
-    pub fn key_authorization(&self, token: &str) -> Result<String, Error> {
-        let key = PKey::private_key_from_pem(self.private_key.as_bytes())?;
-        let thumbprint = PublicKey::try_from(&*key)?.thumbprint()?;
-        Ok(format!("{}.{}", token, thumbprint))
-    }
-
-    /// Get the TXT field value for a dns-01 token. This is the base64url encoded sha256 digest of
-    /// the key authorization value.
-    pub fn dns_01_txt_value(&self, token: &str) -> Result<String, Error> {
-        let key_authorization = self.key_authorization(token)?;
-        let digest = openssl::sha::sha256(key_authorization.as_bytes());
-        Ok(b64u::encode(&digest))
-    }
-
-    /// Prepare a request to update account data.
-    ///
-    /// This is a rather low level interface. You should know what you're doing.
-    pub fn update_account_request<T: Serialize>(
-        &self,
-        nonce: &str,
-        data: &T,
-    ) -> Result<Request, Error> {
-        self.post_request(&self.location, nonce, data)
-    }
-
-    /// Prepare a request to deactivate this account.
-    pub fn deactivate_account_request<T: Serialize>(&self, nonce: &str) -> Result<Request, Error> {
-        self.post_request_raw_payload(
-            &self.location,
-            nonce,
-            r#"{"status":"deactivated"}"#.to_string(),
-        )
-    }
-
-    /// Prepare a request to query an Authorization for an Order.
-    ///
-    /// Returns `Ok(None)` if `auth_index` is out of out of range. You can query the number of
-    /// authorizations from via [`Order::authorization_len`] or by manually inspecting its
-    /// `.data.authorization` vector.
-    pub fn get_authorization(
-        &self,
-        order: &Order,
-        auth_index: usize,
-        nonce: &str,
-    ) -> Result<Option<GetAuthorization>, Error> {
-        match order.authorization(auth_index) {
-            None => Ok(None),
-            Some(url) => Ok(Some(GetAuthorization::new(self.get_request(url, nonce)?))),
-        }
-    }
-
-    /// Prepare a request to validate a Challenge from an Authorization.
-    ///
-    /// Returns `Ok(None)` if `challenge_index` is out of out of range. The challenge count is
-    /// available by inspecting the [`Authorization::challenges`] vector.
-    ///
-    /// This returns a raw `Request` since validation takes some time and the `Authorization`
-    /// object has to be re-queried and its `status` inspected.
-    pub fn validate_challenge(
-        &self,
-        authorization: &Authorization,
-        challenge_index: usize,
-        nonce: &str,
-    ) -> Result<Option<Request>, Error> {
-        match authorization.challenges.get(challenge_index) {
-            None => Ok(None),
-            Some(challenge) => self
-                .post_request_raw_payload(&challenge.url, nonce, "{}".to_string())
-                .map(Some),
-        }
-    }
-
-    /// Prepare a request to revoke a certificate.
-    ///
-    /// The certificate can be either PEM or DER formatted.
-    ///
-    /// Note that this uses the account's key for authorization.
-    ///
-    /// Revocation using a certificate's private key is not yet implemented.
-    pub fn revoke_certificate(
-        &self,
-        certificate: &[u8],
-        reason: Option<u32>,
-    ) -> Result<CertificateRevocation, Error> {
-        let cert = if certificate.starts_with(b"-----BEGIN CERTIFICATE-----") {
-            b64u::encode(&openssl::x509::X509::from_pem(certificate)?.to_der()?)
-        } else {
-            b64u::encode(certificate)
-        };
-
-        let data = match reason {
-            Some(reason) => serde_json::json!({ "certificate": cert, "reason": reason }),
-            None => serde_json::json!({ "certificate": cert }),
-        };
-
-        Ok(CertificateRevocation {
-            account: self,
-            data,
-        })
-    }
-}
-
-/// Certificate revocation involves converting the certificate to base64url encoded DER and then
-/// embedding it in a json structure. Since we also need a nonce and possibly retry the request if
-/// a `BadNonce` error happens, this caches the converted data for efficiency.
-pub struct CertificateRevocation<'a> {
-    account: &'a Account,
-    data: Value,
-}
-
-impl CertificateRevocation<'_> {
-    /// Create the revocation request using the specified nonce for the given directory.
-    pub fn request(&self, directory: &Directory, nonce: &str) -> Result<Request, Error> {
-        self.account
-            .post_request(&directory.data.revoke_cert, nonce, &self.data)
-    }
-}
-
-/// Status of an ACME account.
-#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub enum AccountStatus {
-    /// This is not part of the ACME API, but a temporary marker for us until the ACME provider
-    /// tells us the account's real status.
-    #[serde(rename = "<invalid>")]
-    New,
-
-    /// Means the account is valid and can be used.
-    Valid,
-
-    /// The account has been deactivated by its user and cannot be used anymore.
-    Deactivated,
-
-    /// The account has been revoked by the server and cannot be used anymore.
-    Revoked,
-}
-
-impl AccountStatus {
-    #[inline]
-    fn new() -> Self {
-        AccountStatus::New
-    }
-
-    #[inline]
-    fn is_new(&self) -> bool {
-        *self == AccountStatus::New
-    }
-}
-
-/// ACME Account data. This is the part of the account returned from and possibly sent to the ACME
-/// provider. Some fields may be uptdated by the user via a request to the account location, others
-/// may not be changed.
-#[derive(Clone, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct AccountData {
-    /// The current account status.
-    #[serde(
-        skip_serializing_if = "AccountStatus::is_new",
-        default = "AccountStatus::new"
-    )]
-    pub status: AccountStatus,
-
-    /// URLs to currently pending orders.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub orders: Option<String>,
-
-    /// The acccount's contact info.
-    ///
-    /// This usually contains a `"mailto:<email address>"` entry but may also contain some other
-    /// data if the server accepts it.
-    #[serde(skip_serializing_if = "Vec::is_empty", default)]
-    pub contact: Vec<String>,
-
-    /// Indicated whether the user agreed to the ACME provider's terms of service.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub terms_of_service_agreed: Option<bool>,
-
-    /// External account information.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub external_account_binding: Option<ExternalAccountBinding>,
-
-    /// This is only used by the client when querying an account.
-    #[serde(default = "default_true", skip_serializing_if = "is_false")]
-    pub only_return_existing: bool,
-
-    /// Stores unknown fields if there are any.
-    #[serde(flatten, default, skip_serializing_if = "HashMap::is_empty")]
-    pub extra: HashMap<String, Value>,
-}
-
-#[inline]
-fn default_true() -> bool {
-    true
-}
-
-#[inline]
-fn is_false(b: &bool) -> bool {
-    !*b
-}
-
-/// Helper to create an account.
-///
-/// This is used to generate a private key and set the contact info for the account. Afterwards the
-/// creation request can be created via the [`request`](AccountCreator::request()) method, giving
-/// it a nonce and a directory.  This can be repeated, if necessary, like when the nonce fails.
-///
-/// When the server sends a succesful response, it should be passed to the
-/// [`response`](AccountCreator::response()) method to finish the creation of an [`Account`] which
-/// can then be persisted.
-#[derive(Default)]
-#[must_use = "when creating an account you must pass the response to AccountCreator::response()!"]
-pub struct AccountCreator {
-    contact: Vec<String>,
-    terms_of_service_agreed: bool,
-    key: Option<PKey<Private>>,
-    eab_credentials: Option<(String, PKey<Private>)>,
-}
-
-impl AccountCreator {
-    /// Replace the contact infor with the provided ACME compatible data.
-    pub fn set_contacts(mut self, contact: Vec<String>) -> Self {
-        self.contact = contact;
-        self
-    }
-
-    /// Append a contact string.
-    pub fn contact(mut self, contact: String) -> Self {
-        self.contact.push(contact);
-        self
-    }
-
-    /// Append an email address to the contact list.
-    pub fn email(self, email: String) -> Self {
-        self.contact(format!("mailto:{}", email))
-    }
-
-    /// Change whether the account agrees to the terms of service. Use the directory's or client's
-    /// `terms_of_service_url()` method to present the user with the Terms of Service.
-    pub fn agree_to_tos(mut self, agree: bool) -> Self {
-        self.terms_of_service_agreed = agree;
-        self
-    }
-
-    /// Set the EAB credentials for the account registration
-    pub fn set_eab_credentials(mut self, kid: String, hmac_key: String) -> Result<Self, Error> {
-        let hmac_key = PKey::hmac(&base64::decode(hmac_key)?)?;
-        self.eab_credentials = Some((kid, hmac_key));
-        Ok(self)
-    }
-
-    /// Generate a new RSA key of the specified key size.
-    pub fn generate_rsa_key(self, bits: u32) -> Result<Self, Error> {
-        let key = openssl::rsa::Rsa::generate(bits)?;
-        Ok(self.with_key(PKey::from_rsa(key)?))
-    }
-
-    /// Generate a new P-256 EC key.
-    pub fn generate_ec_key(self) -> Result<Self, Error> {
-        let key = openssl::ec::EcKey::generate(
-            openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1)?.as_ref(),
-        )?;
-        Ok(self.with_key(PKey::from_ec_key(key)?))
-    }
-
-    /// Use an existing key. Note that only RSA and EC keys using the `P-256` curve are currently
-    /// supported, however, this will not be checked at this point.
-    pub fn with_key(mut self, key: PKey<Private>) -> Self {
-        self.key = Some(key);
-        self
-    }
-
-    /// Prepare a HTTP request to create this account.
-    ///
-    /// Changes to the user data made after this will have no effect on the account generated with
-    /// the resulting request.
-    /// Changing the private key between using the request and passing the response to
-    /// [`response`](AccountCreator::response()) will render the account unusable!
-    pub fn request(&self, directory: &Directory, nonce: &str) -> Result<Request, Error> {
-        let key = self.key.as_deref().ok_or(Error::MissingKey)?;
-        let url = directory.new_account_url();
-
-        let external_account_binding = self
-            .eab_credentials
-            .as_ref()
-            .map(|cred| {
-                ExternalAccountBinding::new(&cred.0, &cred.1, Jwk::try_from(key)?, url.to_string())
-            })
-            .transpose()?;
-
-        let data = AccountData {
-            orders: None,
-            status: AccountStatus::New,
-            contact: self.contact.clone(),
-            terms_of_service_agreed: if self.terms_of_service_agreed {
-                Some(true)
-            } else {
-                None
-            },
-            external_account_binding,
-            only_return_existing: false,
-            extra: HashMap::new(),
-        };
-
-        let body = serde_json::to_string(&Jws::new(
-            key,
-            None,
-            url.to_owned(),
-            nonce.to_owned(),
-            &data,
-        )?)?;
-
-        Ok(Request {
-            url: url.to_owned(),
-            method: "POST",
-            content_type: crate::request::JSON_CONTENT_TYPE,
-            body,
-            expected: crate::request::CREATED,
-        })
-    }
-
-    /// After issuing the request from [`request()`](AccountCreator::request()), the response's
-    /// `Location` header and body must be passed to this for verification and to create an account
-    /// which is to be persisted!
-    pub fn response(self, location_header: String, response_body: &[u8]) -> Result<Account, Error> {
-        let private_key = self
-            .key
-            .ok_or(Error::MissingKey)?
-            .private_key_to_pem_pkcs8()?;
-        let private_key = String::from_utf8(private_key).map_err(|_| {
-            Error::Custom("PEM key contained illegal non-utf-8 characters".to_string())
-        })?;
-
-        Ok(Account {
-            location: location_header,
-            data: serde_json::from_slice(response_body)
-                .map_err(|err| Error::BadAccountData(err.to_string()))?,
-            private_key,
-        })
-    }
-}
diff --git a/src/authorization.rs b/src/authorization.rs
deleted file mode 100644 (file)
index fee3614..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-//! Authorization and Challenge data.
-
-use std::collections::HashMap;
-
-use serde::{Deserialize, Serialize};
-use serde_json::Value;
-
-use crate::order::Identifier;
-use crate::request::Request;
-use crate::Error;
-
-/// Status of an [`Authorization`].
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum Status {
-    /// The authorization was deactivated by the client.
-    Deactivated,
-
-    /// The authorization expired.
-    Expired,
-
-    /// The authorization failed and is now invalid.
-    Invalid,
-
-    /// Validation is pending.
-    Pending,
-
-    /// The authorization was revoked by the server.
-    Revoked,
-
-    /// The identifier is authorized.
-    Valid,
-}
-
-impl Status {
-    /// Convenience method to check if the status is 'pending'.
-    #[inline]
-    pub fn is_pending(self) -> bool {
-        self == Status::Pending
-    }
-
-    /// Convenience method to check if the status is 'valid'.
-    #[inline]
-    pub fn is_valid(self) -> bool {
-        self == Status::Valid
-    }
-}
-
-/// Represents an authorization state for an order. The user is expected to pick a challenge,
-/// execute it, and the request validation for it.
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Authorization {
-    /// The identifier (usually domain name) this authorization is for.
-    pub identifier: Identifier,
-
-    /// The current status of this authorization entry.
-    pub status: Status,
-
-    /// Expiration date for the authorization.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub expires: Option<String>,
-
-    /// List of challenges which can be used to complete this authorization.
-    pub challenges: Vec<Challenge>,
-
-    /// The authorization is for a wildcard domain.
-    #[serde(default, skip_serializing_if = "is_false")]
-    pub wildcard: bool,
-}
-
-/// The state of a challenge.
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum ChallengeStatus {
-    /// The challenge is pending and has not been validated yet.
-    Pending,
-
-    /// The valiation is in progress.
-    Processing,
-
-    /// The challenge was successfully validated.
-    Valid,
-
-    /// Validation of this challenge failed.
-    Invalid,
-}
-
-impl ChallengeStatus {
-    /// Convenience method to check if the status is 'pending'.
-    #[inline]
-    pub fn is_pending(self) -> bool {
-        self == ChallengeStatus::Pending
-    }
-
-    /// Convenience method to check if the status is 'valid'.
-    #[inline]
-    pub fn is_valid(self) -> bool {
-        self == ChallengeStatus::Valid
-    }
-}
-
-/// A challenge object contains information on how to complete an authorization for an order.
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Challenge {
-    /// The challenge type (such as `"dns-01"`).
-    #[serde(rename = "type")]
-    pub ty: String,
-
-    /// The current challenge status.
-    pub status: ChallengeStatus,
-
-    /// The URL used to post to in order to begin the validation for this challenge.
-    pub url: String,
-
-    /// Contains the remaining fields of the Challenge object, such as the `token`.
-    #[serde(flatten)]
-    pub data: HashMap<String, Value>,
-}
-
-impl Challenge {
-    /// Most challenges have a `token` used for key authorizations. This is a convenience helper to
-    /// access it.
-    pub fn token(&self) -> Option<&str> {
-        self.data.get("token").and_then(Value::as_str)
-    }
-}
-
-/// Serde helper
-#[inline]
-fn is_false(b: &bool) -> bool {
-    !*b
-}
-
-/// Represents an in-flight query for an authorization.
-///
-/// This is created via [`Account::get_authorization`](crate::Account::get_authorization()).
-pub struct GetAuthorization {
-    //order: OrderData,
-    /// The request to send to the ACME provider. This is wrapped in an option in order to allow
-    /// moving it out instead of copying the contents.
-    ///
-    /// When generated via [`Account::get_authorization`](crate::Account::get_authorization()),
-    /// this is guaranteed to be `Some`.
-    ///
-    /// The response should be passed to the the [`response`](GetAuthorization::response()) method.
-    pub request: Option<Request>,
-}
-
-impl GetAuthorization {
-    pub(crate) fn new(request: Request) -> Self {
-        Self {
-            request: Some(request),
-        }
-    }
-
-    /// Deal with the response we got from the server.
-    pub fn response(self, response_body: &[u8]) -> Result<Authorization, Error> {
-        Ok(serde_json::from_slice(response_body)?)
-    }
-}
diff --git a/src/b64u.rs b/src/b64u.rs
deleted file mode 100644 (file)
index a4f8ce0..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-fn config() -> base64::Config {
-    base64::Config::new(base64::CharacterSet::UrlSafe, false)
-}
-
-/// Encode bytes as base64url into a `String`.
-pub fn encode(data: &[u8]) -> String {
-    base64::encode_config(data, config())
-}
-
-// curiously currently unused as we don't deserialize any of that
-// /// Decode bytes from a base64url string.
-// pub fn decode(data: &str) -> Result<Vec<u8>, base64::DecodeError> {
-//     base64::decode_config(data, config())
-// }
-
-/// Our serde module for encoding bytes as base64url encoded strings.
-pub mod bytes {
-    use serde::{Serialize, Serializer};
-    //use serde::{Deserialize, Deserializer};
-
-    pub fn serialize<S>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: Serializer,
-    {
-        super::encode(data).serialize(serializer)
-    }
-
-    // curiously currently unused as we don't deserialize any of that
-    // pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
-    // where
-    //     D: Deserializer<'de>,
-    // {
-    //     use serde::de::Error;
-
-    //     Ok(super::decode(&String::deserialize(deserializer)?)
-    //         .map_err(|e| D::Error::custom(e.to_string()))?)
-    // }
-}
diff --git a/src/client.rs b/src/client.rs
deleted file mode 100644 (file)
index 53f2688..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-//! A blocking higher-level ACME client implementation using 'curl'.
-
-use std::io::Read;
-use std::sync::Arc;
-
-use serde::{Deserialize, Serialize};
-
-use crate::b64u;
-use crate::error;
-use crate::order::OrderData;
-use crate::request::ErrorResponse;
-use crate::{Account, Authorization, Challenge, Directory, Error, Order, Request};
-
-macro_rules! format_err {
-    ($($fmt:tt)*) => { Error::Client(format!($($fmt)*)) };
-}
-
-macro_rules! bail {
-    ($($fmt:tt)*) => {{ return Err(format_err!($($fmt)*)); }}
-}
-
-/// Low level HTTP response structure.
-pub struct HttpResponse {
-    /// The raw HTTP response body as a byte vector.
-    pub body: Vec<u8>,
-
-    /// The http status code.
-    pub status: u16,
-
-    /// The headers relevant to the ACME protocol.
-    pub headers: Headers,
-}
-
-impl HttpResponse {
-    /// Check the HTTP status code for a success code (200..299).
-    pub fn is_success(&self) -> bool {
-        self.status >= 200 && self.status < 300
-    }
-
-    /// Convenience shortcut to perform json deserialization of the returned body.
-    pub fn json<T: for<'a> Deserialize<'a>>(&self) -> Result<T, Error> {
-        Ok(serde_json::from_slice(&self.body)?)
-    }
-
-    /// Access the raw body as bytes.
-    pub fn bytes(&self) -> &[u8] {
-        &self.body
-    }
-
-    /// Get the returned location header. Borrowing shortcut to `self.headers.location`.
-    pub fn location(&self) -> Option<&str> {
-        self.headers.location.as_deref()
-    }
-
-    /// Convenience helper to assert that a location header was part of the response.
-    pub fn location_required(&mut self) -> Result<String, Error> {
-        self.headers
-            .location
-            .take()
-            .ok_or_else(|| format_err!("missing Location header"))
-    }
-}
-
-/// Contains headers from the HTTP response which are relevant parts of the Acme API.
-///
-/// Note that access to the `nonce` header is internal to this crate only, since a nonce will
-/// always be moved out of the response into the `Client` whenever a new nonce is received.
-#[derive(Default)]
-pub struct Headers {
-    /// The 'Location' header usually encodes the URL where an account or order can be queried from
-    /// after they were created.
-    pub location: Option<String>,
-    nonce: Option<String>,
-}
-
-struct Inner {
-    agent: Option<ureq::Agent>,
-    nonce: Option<String>,
-    proxy: Option<String>,
-}
-
-impl Inner {
-    fn agent(&mut self) -> Result<&mut ureq::Agent, Error> {
-        if self.agent.is_none() {
-            let connector = Arc::new(
-                native_tls::TlsConnector::new()
-                    .map_err(|err| format_err!("failed to create tls connector: {}", err))?,
-            );
-
-            let mut builder = ureq::AgentBuilder::new().tls_connector(connector);
-
-            if let Some(proxy) = self.proxy.as_deref() {
-                builder = builder.proxy(
-                    ureq::Proxy::new(proxy)
-                        .map_err(|err| format_err!("failed to set proxy: {}", err))?,
-                );
-            }
-
-            self.agent = Some(builder.build());
-        }
-
-        Ok(self.agent.as_mut().unwrap())
-    }
-
-    fn new() -> Self {
-        Self {
-            agent: None,
-            nonce: None,
-            proxy: None,
-        }
-    }
-
-    fn execute(
-        &mut self,
-        method: &[u8],
-        url: &str,
-        request_body: Option<(&str, &[u8])>, // content-type and body
-    ) -> Result<HttpResponse, Error> {
-        let agent = self.agent()?;
-        let req = match method {
-            b"POST" => agent.post(url),
-            b"GET" => agent.get(url),
-            b"HEAD" => agent.head(url),
-            other => bail!("invalid http method: {:?}", other),
-        };
-
-        let response = if let Some((content_type, body)) = request_body {
-            req.set("Content-Type", content_type)
-                .set("Content-Length", &body.len().to_string())
-                .send_bytes(body)
-        } else {
-            req.call()
-        }
-        .map_err(|err| format_err!("http request failed: {}", err))?;
-
-        let mut headers = Headers::default();
-        if let Some(value) = response.header(crate::LOCATION) {
-            headers.location = Some(value.to_owned());
-        }
-
-        if let Some(value) = response.header(crate::REPLAY_NONCE) {
-            headers.nonce = Some(value.to_owned());
-        }
-
-        let status = response.status();
-
-        let mut body = Vec::new();
-        response
-            .into_reader()
-            .take(16 * 1024 * 1024) // arbitrary limit
-            .read_to_end(&mut body)
-            .map_err(|err| format_err!("failed to read response body: {}", err))?;
-
-        Ok(HttpResponse {
-            status,
-            headers,
-            body,
-        })
-    }
-
-    pub fn set_proxy(&mut self, proxy: String) {
-        self.proxy = Some(proxy);
-        self.agent = None;
-    }
-
-    /// Low-level API to run an API request. This automatically updates the current nonce!
-    fn run_request(&mut self, request: Request) -> Result<HttpResponse, Error> {
-        let body = if request.body.is_empty() {
-            None
-        } else {
-            Some((request.content_type, request.body.as_bytes()))
-        };
-
-        let mut response = self
-            .execute(request.method.as_bytes(), &request.url, body)
-            .map_err({
-                // borrow fixup:
-                let method = &request.method;
-                let url = &request.url;
-                move |err| format_err!("failed to execute {} request to {}: {}", method, url, err)
-            })?;
-
-        let got_nonce = self.update_nonce(&mut response)?;
-
-        if response.is_success() {
-            if response.status != request.expected {
-                return Err(Error::InvalidApi(format!(
-                    "API server responded with unexpected status code: {:?}",
-                    response.status
-                )));
-            }
-            return Ok(response);
-        }
-
-        let error: ErrorResponse = response.json().map_err(|err| {
-            format_err!("error status with improper error ACME response: {}", err)
-        })?;
-
-        if error.ty == error::BAD_NONCE {
-            if !got_nonce {
-                return Err(Error::InvalidApi(
-                    "badNonce without a new Replay-Nonce header".to_string(),
-                ));
-            }
-            return Err(Error::BadNonce);
-        }
-
-        Err(Error::Api(error))
-    }
-
-    /// If the response contained a nonce, update our nonce and return `true`, otherwise return
-    /// `false`.
-    fn update_nonce(&mut self, response: &mut HttpResponse) -> Result<bool, Error> {
-        match response.headers.nonce.take() {
-            Some(nonce) => {
-                self.nonce = Some(nonce);
-                Ok(true)
-            }
-            None => Ok(false),
-        }
-    }
-
-    /// Update the nonce, if there isn't one it is an error.
-    fn must_update_nonce(&mut self, response: &mut HttpResponse) -> Result<(), Error> {
-        if !self.update_nonce(response)? {
-            bail!("newNonce URL did not return a nonce");
-        }
-        Ok(())
-    }
-
-    /// Update the Nonce.
-    fn new_nonce(&mut self, new_nonce_url: &str) -> Result<(), Error> {
-        let mut response = self.execute(b"HEAD", new_nonce_url, None).map_err(|err| {
-            Error::InvalidApi(format!("failed to get HEAD of newNonce URL: {}", err))
-        })?;
-
-        if !response.is_success() {
-            bail!("HEAD on newNonce URL returned error");
-        }
-
-        self.must_update_nonce(&mut response)?;
-
-        Ok(())
-    }
-
-    /// Make sure a nonce is available without forcing renewal.
-    fn nonce(&mut self, new_nonce_url: &str) -> Result<&str, Error> {
-        if self.nonce.is_none() {
-            self.new_nonce(new_nonce_url)?;
-        }
-        self.nonce
-            .as_deref()
-            .ok_or_else(|| format_err!("failed to get nonce"))
-    }
-}
-
-/// A blocking Acme client using curl's `Easy` interface.
-pub struct Client {
-    inner: Inner,
-    directory: Option<Directory>,
-    account: Option<Account>,
-    directory_url: String,
-}
-
-impl Client {
-    /// Create a new Client. This has no account associated with it yet, so the next step is to
-    /// either attach an existing `Account` or create a new one.
-    pub fn new(directory_url: String) -> Self {
-        Self {
-            inner: Inner::new(),
-            directory: None,
-            account: None,
-            directory_url,
-        }
-    }
-
-    /// Get the directory URL without querying the `Directory` structure.
-    ///
-    /// The difference to [`directory`](Client::directory()) is that this does not
-    /// attempt to fetch the directory data from the ACME server.
-    pub fn directory_url(&self) -> &str {
-        &self.directory_url
-    }
-
-    /// Set the account this client should use.
-    pub fn set_account(&mut self, account: Account) {
-        self.account = Some(account);
-    }
-
-    /// Get the Directory information.
-    pub fn directory(&mut self) -> Result<&Directory, Error> {
-        Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)
-    }
-
-    /// Get the Directory information.
-    fn get_directory<'a>(
-        inner: &'_ mut Inner,
-        directory: &'a mut Option<Directory>,
-        directory_url: &str,
-    ) -> Result<&'a Directory, Error> {
-        if let Some(d) = directory {
-            return Ok(d);
-        }
-
-        let response = inner
-            .execute(b"GET", directory_url, None)
-            .map_err(|err| Error::InvalidApi(format!("failed to get directory info: {}", err)))?;
-
-        if !response.is_success() {
-            bail!(
-                "GET on the directory URL returned error status ({})",
-                response.status
-            );
-        }
-
-        *directory = Some(Directory::from_parts(
-            directory_url.to_string(),
-            response.json()?,
-        ));
-        Ok(directory.as_ref().unwrap())
-    }
-
-    /// Get the current account, if there is one.
-    pub fn account(&self) -> Option<&Account> {
-        self.account.as_ref()
-    }
-
-    /// Convenience method to get the ToS URL from the contained `Directory`.
-    ///
-    /// This requires mutable self as the directory information may be lazily loaded, which can
-    /// fail.
-    pub fn terms_of_service_url(&mut self) -> Result<Option<&str>, Error> {
-        Ok(self.directory()?.terms_of_service_url())
-    }
-
-    /// Get a fresh nonce (this should normally not be required as nonces are updated
-    /// automatically, even when a `badNonce` error occurs, which according to the ACME API
-    /// specification should include a new valid nonce in its headers anyway).
-    pub fn new_nonce(&mut self) -> Result<(), Error> {
-        let was_none = self.inner.nonce.is_none();
-        let directory =
-            Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-        if was_none && self.inner.nonce.is_some() {
-            // this was the first call and we already got a nonce from querying the directory
-            return Ok(());
-        }
-
-        // otherwise actually call up to get a new nonce
-        self.inner.new_nonce(directory.new_nonce_url())
-    }
-
-    /// borrow helper
-    fn nonce<'a>(inner: &'a mut Inner, directory: &'_ Directory) -> Result<&'a str, Error> {
-        inner.nonce(directory.new_nonce_url())
-    }
-
-    /// Convenience method to create a new account with a list of ACME compatible contact strings
-    /// (eg. `mailto:someone@example.com`).
-    ///
-    /// Please remember to persist the returned `Account` structure somewhere to not lose access to
-    /// the account!
-    ///
-    /// If an RSA key size is provided, an RSA key will be generated. Otherwise an EC key using the
-    /// P-256 curve will be generated.
-    pub fn new_account(
-        &mut self,
-        contact: Vec<String>,
-        tos_agreed: bool,
-        rsa_bits: Option<u32>,
-        eab_creds: Option<(String, String)>,
-    ) -> Result<&Account, Error> {
-        let mut account = Account::creator()
-            .set_contacts(contact)
-            .agree_to_tos(tos_agreed);
-        if let Some((eab_kid, eab_hmac_key)) = eab_creds {
-            account = account.set_eab_credentials(eab_kid, eab_hmac_key)?;
-        }
-        let account = if let Some(bits) = rsa_bits {
-            account.generate_rsa_key(bits)?
-        } else {
-            account.generate_ec_key()?
-        };
-
-        self.register_account(account)
-    }
-
-    /// Register an ACME account.
-    ///
-    /// This uses an [`AccountCreator`](crate::account::AccountCreator) since it may need to build
-    /// the request multiple times in case the we get a `BadNonce` error.
-    pub fn register_account(
-        &mut self,
-        account: crate::account::AccountCreator,
-    ) -> Result<&Account, Error> {
-        let mut retry = retry();
-        let mut response = loop {
-            retry.tick()?;
-
-            let directory =
-                Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-            let nonce = Self::nonce(&mut self.inner, directory)?;
-            let request = account.request(directory, nonce)?;
-            match self.run_request(request) {
-                Ok(response) => break response,
-                Err(err) if err.is_bad_nonce() => continue,
-                Err(err) => return Err(err),
-            }
-        };
-
-        let account = account.response(response.location_required()?, response.bytes().as_ref())?;
-
-        self.account = Some(account);
-        Ok(self.account.as_ref().unwrap())
-    }
-
-    fn need_account(account: &Option<Account>) -> Result<&Account, Error> {
-        account
-            .as_ref()
-            .ok_or_else(|| format_err!("cannot use client without an account"))
-    }
-
-    /// Update account data.
-    ///
-    /// Low-level version: we allow arbitrary data to be passed to the remote here, it's up to the
-    /// user to know what to do for now.
-    pub fn update_account<T: Serialize>(&mut self, data: &T) -> Result<&Account, Error> {
-        let account = Self::need_account(&self.account)?;
-
-        let mut retry = retry();
-        let response = loop {
-            retry.tick()?;
-            let directory =
-                Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-            let nonce = Self::nonce(&mut self.inner, directory)?;
-            let request = account.post_request(&account.location, nonce, data)?;
-            let response = match self.inner.run_request(request) {
-                Ok(response) => response,
-                Err(err) if err.is_bad_nonce() => continue,
-                Err(err) => return Err(err),
-            };
-
-            break response;
-        };
-
-        // unwrap: we asserted we have an account at the top of the method!
-        let account = self.account.as_mut().unwrap();
-        account.data = response.json()?;
-        Ok(account)
-    }
-
-    /// Method to create a new order for a set of domains.
-    ///
-    /// Please remember to persist the order somewhere (ideally along with the account data) in
-    /// order to finish & query it later on.
-    pub fn new_order(&mut self, domains: Vec<String>) -> Result<Order, Error> {
-        let account = Self::need_account(&self.account)?;
-
-        let order = domains
-            .into_iter()
-            .fold(OrderData::new(), |order, domain| order.domain(domain));
-
-        let mut retry = retry();
-        loop {
-            retry.tick()?;
-
-            let directory =
-                Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-            let nonce = Self::nonce(&mut self.inner, directory)?;
-            let mut new_order = account.new_order(&order, directory, nonce)?;
-            let mut response = match self.inner.run_request(new_order.request.take().unwrap()) {
-                Ok(response) => response,
-                Err(err) if err.is_bad_nonce() => continue,
-                Err(err) => return Err(err),
-            };
-
-            return new_order.response(response.location_required()?, response.bytes().as_ref());
-        }
-    }
-
-    /// Assuming the provided URL is an 'Authorization' URL, get and deserialize it.
-    pub fn get_authorization(&mut self, url: &str) -> Result<Authorization, Error> {
-        self.post_as_get(url)?.json()
-    }
-
-    /// Assuming the provided URL is an 'Order' URL, get and deserialize it.
-    pub fn get_order(&mut self, url: &str) -> Result<OrderData, Error> {
-        self.post_as_get(url)?.json()
-    }
-
-    /// Low level "POST-as-GET" request.
-    pub fn post_as_get(&mut self, url: &str) -> Result<HttpResponse, Error> {
-        let account = Self::need_account(&self.account)?;
-
-        let mut retry = retry();
-        loop {
-            retry.tick()?;
-
-            let directory =
-                Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-            let nonce = Self::nonce(&mut self.inner, directory)?;
-            let request = account.get_request(url, nonce)?;
-            match self.inner.run_request(request) {
-                Ok(response) => return Ok(response),
-                Err(err) if err.is_bad_nonce() => continue,
-                Err(err) => return Err(err),
-            }
-        }
-    }
-
-    /// Low level POST request.
-    pub fn post<T: Serialize>(&mut self, url: &str, data: &T) -> Result<HttpResponse, Error> {
-        let account = Self::need_account(&self.account)?;
-
-        let mut retry = retry();
-        loop {
-            retry.tick()?;
-
-            let directory =
-                Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-            let nonce = Self::nonce(&mut self.inner, directory)?;
-            let request = account.post_request(url, nonce, data)?;
-            match self.inner.run_request(request) {
-                Ok(response) => return Ok(response),
-                Err(err) if err.is_bad_nonce() => continue,
-                Err(err) => return Err(err),
-            }
-        }
-    }
-
-    /// Request challenge validation. Afterwards, the challenge should be polled.
-    pub fn request_challenge_validation(&mut self, url: &str) -> Result<Challenge, Error> {
-        self.post(url, &serde_json::json!({}))?.json()
-    }
-
-    /// Shortcut to `account().ok_or_else(...).key_authorization()`.
-    pub fn key_authorization(&self, token: &str) -> Result<String, Error> {
-        Self::need_account(&self.account)?.key_authorization(token)
-    }
-
-    /// Shortcut to `account().ok_or_else(...).dns_01_txt_value()`.
-    /// the key authorization value.
-    pub fn dns_01_txt_value(&self, token: &str) -> Result<String, Error> {
-        Self::need_account(&self.account)?.dns_01_txt_value(token)
-    }
-
-    /// Low-level API to run an n API request. This automatically updates the current nonce!
-    pub fn run_request(&mut self, request: Request) -> Result<HttpResponse, Error> {
-        self.inner.run_request(request)
-    }
-
-    /// Finalize an Order via its `finalize` URL property and the DER encoded CSR.
-    pub fn finalize(&mut self, url: &str, csr: &[u8]) -> Result<(), Error> {
-        let csr = b64u::encode(csr);
-        let data = serde_json::json!({ "csr": csr });
-        self.post(url, &data)?;
-        Ok(())
-    }
-
-    /// Download a certificate via its 'certificate' URL property.
-    ///
-    /// The certificate will be a PEM certificate chain.
-    pub fn get_certificate(&mut self, url: &str) -> Result<Vec<u8>, Error> {
-        Ok(self.post_as_get(url)?.body)
-    }
-
-    /// Revoke an existing certificate (PEM or DER formatted).
-    pub fn revoke_certificate(
-        &mut self,
-        certificate: &[u8],
-        reason: Option<u32>,
-    ) -> Result<(), Error> {
-        // TODO: This can also work without an account.
-        let account = Self::need_account(&self.account)?;
-
-        let revocation = account.revoke_certificate(certificate, reason)?;
-
-        let mut retry = retry();
-        loop {
-            retry.tick()?;
-
-            let directory =
-                Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?;
-            let nonce = Self::nonce(&mut self.inner, directory)?;
-            let request = revocation.request(directory, nonce)?;
-            match self.inner.run_request(request) {
-                Ok(_response) => return Ok(()),
-                Err(err) if err.is_bad_nonce() => continue,
-                Err(err) => return Err(err),
-            }
-        }
-    }
-
-    /// Set a proxy
-    pub fn set_proxy(&mut self, proxy: String) {
-        self.inner.set_proxy(proxy)
-    }
-}
-
-/// bad nonce retry count helper
-struct Retry(usize);
-
-const fn retry() -> Retry {
-    Retry(0)
-}
-
-impl Retry {
-    fn tick(&mut self) -> Result<(), Error> {
-        if self.0 >= 3 {
-            bail!("kept getting a badNonce error!");
-        }
-        self.0 += 1;
-        Ok(())
-    }
-}
diff --git a/src/directory.rs b/src/directory.rs
deleted file mode 100644 (file)
index ed8203f..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-//! ACME Directory information.
-
-use serde::{Deserialize, Serialize};
-
-/// An ACME Directory. This contains the base URL and the directory data as received via a `GET`
-/// request to the URL.
-pub struct Directory {
-    /// The main entry point URL to the ACME directory.
-    pub url: String,
-
-    /// The json structure received via a `GET` request to the directory URL. This contains the
-    /// URLs for various API entry points.
-    pub data: DirectoryData,
-}
-
-/// The ACME Directory object structure.
-///
-/// The data in here is typically not relevant to the user of this crate.
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct DirectoryData {
-    /// The entry point to create a new account.
-    pub new_account: String,
-
-    /// The entry point to retrieve a new nonce, should be used with a `HEAD` request.
-    pub new_nonce: String,
-
-    /// URL to post new orders to.
-    pub new_order: String,
-
-    /// URL to use for certificate revocation.
-    pub revoke_cert: String,
-
-    /// Account key rollover URL.
-    pub key_change: String,
-
-    /// Metadata object, for additional information which aren't directly part of the API
-    /// itself, such as the terms of service.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub meta: Option<Meta>,
-}
-
-/// The directory's "meta" object.
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Meta {
-    /// The terms of service. This is typically in the form of an URL.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub terms_of_service: Option<String>,
-
-    /// Flag indicating if EAB is required, None is equivalent to false
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub external_account_required: Option<bool>,
-
-    /// Website with information about the ACME Server
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub website: Option<String>,
-
-    /// List of hostnames used by the CA, intended for the use with caa dns records
-    #[serde(default, skip_serializing_if = "Vec::is_empty")]
-    pub caa_identities: Vec<String>,
-}
-
-impl Directory {
-    /// Create a `Directory` given the parsed `DirectoryData` of a `GET` request to the directory
-    /// URL.
-    pub fn from_parts(url: String, data: DirectoryData) -> Self {
-        Self { url, data }
-    }
-
-    /// Get the ToS URL.
-    pub fn terms_of_service_url(&self) -> Option<&str> {
-        match &self.data.meta {
-            Some(meta) => meta.terms_of_service.as_deref(),
-            None => None,
-        }
-    }
-
-    /// Get if external account binding is required
-    pub fn external_account_binding_required(&self) -> bool {
-        matches!(
-            &self.data.meta,
-            Some(Meta {
-                external_account_required: Some(true),
-                ..
-            })
-        )
-    }
-
-    /// Get the "newNonce" URL. Use `HEAD` requests on this to get a new nonce.
-    pub fn new_nonce_url(&self) -> &str {
-        &self.data.new_nonce
-    }
-
-    pub(crate) fn new_account_url(&self) -> &str {
-        &self.data.new_account
-    }
-
-    pub(crate) fn new_order_url(&self) -> &str {
-        &self.data.new_order
-    }
-
-    /// Access to the in the Acme spec defined metadata structure.
-    pub fn meta(&self) -> Option<&Meta> {
-        self.data.meta.as_ref()
-    }
-}
diff --git a/src/eab.rs b/src/eab.rs
deleted file mode 100644 (file)
index a4c0642..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-use openssl::hash::MessageDigest;
-use openssl::pkey::{HasPrivate, PKeyRef};
-use openssl::sign::Signer;
-use serde::{Deserialize, Serialize};
-
-use crate::key::Jwk;
-use crate::{b64u, Error};
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-struct Protected {
-    alg: &'static str,
-    url: String,
-    kid: String,
-}
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-#[serde(rename_all = "camelCase")]
-pub struct ExternalAccountBinding {
-    protected: String,
-    payload: String,
-    signature: String,
-}
-
-impl ExternalAccountBinding {
-    pub fn new<P>(
-        eab_kid: &str,
-        eab_hmac_key: &PKeyRef<P>,
-        jwk: Jwk,
-        url: String,
-    ) -> Result<Self, Error>
-    where
-        P: HasPrivate,
-    {
-        let protected = Protected {
-            alg: "HS256",
-            kid: eab_kid.to_string(),
-            url,
-        };
-        let payload = b64u::encode(serde_json::to_string(&jwk)?.as_bytes());
-        let protected_data = b64u::encode(serde_json::to_string(&protected)?.as_bytes());
-        let signature = {
-            let protected = protected_data.as_bytes();
-            let payload = payload.as_bytes();
-            Self::sign_hmac(eab_hmac_key, protected, payload)?
-        };
-
-        let signature = b64u::encode(&signature);
-        Ok(ExternalAccountBinding {
-            protected: protected_data,
-            payload,
-            signature,
-        })
-    }
-
-    fn sign_hmac<P>(key: &PKeyRef<P>, protected: &[u8], payload: &[u8]) -> Result<Vec<u8>, Error>
-    where
-        P: HasPrivate,
-    {
-        let mut signer = Signer::new(MessageDigest::sha256(), key)?;
-        signer.update(protected)?;
-        signer.update(b".")?;
-        signer.update(payload)?;
-        Ok(signer.sign_to_vec()?)
-    }
-}
diff --git a/src/error.rs b/src/error.rs
deleted file mode 100644 (file)
index 59da3ea..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-//! The `Error` type and some ACME error constants for reference.
-
-use std::fmt;
-
-use openssl::error::ErrorStack as SslErrorStack;
-
-/// The ACME error string for a "bad nonce" error.
-pub const BAD_NONCE: &str = "urn:ietf:params:acme:error:badNonce";
-
-/// The ACME error string for a "user action required" error.
-pub const USER_ACTION_REQUIRED: &str = "urn:ietf:params:acme:error:userActionRequired";
-
-/// Error types returned by this crate.
-#[derive(Debug)]
-#[must_use = "unused errors have no effect"]
-pub enum Error {
-    /// A `badNonce` API response. The request should be retried with the new nonce received along
-    /// with this response.
-    BadNonce,
-
-    /// A `userActionRequired` API response. Typically this means there was a change to the ToS and
-    /// the user has to agree to the new terms.
-    UserActionRequired(String),
-
-    /// Other error repsonses from the Acme API not handled specially.
-    Api(crate::request::ErrorResponse),
-
-    /// The Acme API behaved unexpectedly.
-    InvalidApi(String),
-
-    /// Tried to use an `Account` or `AccountCreator` without a private key.
-    MissingKey,
-
-    /// Tried to create an `Account` without providing a single contact info.
-    MissingContactInfo,
-
-    /// Tried to use an empty `Order`.
-    EmptyOrder,
-
-    /// A raw `openssl::PKey` containing an unsupported key was passed.
-    UnsupportedKeyType,
-
-    /// A raw `openssl::PKey` or `openssl::EcKey` with an unsupported curve was passed.
-    UnsupportedGroup,
-
-    /// Failed to parse the account data returned by the API upon account creation.
-    BadAccountData(String),
-
-    /// Failed to  parse the order data returned by the API from a new-order request.
-    BadOrderData(String),
-
-    /// An openssl error occurred during a crypto operation.
-    RawSsl(SslErrorStack),
-
-    /// An openssl error occurred during a crypto operation.
-    /// With some textual context.
-    Ssl(&'static str, SslErrorStack),
-
-    /// An otherwise uncaught serde error happened.
-    Json(serde_json::Error),
-
-    /// Failed to parse
-    BadBase64(base64::DecodeError),
-
-    /// Can be used by the user for textual error messages without having to downcast to regular
-    /// acme errors.
-    Custom(String),
-
-    /// If built with the `client` feature, this is where general ureq/network errors end up.
-    /// This is usually a `ureq::Error`, however in order to provide an API which is not
-    /// feature-dependent, this variant is always present and contains a boxed `dyn Error`.
-    HttpClient(Box<dyn std::error::Error + Send + Sync + 'static>),
-
-    /// If built with the `client` feature, this is where client specific errors which are not from
-    /// errors forwarded from `ureq` end up.
-    Client(String),
-
-    /// A non-openssl error occurred while building data for the CSR.
-    Csr(String),
-}
-
-impl Error {
-    /// Create an `Error` from a custom text.
-    pub fn custom<T: std::fmt::Display>(s: T) -> Self {
-        Error::Custom(s.to_string())
-    }
-
-    /// Convenience method to check if this error represents a bad nonce error in which case the
-    /// request needs to be re-created using a new nonce.
-    pub fn is_bad_nonce(&self) -> bool {
-        matches!(self, Error::BadNonce)
-    }
-}
-
-impl std::error::Error for Error {}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::Api(err) => match err.detail.as_deref() {
-                Some(detail) => write!(f, "{}: {}", err.ty, detail),
-                None => fmt::Display::fmt(&err.ty, f),
-            },
-            Error::InvalidApi(err) => write!(f, "Acme Server API misbehaved: {}", err),
-            Error::BadNonce => f.write_str("bad nonce, please retry with a new nonce"),
-            Error::UserActionRequired(err) => write!(f, "user action required: {}", err),
-            Error::MissingKey => f.write_str("cannot build an account without a key"),
-            Error::MissingContactInfo => f.write_str("account requires contact info"),
-            Error::EmptyOrder => f.write_str("cannot make an empty order"),
-            Error::UnsupportedKeyType => f.write_str("unsupported key type"),
-            Error::UnsupportedGroup => f.write_str("unsupported EC group"),
-            Error::BadAccountData(err) => {
-                write!(f, "bad response to account query or creation: {}", err)
-            }
-            Error::BadOrderData(err) => {
-                write!(f, "bad response to new-order query or creation: {}", err)
-            }
-            Error::RawSsl(err) => fmt::Display::fmt(err, f),
-            Error::Ssl(context, err) => {
-                write!(f, "{}: {}", context, err)
-            }
-            Error::Json(err) => fmt::Display::fmt(err, f),
-            Error::Custom(err) => fmt::Display::fmt(err, f),
-            Error::HttpClient(err) => fmt::Display::fmt(err, f),
-            Error::Client(err) => fmt::Display::fmt(err, f),
-            Error::Csr(err) => fmt::Display::fmt(err, f),
-            Error::BadBase64(err) => fmt::Display::fmt(err, f),
-        }
-    }
-}
-
-impl From<SslErrorStack> for Error {
-    fn from(e: SslErrorStack) -> Self {
-        Error::RawSsl(e)
-    }
-}
-
-impl From<serde_json::Error> for Error {
-    fn from(e: serde_json::Error) -> Self {
-        Error::Json(e)
-    }
-}
-
-impl From<crate::request::ErrorResponse> for Error {
-    fn from(e: crate::request::ErrorResponse) -> Self {
-        Error::Api(e)
-    }
-}
-
-impl From<base64::DecodeError> for Error {
-    fn from(e: base64::DecodeError) -> Self {
-        Error::BadBase64(e)
-    }
-}
diff --git a/src/json.rs b/src/json.rs
deleted file mode 100644 (file)
index e192d67..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-use openssl::hash::Hasher;
-use serde_json::Value;
-
-use crate::Error;
-
-pub fn to_hash_canonical(value: &Value, output: &mut Hasher) -> Result<(), Error> {
-    match value {
-        Value::Null | Value::String(_) | Value::Number(_) | Value::Bool(_) => {
-            serde_json::to_writer(output, &value)?;
-        }
-        Value::Array(list) => {
-            output.update(b"[")?;
-            let mut iter = list.iter();
-            if let Some(item) = iter.next() {
-                to_hash_canonical(item, output)?;
-                for item in iter {
-                    output.update(b",")?;
-                    to_hash_canonical(item, output)?;
-                }
-            }
-            output.update(b"]")?;
-        }
-        Value::Object(map) => {
-            output.update(b"{")?;
-            let mut keys: Vec<&str> = map.keys().map(String::as_str).collect();
-            keys.sort_unstable();
-            let mut iter = keys.into_iter();
-            if let Some(key) = iter.next() {
-                serde_json::to_writer(&mut *output, &key)?;
-                output.update(b":")?;
-                to_hash_canonical(&map[key], output)?;
-                for key in iter {
-                    output.update(b",")?;
-                    serde_json::to_writer(&mut *output, &key)?;
-                    output.update(b":")?;
-                    to_hash_canonical(&map[key], output)?;
-                }
-            }
-            output.update(b"}")?;
-        }
-    }
-    Ok(())
-}
diff --git a/src/jws.rs b/src/jws.rs
deleted file mode 100644 (file)
index b867f71..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-use std::convert::TryFrom;
-
-use openssl::hash::{Hasher, MessageDigest};
-use openssl::pkey::{HasPrivate, PKeyRef};
-use openssl::sign::Signer;
-use serde::Serialize;
-
-use crate::b64u;
-use crate::key::{Jwk, PublicKey};
-use crate::Error;
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Protected {
-    alg: &'static str,
-    nonce: String,
-    url: String,
-    #[serde(flatten)]
-    key: KeyId,
-}
-
-/// Acme requires to the use of *either* `jwk` *or* `kid` depending on the action taken.
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub enum KeyId {
-    /// This is the actual JWK structure.
-    Jwk(Jwk),
-
-    /// This should be the account location.
-    Kid(String),
-}
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Jws {
-    protected: String,
-    payload: String,
-    signature: String,
-}
-
-impl Jws {
-    pub fn new<P, T>(
-        key: &PKeyRef<P>,
-        location: Option<String>,
-        url: String,
-        nonce: String,
-        payload: &T,
-    ) -> Result<Self, Error>
-    where
-        P: HasPrivate,
-        T: Serialize,
-    {
-        Self::new_full(
-            key,
-            location,
-            url,
-            nonce,
-            b64u::encode(serde_json::to_string(payload)?.as_bytes()),
-        )
-    }
-
-    pub fn new_full<P: HasPrivate>(
-        key: &PKeyRef<P>,
-        location: Option<String>,
-        url: String,
-        nonce: String,
-        payload: String,
-    ) -> Result<Self, Error> {
-        let jwk = Jwk::try_from(key)?;
-
-        let pubkey = jwk.key.clone();
-        let mut protected = Protected {
-            alg: "",
-            nonce,
-            url,
-            key: match location {
-                Some(location) => KeyId::Kid(location),
-                None => KeyId::Jwk(jwk),
-            },
-        };
-
-        let (digest, ec_order_bytes): (MessageDigest, usize) = match &pubkey {
-            PublicKey::Rsa(_) => (Self::prepare_rsa(key, &mut protected), 0),
-            PublicKey::Ec(_) => Self::prepare_ec(key, &mut protected),
-        };
-
-        let protected_data = b64u::encode(serde_json::to_string(&protected)?.as_bytes());
-
-        let signature = {
-            let prot = protected_data.as_bytes();
-            let payload = payload.as_bytes();
-            match &pubkey {
-                PublicKey::Rsa(_) => Self::sign_rsa(key, digest, prot, payload),
-                PublicKey::Ec(_) => Self::sign_ec(key, digest, ec_order_bytes, prot, payload),
-            }?
-        };
-
-        let signature = b64u::encode(&signature);
-
-        Ok(Jws {
-            protected: protected_data,
-            payload,
-            signature,
-        })
-    }
-
-    fn prepare_rsa<P>(_key: &PKeyRef<P>, protected: &mut Protected) -> MessageDigest
-    where
-        P: HasPrivate,
-    {
-        protected.alg = "RS256";
-        MessageDigest::sha256()
-    }
-
-    /// Returns the digest and the size of the two signature components 'r' and 's'.
-    fn prepare_ec<P>(_key: &PKeyRef<P>, protected: &mut Protected) -> (MessageDigest, usize)
-    where
-        P: HasPrivate,
-    {
-        // Note: if we support >256 bit keys we'll want to also support using ES512 here probably
-        protected.alg = "ES256";
-        //  'r' and 's' are each 256 bit numbers:
-        (MessageDigest::sha256(), 32)
-    }
-
-    fn sign_rsa<P>(
-        key: &PKeyRef<P>,
-        digest: MessageDigest,
-        protected: &[u8],
-        payload: &[u8],
-    ) -> Result<Vec<u8>, Error>
-    where
-        P: HasPrivate,
-    {
-        let mut signer = Signer::new(digest, key)?;
-        signer.set_rsa_padding(openssl::rsa::Padding::PKCS1)?;
-        signer.update(protected)?;
-        signer.update(b".")?;
-        signer.update(payload)?;
-        Ok(signer.sign_to_vec()?)
-    }
-
-    fn sign_ec<P>(
-        key: &PKeyRef<P>,
-        digest: MessageDigest,
-        ec_order_bytes: usize,
-        protected: &[u8],
-        payload: &[u8],
-    ) -> Result<Vec<u8>, Error>
-    where
-        P: HasPrivate,
-    {
-        let mut hasher = Hasher::new(digest)?;
-        hasher.update(protected)?;
-        hasher.update(b".")?;
-        hasher.update(payload)?;
-        let sig =
-            openssl::ecdsa::EcdsaSig::sign(hasher.finish()?.as_ref(), key.ec_key()?.as_ref())?;
-        let r = sig.r().to_vec();
-        let s = sig.s().to_vec();
-        let mut out = Vec::with_capacity(ec_order_bytes * 2);
-        out.extend(std::iter::repeat(0u8).take(ec_order_bytes - r.len()));
-        out.extend(r);
-        out.extend(std::iter::repeat(0u8).take(ec_order_bytes - s.len()));
-        out.extend(s);
-        Ok(out)
-    }
-}
diff --git a/src/key.rs b/src/key.rs
deleted file mode 100644 (file)
index 5dbc546..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-use std::convert::{TryFrom, TryInto};
-
-use openssl::hash::{Hasher, MessageDigest};
-use openssl::pkey::{HasPublic, Id, PKeyRef};
-use serde::Serialize;
-
-use crate::b64u;
-use crate::Error;
-
-/// An RSA public key.
-#[derive(Clone, Debug, Serialize)]
-#[serde(deny_unknown_fields)]
-pub struct RsaPublicKey {
-    #[serde(with = "b64u::bytes")]
-    e: Vec<u8>,
-    #[serde(with = "b64u::bytes")]
-    n: Vec<u8>,
-}
-
-/// An EC public key.
-#[derive(Clone, Debug, Serialize)]
-#[serde(deny_unknown_fields)]
-pub struct EcPublicKey {
-    crv: &'static str,
-    #[serde(with = "b64u::bytes")]
-    x: Vec<u8>,
-    #[serde(with = "b64u::bytes")]
-    y: Vec<u8>,
-}
-
-/// A public key.
-///
-/// Internally tagged, so this already contains the 'kty' member.
-#[derive(Clone, Debug, Serialize)]
-#[serde(tag = "kty")]
-pub enum PublicKey {
-    #[serde(rename = "RSA")]
-    Rsa(RsaPublicKey),
-    #[serde(rename = "EC")]
-    Ec(EcPublicKey),
-}
-
-impl PublicKey {
-    /// The thumbprint is the b64u encoded sha256sum of the *canonical* json representation.
-    pub fn thumbprint(&self) -> Result<String, Error> {
-        let mut hasher = Hasher::new(MessageDigest::sha256())?;
-        crate::json::to_hash_canonical(&serde_json::to_value(self)?, &mut hasher)?;
-        Ok(b64u::encode(hasher.finish()?.as_ref()))
-    }
-}
-
-#[derive(Clone, Debug, Serialize)]
-pub struct Jwk {
-    #[serde(rename = "use", skip_serializing_if = "Option::is_none")]
-    pub usage: Option<String>,
-
-    /// The key data is internally tagged, we can just flatten it.
-    #[serde(flatten)]
-    pub key: PublicKey,
-}
-
-impl<P: HasPublic> TryFrom<&PKeyRef<P>> for Jwk {
-    type Error = Error;
-
-    fn try_from(key: &PKeyRef<P>) -> Result<Self, Self::Error> {
-        Ok(Self {
-            key: key.try_into()?,
-            usage: None,
-        })
-    }
-}
-
-impl<P: HasPublic> TryFrom<&PKeyRef<P>> for PublicKey {
-    type Error = Error;
-
-    fn try_from(key: &PKeyRef<P>) -> Result<Self, Self::Error> {
-        match key.id() {
-            Id::RSA => Ok(PublicKey::Rsa(RsaPublicKey::try_from(&key.rsa()?)?)),
-            Id::EC => Ok(PublicKey::Ec(EcPublicKey::try_from(&key.ec_key()?)?)),
-            _ => Err(Error::UnsupportedKeyType),
-        }
-    }
-}
-
-impl<P: HasPublic> TryFrom<&openssl::rsa::Rsa<P>> for RsaPublicKey {
-    type Error = Error;
-
-    fn try_from(key: &openssl::rsa::Rsa<P>) -> Result<Self, Self::Error> {
-        Ok(RsaPublicKey {
-            e: key.e().to_vec(),
-            n: key.n().to_vec(),
-        })
-    }
-}
-
-impl<P: HasPublic> TryFrom<&openssl::ec::EcKey<P>> for EcPublicKey {
-    type Error = Error;
-
-    fn try_from(key: &openssl::ec::EcKey<P>) -> Result<Self, Self::Error> {
-        let group = key.group();
-
-        if group.curve_name() != Some(openssl::nid::Nid::X9_62_PRIME256V1) {
-            return Err(Error::UnsupportedGroup);
-        }
-
-        let mut ctx = openssl::bn::BigNumContext::new()?;
-        let mut x = openssl::bn::BigNum::new()?;
-        let mut y = openssl::bn::BigNum::new()?;
-        key.public_key()
-            .affine_coordinates(group, &mut x, &mut y, &mut ctx)?;
-
-        Ok(EcPublicKey {
-            crv: "P-256",
-            x: x.to_vec(),
-            y: y.to_vec(),
-        })
-    }
-}
-
-#[test]
-fn test_key_conversion() -> Result<(), Error> {
-    let key = openssl::ec::EcKey::generate(
-        openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1)?.as_ref(),
-    )?;
-
-    let _ = EcPublicKey::try_from(&key).expect("failed to jsonify ec key");
-
-    Ok(())
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644 (file)
index 98ad04e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-//! ACME protocol helper.
-//!
-//! This is supposed to implement the low level parts of the ACME protocol, providing an [`Account`]
-//! and some other helper types which allow interacting with an ACME server by implementing methods
-//! which create [`Request`]s the user can then combine with a nonce and send to the the ACME
-//! server using whatever http client they choose.
-//!
-//! This is a rather low level crate, and while it provides an optional synchronous client using
-//! curl (for simplicity), users should have basic understanding of the ACME API in order to
-//! implement a client using this.
-//!
-//! The [`Account`] helper supports RSA and ECC keys and provides most of the API methods.
-
-#![deny(missing_docs)]
-
-mod b64u;
-mod eab;
-mod json;
-mod jws;
-mod key;
-mod request;
-
-pub mod account;
-pub mod authorization;
-pub mod directory;
-pub mod error;
-pub mod order;
-pub mod util;
-
-#[doc(inline)]
-pub use account::Account;
-
-#[doc(inline)]
-pub use authorization::{Authorization, Challenge};
-
-#[doc(inline)]
-pub use directory::Directory;
-
-#[doc(inline)]
-pub use error::Error;
-
-#[doc(inline)]
-pub use order::Order;
-
-#[doc(inline)]
-pub use request::Request;
-
-// we don't inline these:
-pub use order::NewOrder;
-pub use request::ErrorResponse;
-
-/// Header name for nonces.
-pub const REPLAY_NONCE: &str = "Replay-Nonce";
-
-/// Header name for locations.
-pub const LOCATION: &str = "Location";
-
-#[cfg(feature = "client")]
-pub mod client;
-#[cfg(feature = "client")]
-pub use client::Client;
diff --git a/src/order.rs b/src/order.rs
deleted file mode 100644 (file)
index 404d4ae..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-//! ACME Orders data and identifiers.
-
-use serde::{Deserialize, Serialize};
-use serde_json::Value;
-
-use crate::request::Request;
-use crate::Error;
-
-/// Status of an [`Order`].
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum Status {
-    /// Invalid, used as a place holder for when sending objects as contrary to account creation,
-    /// the Acme RFC does not require the server to ignore unknown parts of the `Order` object.
-    New,
-
-    /// Authorization failed and it is now invalid.
-    Invalid,
-
-    /// The authorization is pending and the user should look through its challenges.
-    ///
-    /// This is the initial state of a new authorization.
-    Pending,
-
-    /// The ACME provider is processing an authorization validation.
-    Processing,
-
-    /// The requirements for the order have been met and it may be finalized.
-    Ready,
-
-    /// The certificate has been issued and can be downloaded from the URL provided in the
-    /// [`Order`]'s `certificate` field.
-    Valid,
-}
-
-impl Default for Status {
-    fn default() -> Self {
-        Status::New
-    }
-}
-
-impl Status {
-    /// Serde helper
-    fn is_new(&self) -> bool {
-        *self == Status::New
-    }
-
-    /// Convenience method to check if the status is 'pending'.
-    #[inline]
-    pub fn is_pending(self) -> bool {
-        self == Status::Pending
-    }
-
-    /// Convenience method to check if the status is 'valid'.
-    #[inline]
-    pub fn is_valid(self) -> bool {
-        self == Status::Valid
-    }
-}
-
-/// An identifier used for a certificate request.
-///
-/// Currently only supports DNS name identifiers.
-#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
-#[serde(tag = "type", content = "value", rename_all = "lowercase")]
-pub enum Identifier {
-    /// A DNS identifier is used to request a domain name to be added to a certificate.
-    Dns(String),
-}
-
-/// This contains the order data sent to and received from the ACME server.
-///
-/// This is typically filled with a set of domains and then issued as a new-order request via [`Account::new_order`](crate::Account::new_order).
-#[derive(Clone, Debug, Default, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct OrderData {
-    /// The order status.
-    #[serde(skip_serializing_if = "Status::is_new", default)]
-    pub status: Status,
-
-    /// This order's expiration date as RFC3339 formatted time string.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub expires: Option<String>,
-
-    /// List of identifiers to order for the certificate.
-    pub identifiers: Vec<Identifier>,
-
-    /// An RFC3339 formatted time string. It is up to the user to choose a dev dependency for this
-    /// shit.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub not_before: Option<String>,
-
-    /// An RFC3339 formatted time string. It is up to the user to choose a dev dependency for this
-    /// shit.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub not_after: Option<String>,
-
-    /// Possible errors in this order.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub error: Option<Value>,
-
-    /// List of URL's to authorizations the client needs to complete.
-    #[serde(skip_serializing_if = "Vec::is_empty")]
-    pub authorizations: Vec<String>,
-
-    /// URL the final CSR needs to be POSTed to in order to complete the order, once all
-    /// authorizations have been performed.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub finalize: Option<String>,
-
-    /// URL at which the issued certificate can be fetched once it is available.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub certificate: Option<String>,
-}
-
-impl OrderData {
-    /// Initialize an empty order object.
-    pub fn new() -> Self {
-        Default::default()
-    }
-
-    /// Builder-style method to add a domain identifier to the data.
-    pub fn domain(mut self, domain: String) -> Self {
-        self.identifiers.push(Identifier::Dns(domain));
-        self
-    }
-}
-
-/// Represents an order for a new certificate. This combines the order's own location (URL) with
-/// the [`OrderData`] received from the ACME server.
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Order {
-    /// Order location URL.
-    pub location: String,
-
-    /// The order's data object.
-    pub data: OrderData,
-}
-
-impl Order {
-    /// Get an authorization URL (or `None` if the index is out of range).
-    pub fn authorization(&self, index: usize) -> Option<&str> {
-        Some(self.data.authorizations.get(index)?)
-    }
-
-    /// Get the number of authorizations in this object.
-    pub fn authorization_len(&self) -> usize {
-        self.data.authorizations.len()
-    }
-}
-
-/// Represents a new in-flight order creation.
-///
-/// This is created via [`Account::new_order`](crate::Account::new_order()).
-pub struct NewOrder {
-    //order: OrderData,
-    /// The request to execute to place the order. When creating a [`NewOrder`] via
-    /// [`Account::new_order`](crate::Account::new_order) this is guaranteed to be `Some`.
-    pub request: Option<Request>,
-}
-
-impl NewOrder {
-    pub(crate) fn new(request: Request) -> Self {
-        Self {
-            //order,
-            request: Some(request),
-        }
-    }
-
-    /// Deal with the response we got from the server.
-    pub fn response(self, location_header: String, response_body: &[u8]) -> Result<Order, Error> {
-        Ok(Order {
-            location: location_header,
-            data: serde_json::from_slice(response_body)
-                .map_err(|err| Error::BadOrderData(err.to_string()))?,
-        })
-    }
-}
diff --git a/src/request.rs b/src/request.rs
deleted file mode 100644 (file)
index 78a9091..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-use serde::Deserialize;
-
-pub(crate) const JSON_CONTENT_TYPE: &str = "application/jose+json";
-pub(crate) const CREATED: u16 = 201;
-
-/// A request which should be performed on the ACME provider.
-pub struct Request {
-    /// The complete URL to send the request to.
-    pub url: String,
-
-    /// The HTTP method name to use.
-    pub method: &'static str,
-
-    /// The `Content-Type` header to pass along.
-    pub content_type: &'static str,
-
-    /// The body to pass along with request, or an empty string.
-    pub body: String,
-
-    /// The expected status code a compliant ACME provider will return on success.
-    pub expected: u16,
-}
-
-/// An ACME error response contains a specially formatted type string, and can optionally
-/// contain textual details and a set of sub problems.
-#[derive(Clone, Debug, Deserialize)]
-pub struct ErrorResponse {
-    /// The ACME error type string.
-    ///
-    /// Most of the time we're only interested in the "bad nonce" or "user action required"
-    /// errors. When an [`Error`](crate::Error) is built from this error response, it will map
-    /// to the corresponding enum values (eg. [`Error::BadNonce`](crate::Error::BadNonce)).
-    #[serde(rename = "type")]
-    pub ty: String,
-
-    /// A textual detail string optionally provided by the ACME provider to inform the user more
-    /// verbosely about why the error occurred.
-    pub detail: Option<String>,
-
-    /// Additional json data containing information as to why the error occurred.
-    pub subproblems: Option<serde_json::Value>,
-}
diff --git a/src/util.rs b/src/util.rs
deleted file mode 100644 (file)
index 57acf85..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-//! Certificate utility methods for convenience (such as CSR generation).
-
-use std::collections::HashMap;
-
-use openssl::hash::MessageDigest;
-use openssl::nid::Nid;
-use openssl::pkey::PKey;
-use openssl::rsa::Rsa;
-use openssl::x509::{self, X509Name, X509Req};
-
-use crate::Error;
-
-/// A certificate signing request.
-pub struct Csr {
-    /// DER encoded certificate request.
-    pub data: Vec<u8>,
-
-    /// PEM formatted PKCS#8 private key.
-    pub private_key_pem: Vec<u8>,
-}
-
-impl Csr {
-    /// Generate a CSR in DER format with a PEM formatted PKCS8 private key.
-    ///
-    /// The `identifiers` should be a list of domains. The `attributes` should have standard names
-    /// recognized by openssl.
-    pub fn generate(
-        identifiers: &[impl AsRef<str>],
-        attributes: &HashMap<String, &str>,
-    ) -> Result<Self, Error> {
-        if identifiers.is_empty() {
-            return Err(Error::Csr("cannot generate empty CSR".to_string()));
-        }
-
-        let private_key = Rsa::generate(4096)
-            .and_then(PKey::from_rsa)
-            .map_err(|err| Error::Ssl("failed to generate RSA key: {}", err))?;
-
-        let private_key_pem = private_key
-            .private_key_to_pem_pkcs8()
-            .map_err(|err| Error::Ssl("failed to format private key as PEM pkcs8: {}", err))?;
-
-        let mut name = X509Name::builder()?;
-        if !attributes.contains_key("CN") {
-            name.append_entry_by_nid(Nid::COMMONNAME, identifiers[0].as_ref())?;
-        }
-        for (key, value) in attributes {
-            name.append_entry_by_text(key, value)?;
-        }
-        let name = name.build();
-
-        let mut csr = X509Req::builder()?;
-        csr.set_subject_name(&name)?;
-        csr.set_pubkey(&private_key)?;
-
-        let context = csr.x509v3_context(None);
-        let mut ext = openssl::stack::Stack::new()?;
-        ext.push(x509::extension::BasicConstraints::new().build()?)?;
-        ext.push(
-            x509::extension::KeyUsage::new()
-                .digital_signature()
-                .key_encipherment()
-                .build()?,
-        )?;
-        ext.push(
-            x509::extension::ExtendedKeyUsage::new()
-                .server_auth()
-                .client_auth()
-                .build()?,
-        )?;
-        let mut san = x509::extension::SubjectAlternativeName::new();
-        for dns in identifiers {
-            san.dns(dns.as_ref());
-        }
-        ext.push({ san }.build(&context)?)?;
-        csr.add_extensions(&ext)?;
-
-        csr.sign(&private_key, MessageDigest::sha256())?;
-
-        Ok(Self {
-            data: csr.build().to_der()?,
-            private_key_pem,
-        })
-    }
-}