Skip to content

Commit

Permalink
Switch from base64 to base64ct
Browse files Browse the repository at this point in the history
  • Loading branch information
tgross35 committed Nov 4, 2023
1 parent 6524683 commit 05e166c
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 43 deletions.
21 changes: 6 additions & 15 deletions .github/workflows/validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,15 @@ jobs:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-features --all-targets -- -D warnings
env:
TEST_TANG_URL: '' # just for validation
- run: cargo clippy --no-default-features --all-targets -- -D warnings

test:
strategy:
fail-fast: true
matrix:
# os: [ubuntu-latest]
include:
- build: linux
os: ubuntu-latest
target: x86_64-unknown-linux-musl
# - build: macos
# os: macos-latest
# target: x86_64-apple-darwin
# extension: ''
- build: windows-msvc
os: windows-latest
target: x86_64-pc-windows-msvc

os: [ubuntu-latest, macos-latest, windows-msvc]
name: "Test on ${{ matrix.os }} (cargo test)"
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -66,9 +56,10 @@ jobs:
--name tang-backend
padhihomelab/tang
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Run integration testing
env:
TEST_TANG_URL: localost:11697
TEST_TANG_URL: localhost:11697
# Run only integration tests with `--test '*'`
run: cargo test --test '*' --features _backend
- name: Print docker logs
Expand Down Expand Up @@ -102,11 +93,11 @@ jobs:
outdated:
name: Outdated
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/install@cargo-outdated
- uses: Swatinem/rust-cache@v2
- run: cargo outdated --workspace --exit-code 1

security_audit:
Expand Down
17 changes: 10 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ name = "clevis"
path = "src/main.rs"

[dependencies]
base64 = "0.21.0"
clap = { version = "4.2.1", features = ["derive"] }
clap = { version = "4.4.7", features = ["derive"] }
env_logger = "0.10.0"
josekit = "0.8.2"
josekit = "0.8.4"
log = "0.4.20"
serde = "1.0.160"
sha2 = "0.10.6"
serde_json = { version = "1.0.95", features = ["preserve_order"] }
ureq = { version = "2.6.2", features = ["json"] }
serde = "1.0.190"
sha2 = "0.10.8"
serde_json = { version = "1.0.108", features = ["preserve_order"] }
ureq = { version = "2.8.0", features = ["json"] }
sha1 = "0.10.6"
hex = "0.4.3"
p521 = { git = "https://github.com/RustCrypto/elliptic-curves.git" }
p256 = { git = "https://github.com/RustCrypto/elliptic-curves.git" }
base64ct = { version = "1.6.0", features = ["alloc"] }

# vsss-rs = "2.7.1"

[features]
Expand Down
10 changes: 5 additions & 5 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ pub type Result<T, E = Error> = core::result::Result<T, E>;

#[derive(Debug)]
pub enum Error {
Server(ureq::Error),
Server(Box<ureq::Error>),
Algorithm(Box<str>, &'static str),
IoError(io::Error),
MissingKeyOp(Box<str>),
JsonMissingKey(Box<str>),
JsonKeyType(Box<str>),
Utf8(Utf8Error),
Base64(base64::DecodeError),
Base64(base64ct::Error),
Json(serde_json::Error),
Jose(josekit::JoseError),
VerifyKey,
Expand All @@ -33,7 +33,7 @@ impl fmt::Display for Error {

impl From<ureq::Error> for Error {
fn from(value: ureq::Error) -> Self {
Error::Server(value)
Error::Server(value.into())
}
}

Expand All @@ -49,8 +49,8 @@ impl From<Utf8Error> for Error {
}
}

impl From<base64::DecodeError> for Error {
fn from(value: base64::DecodeError) -> Self {
impl From<base64ct::Error> for Error {
fn from(value: base64ct::Error) -> Self {
Self::Base64(value)
}
}
Expand Down
33 changes: 23 additions & 10 deletions src/jose.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::key_exchange::create_encryption_key;
use crate::util::{b64_to_bytes, b64_to_str};
use crate::{Error, Result};
use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
use base64ct::{Base64UrlUnpadded, Encoding};
use josekit::jwe::alg::ecdh_es::EcdhEsJweAlgorithm;
use josekit::jwe::{self, JweHeader};
use josekit::jwk::Jwk;
Expand All @@ -17,6 +17,8 @@ use std::ops::Deref;
use std::{sync::OnceLock, time::Duration};

/// Representation of a tang advertisment response which is a JWS of available keys.
///
/// This is what is produced when you GET `tang_url/adv`.
#[derive(Deserialize)]
pub struct Advertisment {
#[serde(deserialize_with = "b64_to_str")]
Expand All @@ -34,16 +36,24 @@ impl Advertisment {
let verifier = get_verifier(verify_jwk)?;

// B64 is 4/3 data length, plus a `.`
let verify_len = ((self.payload.len() + self.protected.len()) * 4 / 3) + 1;
let mut to_verify = String::with_capacity(verify_len);
let payload_b64_len = Base64UrlUnpadded::encoded_len(self.payload.as_bytes());
let protected_b64_len = Base64UrlUnpadded::encoded_len(self.protected.as_bytes());
let mut to_verify = vec![b'.'; payload_b64_len + 1 + protected_b64_len];

// The format `b64(HEADER).b64(PAYLOAD)` is used for validation
BASE64_URL_SAFE_NO_PAD.encode_string(&self.protected, &mut to_verify);
to_verify.push('.');
BASE64_URL_SAFE_NO_PAD.encode_string(&self.payload, &mut to_verify);
Base64UrlUnpadded::encode(
self.protected.as_bytes(),
&mut to_verify[..protected_b64_len],
)
.unwrap();
Base64UrlUnpadded::encode(
self.payload.as_bytes(),
&mut to_verify[(protected_b64_len + 1)..],
)
.unwrap();

verifier
.verify(to_verify.as_bytes(), &self.signature)
.verify(&to_verify, &self.signature)
.map_err(Into::into)
}

Expand All @@ -67,7 +77,10 @@ impl fmt::Debug for Advertisment {
f.debug_struct("Advertisment")
.field("payload", &json_field(&self.payload))
.field("protected", &json_field(&self.protected))
.field("signature", &BASE64_URL_SAFE_NO_PAD.encode(&self.signature))
.field(
"signature",
&Base64UrlUnpadded::encode_string(&self.signature),
)
.finish()
}
}
Expand Down Expand Up @@ -220,12 +233,12 @@ fn make_thumbprint(jwk: &Jwk, alg: ThpHashAlg) -> Result<String> {
ThpHashAlg::Sha1 => {
let mut hasher = sha1::Sha1::new();
hasher.update(to_hash.as_bytes());
Ok(BASE64_URL_SAFE_NO_PAD.encode(hasher.finalize()))
Ok(Base64UrlUnpadded::encode_string(&hasher.finalize()))
}
ThpHashAlg::Sha256 => {
let mut hasher = Sha256::new();
hasher.update(to_hash.as_bytes());
Ok(BASE64_URL_SAFE_NO_PAD.encode(hasher.finalize()))
Ok(Base64UrlUnpadded::encode_string(&hasher.finalize()))
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/tang_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{sync::OnceLock, time::Duration};
use crate::jose::{Advertisment, JwkSet};
use crate::util::{b64_to_bytes, b64_to_str};
use crate::{Error, Result};
use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
use base64ct::{Base64UrlUnpadded, Encoding};
use josekit::jwk::Jwk;
use josekit::jws::alg::ecdsa::EcdsaJwsAlgorithm;
use josekit::jws::alg::eddsa::EddsaJwsAlgorithm;
Expand All @@ -16,6 +16,7 @@ use serde_json::{json, Value};
const DEFAULT_URL: &str = "http://tang.local";
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(120);

/// A tang server connection specification
#[derive(Clone, Debug)]
pub struct TangClient {
url: String,
Expand Down
7 changes: 2 additions & 5 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::collections::BTreeMap;

use base64::prelude::BASE64_URL_SAFE_NO_PAD;
use base64::{prelude::BASE64_STANDARD_NO_PAD, Engine};
use base64ct::{Base64UrlUnpadded, Encoding};
use serde::de::Error as DeError;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::{Map, Value as JsonValue};
Expand All @@ -20,8 +19,6 @@ where
D: Deserializer<'de>,
{
String::deserialize(deserializer).and_then(|string| {
BASE64_URL_SAFE_NO_PAD
.decode(&string)
.map_err(|err| DeError::custom(dbg!(err.to_string())))
Base64UrlUnpadded::decode_vec(&string).map_err(|err| DeError::custom(err.to_string()))
})
}

0 comments on commit 05e166c

Please sign in to comment.