Skip to content
This repository was archived by the owner on Feb 11, 2025. It is now read-only.

Commit 7672acf

Browse files
Merge pull request #368 from rvolosatovs/update/dalek
build: update `ed25519-dalek` and `base64`
2 parents 175db03 + 90373bd commit 7672acf

File tree

10 files changed

+220
-231
lines changed

10 files changed

+220
-231
lines changed

Cargo.lock

Lines changed: 125 additions & 172 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ anyhow = "1.0.44"
4747
async-compression = { version = "0.3", default-features = false, features = ["tokio", "gzip"], optional = true }
4848
async-trait = "0.1.51"
4949
atty = { version = "0.2", optional = true }
50-
base64 = "0.13.0"
50+
base64 = "0.21"
5151
bcrypt = "0.13"
5252
bytes = "1.1.0"
53-
clap = { version = "3", features = ["derive", "env", "cargo"], optional = true }
53+
clap = { workspace = true, features = ["derive", "env", "cargo"], optional = true }
5454
dirs = { version = "4.0.0", optional = true }
55-
ed25519-dalek = "1.0.1"
55+
ed25519-dalek = { version = "2", features = ["pkcs8", "rand_core"] }
5656
either = { version = "1.6.1", optional = true }
5757
futures = "0.3.17"
5858
hyper = { version = "0.14.12", optional = true }
@@ -62,8 +62,7 @@ mime = { version = "0.3.16", optional = true }
6262
mime_guess = { version = "2.0.3", optional = true }
6363
oauth2 = { version = "4.1.0", features = ["reqwest"], optional = true }
6464
openid = { version = "0.10", default-features = false, optional = true }
65-
# We need the older version of rand for dalek
66-
rand = "0.7"
65+
rand = "0.8"
6766
reqwest = { version = "0.11.4", features = ["stream"], default-features = false, optional = true }
6867
semver = { version = "1.0.4", features = ["serde"] }
6968
serde = { version = "1.0.130", features = ["derive"] }
@@ -89,8 +88,12 @@ warp = { version = "0.3", features = ["tls"], optional = true }
8988
remove_dir_all = "0.8"
9089

9190
[dev-dependencies]
91+
clap = { workspace = true, features = ["cargo"] }
9292
rstest = "0.15.0"
9393

94+
[workspace.dependencies]
95+
clap = "3"
96+
9497
[[bin]]
9598
name = "bindle-server"
9699
path = "bin/server.rs"

bin/client/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use bindle::{
1919
provider::Provider,
2020
};
2121

22+
use base64::Engine;
2223
use clap::Parser;
2324
use sha2::Digest;
2425
use tokio::io::AsyncWriteExt;
@@ -423,9 +424,10 @@ async fn run() -> std::result::Result<(), ClientError> {
423424
.await
424425
.unwrap_or_else(|_| KeyRing::default());
425426
// First, check that the key is actually valid
426-
let raw = base64::decode(&opts.key)
427+
let key = base64::engine::general_purpose::STANDARD
428+
.decode(&opts.key)
427429
.map_err(|_| SignatureError::CorruptKey(opts.key.clone()))?;
428-
ed25519_dalek::PublicKey::from_bytes(&raw)
430+
ed25519_dalek::VerifyingKey::try_from(key.as_slice())
429431
.map_err(|_| SignatureError::CorruptKey(opts.key.clone()))?;
430432
keyring.add_entry(KeyEntry {
431433
label: opts.label,

src/authn/http_basic.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::{collections::HashMap, path::Path};
22

3+
use base64::Engine;
4+
35
use super::Authenticator;
46
use crate::authz::Authorizable;
57

@@ -99,7 +101,8 @@ fn parse_basic(auth_data: &str) -> anyhow::Result<(String, String)> {
99101
None => anyhow::bail!("Wrong auth type. Only Basic auth is supported"),
100102
Some(suffix) => {
101103
// suffix should be base64 string
102-
let decoded = String::from_utf8(base64::decode(suffix)?)?;
104+
let decoded =
105+
String::from_utf8(base64::engine::general_purpose::STANDARD.decode(suffix)?)?;
103106
let pair: Vec<&str> = decoded.splitn(2, ':').collect();
104107
if pair.len() != 2 {
105108
anyhow::bail!("Malformed Basic header")

src/authn/oidc.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! An authenticator that validates OIDC issued JWTs
2+
use base64::Engine;
23
use jsonwebtoken::{Algorithm, DecodingKey, Validation};
34
use openid::biscuit::jwk::{AlgorithmParameters, KeyType, PublicKeyUse};
45
use serde::Deserialize;
@@ -151,22 +152,16 @@ impl OidcAuthenticator {
151152
// that key is malformed (which should be a rare instance because it would mean
152153
// misconfiguration on the OIDC provider's part), just skip it
153154
let raw =
154-
base64::decode(k.common.x509_chain.unwrap_or_default().pop()?).ok()?;
155+
base64::engine::general_purpose::STANDARD.decode(k.common.x509_chain.unwrap_or_default().pop()?).ok()?;
155156
DecodingKey::from_ec_der(&raw)
156157
}
157158
KeyType::RSA => {
158159
if let AlgorithmParameters::RSA(rsa) = k.algorithm {
159160
// NOTE: jsonwebtoken expects a base64 encoded component (big endian) so
160161
// we are reencoding it here
161162
DecodingKey::from_rsa_components(
162-
&base64::encode_config(
163-
rsa.n.to_bytes_be(),
164-
base64::URL_SAFE_NO_PAD,
165-
),
166-
&base64::encode_config(
167-
rsa.e.to_bytes_be(),
168-
base64::URL_SAFE_NO_PAD,
169-
),
163+
&base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(rsa.n.to_bytes_be()),
164+
&base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(rsa.e.to_bytes_be()),
170165
).map_or_else(|e| {
171166
tracing::error!(error = %e, "Unable to parse decoding key from discovery client, skipping");
172167
None

src/client/tokens.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
sync::Arc,
77
};
88

9+
use base64::Engine;
910
use oauth2::reqwest::async_http_client;
1011
use oauth2::{
1112
basic::*, devicecode::DeviceAuthorizationResponse, AuthUrl, Client as Oauth2Client, ClientId,
@@ -110,7 +111,8 @@ impl HttpBasic {
110111
#[async_trait::async_trait]
111112
impl TokenManager for HttpBasic {
112113
async fn apply_auth_header(&self, builder: RequestBuilder) -> Result<RequestBuilder> {
113-
let data = base64::encode(format!("{}:{}", self.username, self.password));
114+
let data = base64::engine::general_purpose::STANDARD
115+
.encode(format!("{}:{}", self.username, self.password));
114116
let mut header_val = HeaderValue::from_str(&format!("Basic {}", data))
115117
.map_err(|e| ClientError::Other(e.to_string()))?;
116118
header_val.set_sensitive(true);

src/invoice/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub use api::{
2222
ErrorResponse, HealthResponse, InvoiceCreateResponse, KeyOptions, MissingParcelsResponse,
2323
QueryOptions,
2424
};
25+
use base64::Engine;
2526
#[doc(inline)]
2627
pub use bindle_spec::BindleSpec;
2728
#[doc(inline)]
@@ -203,7 +204,8 @@ impl Invoice {
203204
let key = keyfile.key()?;
204205
// The spec says it is illegal for the a single key to sign the same invoice
205206
// more than once.
206-
let encoded_key = base64::encode(key.public.to_bytes());
207+
let encoded_key =
208+
base64::engine::general_purpose::STANDARD.encode(key.verifying_key().as_bytes());
207209
if let Some(sigs) = self.signature.as_ref() {
208210
for s in sigs {
209211
if s.key == encoded_key {
@@ -223,7 +225,7 @@ impl Invoice {
223225
let signature_entry = Signature {
224226
by: signer_name,
225227
key: encoded_key,
226-
signature: base64::encode(signature.to_bytes()),
228+
signature: base64::engine::general_purpose::STANDARD.encode(signature.to_bytes()),
227229
role: signer_role,
228230
at: ts.as_secs(),
229231
};
@@ -270,7 +272,8 @@ fn sign_one(
270272
let key = keyfile.key()?;
271273
// The spec says it is illegal for the a single key to sign the same invoice
272274
// more than once.
273-
let encoded_key = base64::encode(key.public.to_bytes());
275+
let encoded_key =
276+
base64::engine::general_purpose::STANDARD.encode(key.verifying_key().as_bytes());
274277
if let Some(sigs) = inv.signature.as_ref() {
275278
for s in sigs {
276279
if s.key == encoded_key {
@@ -290,7 +293,7 @@ fn sign_one(
290293
let signature_entry = Signature {
291294
by: signer_name,
292295
key: encoded_key,
293-
signature: base64::encode(signature.to_bytes()),
296+
signature: base64::engine::general_purpose::STANDARD.encode(signature.to_bytes()),
294297
role: signer_role,
295298
at: ts.as_secs(),
296299
};

src/invoice/signature.rs

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
//! Contains the Signature type along with associated types and Roles
22
3-
pub use ed25519_dalek::{Keypair, PublicKey, Signature as EdSignature, Signer};
3+
use base64::Engine;
4+
pub use ed25519_dalek::{
5+
Signature as EdSignature,
6+
Signer,
7+
SigningKey as Keypair, // re-export under old name for backwards compatibility
8+
SigningKey,
9+
VerifyingKey as PublicKey, // re-export under old name for backwards compatibility
10+
VerifyingKey,
11+
};
412
use serde::{Deserialize, Serialize};
513
use thiserror::Error;
614
#[cfg(not(target_arch = "wasm32"))]
@@ -197,7 +205,7 @@ impl KeyRing {
197205
self.key.push(entry)
198206
}
199207

200-
pub fn contains(&self, key: &PublicKey) -> bool {
208+
pub fn contains(&self, key: &VerifyingKey) -> bool {
201209
// This could definitely be optimized.
202210
for k in self.key.iter() {
203211
// Note that we are skipping malformed keys because they don't matter
@@ -246,40 +254,43 @@ impl KeyEntry {
246254
/// In most cases, it is fine to construct a KeyEntry struct manually. This
247255
/// constructor merely encapsulates the logic to store the public key in its
248256
/// canonical encoded format (as a String).
249-
pub fn new(label: &str, roles: Vec<SignatureRole>, public_key: PublicKey) -> Self {
250-
let key = base64::encode(public_key.to_bytes());
257+
pub fn new(label: &str, roles: Vec<SignatureRole>, public_key: VerifyingKey) -> Self {
258+
let key = base64::engine::general_purpose::STANDARD.encode(public_key.to_bytes());
251259
KeyEntry {
252260
label: label.to_owned(),
253261
roles,
254262
key,
255263
label_signature: None,
256264
}
257265
}
258-
pub fn sign_label(&mut self, key: Keypair) {
266+
pub fn sign_label(&mut self, key: SigningKey) {
259267
let sig = key.sign(self.label.as_bytes());
260-
self.label_signature = Some(base64::encode(sig.to_bytes()));
268+
self.label_signature =
269+
Some(base64::engine::general_purpose::STANDARD.encode(sig.to_bytes()));
261270
}
262-
pub fn verify_label(self, key: PublicKey) -> anyhow::Result<()> {
271+
pub fn verify_label(self, key: VerifyingKey) -> anyhow::Result<()> {
263272
match self.label_signature {
264273
None => {
265274
tracing::log::info!("Label was not signed. Skipping.");
266275
Ok(())
267276
}
268277
Some(txt) => {
269-
let decoded_txt = base64::decode(txt)?;
278+
let decoded_txt = base64::engine::general_purpose::STANDARD.decode(txt)?;
270279
let sig = EdSignature::try_from(decoded_txt.as_slice())?;
271280
key.verify_strict(self.label.as_bytes(), &sig)?;
272281
Ok(())
273282
}
274283
}
275284
}
276-
pub(crate) fn public_key(&self) -> Result<PublicKey, SignatureError> {
277-
let rawbytes = base64::decode(&self.key).map_err(|_e| {
278-
// We swallow the source error because it could disclose information about
279-
// the secret key.
280-
SignatureError::CorruptKey("Base64 decoding of the public key failed".to_owned())
281-
})?;
282-
let pk = PublicKey::from_bytes(rawbytes.as_slice()).map_err(|e| {
285+
pub(crate) fn public_key(&self) -> Result<VerifyingKey, SignatureError> {
286+
let rawbytes = base64::engine::general_purpose::STANDARD
287+
.decode(&self.key)
288+
.map_err(|_e| {
289+
// We swallow the source error because it could disclose information about
290+
// the secret key.
291+
SignatureError::CorruptKey("Base64 decoding of the public key failed".to_owned())
292+
})?;
293+
let pk = VerifyingKey::try_from(rawbytes.as_slice()).map_err(|e| {
283294
error!(%e, "Error loading public key");
284295
// Don't leak information about the key, because this could be sent to
285296
// a remote. A generic error is all the user should see.
@@ -297,7 +308,7 @@ impl TryFrom<SecretKeyEntry> for KeyEntry {
297308
let mut s = Self {
298309
label: secret.label,
299310
roles: secret.roles,
300-
key: base64::encode(skey.public.to_bytes()),
311+
key: base64::engine::general_purpose::STANDARD.encode(skey.verifying_key().as_bytes()),
301312
label_signature: None,
302313
};
303314
s.sign_label(skey);
@@ -312,7 +323,7 @@ impl TryFrom<&SecretKeyEntry> for KeyEntry {
312323
let mut s = Self {
313324
label: secret.label.clone(),
314325
roles: secret.roles.clone(),
315-
key: base64::encode(skey.public.to_bytes()),
326+
key: base64::engine::general_purpose::STANDARD.encode(skey.verifying_key().as_bytes()),
316327
label_signature: None,
317328
};
318329
s.sign_label(skey);
@@ -337,28 +348,34 @@ pub struct SecretKeyEntry {
337348
impl SecretKeyEntry {
338349
pub fn new(label: &str, roles: Vec<SignatureRole>) -> Self {
339350
let mut rng = rand::rngs::OsRng {};
340-
let rawkey = Keypair::generate(&mut rng);
341-
let keypair = base64::encode(rawkey.to_bytes());
351+
let rawkey = SigningKey::generate(&mut rng);
352+
let keypair = base64::engine::general_purpose::STANDARD.encode(rawkey.to_keypair_bytes());
342353
Self {
343354
label: label.to_owned(),
344355
keypair,
345356
roles,
346357
}
347358
}
348359

349-
pub(crate) fn key(&self) -> Result<Keypair, SignatureError> {
350-
let rawbytes = base64::decode(&self.keypair).map_err(|_e| {
360+
pub(crate) fn key(&self) -> Result<SigningKey, SignatureError> {
361+
let rawbytes = base64::engine::general_purpose::STANDARD
362+
.decode(&self.keypair)
363+
.map_err(|_e| {
364+
// We swallow the source error because it could disclose information about
365+
// the secret key.
366+
SignatureError::CorruptKey("Base64 decoding of the keypair failed".to_owned())
367+
})?;
368+
let rawbytes = rawbytes.try_into().map_err(|_e| {
351369
// We swallow the source error because it could disclose information about
352370
// the secret key.
353-
SignatureError::CorruptKey("Base64 decoding of the keypair failed".to_owned())
371+
SignatureError::CorruptKey("Invalid keypair length".to_owned())
354372
})?;
355-
let keypair = Keypair::from_bytes(&rawbytes).map_err(|e| {
373+
SigningKey::from_keypair_bytes(&rawbytes).map_err(|e| {
356374
tracing::log::error!("Error loading key: {}", e);
357375
// Don't leak information about the key, because this could be sent to
358376
// a remote. A generic error is all the user should see.
359377
SignatureError::CorruptKey("Could not load keypair".to_owned())
360-
})?;
361-
Ok(keypair)
378+
})
362379
}
363380
}
364381

@@ -481,7 +498,7 @@ impl SecretKeyStorage for SecretKeyFile {
481498
#[cfg(test)]
482499
mod test {
483500
use super::*;
484-
use ed25519_dalek::Keypair;
501+
use ed25519_dalek::SigningKey;
485502

486503
#[test]
487504
fn test_parse_role() {
@@ -508,7 +525,7 @@ mod test {
508525
#[test]
509526
fn test_sign_label() {
510527
let mut rng = rand::rngs::OsRng {};
511-
let keypair = Keypair::generate(&mut rng);
528+
let keypair = SigningKey::generate(&mut rng);
512529

513530
let mut ke = KeyEntry {
514531
label: "Matt Butcher <matt@example.com>".to_owned(),
@@ -517,7 +534,7 @@ mod test {
517534
label_signature: None,
518535
};
519536

520-
let pubkey = keypair.public;
537+
let pubkey = keypair.verifying_key();
521538
ke.sign_label(keypair);
522539

523540
assert!(ke.label_signature.is_some());

src/invoice/verification.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::invoice::Signed;
22

33
use super::signature::KeyRing;
44
use super::{Invoice, Signature, SignatureError, SignatureRole};
5-
use ed25519_dalek::{PublicKey, Signature as EdSignature};
5+
use base64::Engine;
6+
use ed25519_dalek::{Signature as EdSignature, VerifyingKey};
67
use tracing::debug;
78

89
use std::borrow::{Borrow, BorrowMut};
@@ -136,13 +137,15 @@ fn parse_roles(r: Option<&&str>) -> Result<Vec<SignatureRole>, &'static str> {
136137
/// A strategy for verifying an invoice.
137138
impl VerificationStrategy {
138139
fn verify_signature(&self, sig: &Signature, cleartext: &[u8]) -> Result<(), SignatureError> {
139-
let pk = base64::decode(sig.key.as_bytes())
140+
let pk = base64::engine::general_purpose::STANDARD
141+
.decode(sig.key.as_bytes())
140142
.map_err(|_| SignatureError::CorruptKey(sig.key.clone()))?;
141-
let sig_block = base64::decode(sig.signature.as_bytes())
143+
let sig_block = base64::engine::general_purpose::STANDARD
144+
.decode(sig.signature.as_bytes())
142145
.map_err(|_| SignatureError::CorruptSignature(sig.key.clone()))?;
143146

144-
let pubkey =
145-
PublicKey::from_bytes(&pk).map_err(|_| SignatureError::CorruptKey(sig.key.clone()))?;
147+
let pubkey = VerifyingKey::try_from(pk.as_slice())
148+
.map_err(|_| SignatureError::CorruptKey(sig.key.clone()))?;
146149
let ed_sig = EdSignature::try_from(sig_block.as_slice())
147150
.map_err(|_| SignatureError::CorruptSignature(sig.key.clone()))?;
148151
pubkey
@@ -231,9 +234,10 @@ impl VerificationStrategy {
231234
filled_roles.push(role);
232235
}
233236
// See if the public key is known to us
234-
let pubkey = base64::decode(&s.key)
237+
let pubkey = base64::engine::general_purpose::STANDARD
238+
.decode(&s.key)
235239
.map_err(|_| SignatureError::CorruptKey(s.key.to_string()))?;
236-
let pko = PublicKey::from_bytes(pubkey.as_slice())
240+
let pko = VerifyingKey::try_from(pubkey.as_slice())
237241
.map_err(|_| SignatureError::CorruptKey(s.key.to_string()))?;
238242

239243
debug!("Looking for key");

0 commit comments

Comments
 (0)