Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite3d7684

Browse files
authored
Release v0.6.0 for web-bot-auth crates (#68)
* Make `@authority;req` errors more prominent + fix example signaturegenerationThis change amends the `http-signature-dir` to print an error logwhendirectories mistakenly sign `@authority` without the `req`parameter.It fixes a bug with the example signature agent card generation whereonly the host component was used to sign `@authority`, rather than thefull host and port pair (i.e. the _actual_ authority component). Thisled to verifiers being unable to verify generated signatures.It fixes some minor comments and superfluous Github Actions changes,and does some basic refactoring to make the logic a bit morestraightforward in the example. Importantly, it also adds the`alg` parameter in generated signatures - this is in line with theopinionated signing we do, whereby other elements normal to web bot authare also enforced for arbitrary HTTP signatures.* Release v0.6.0 of web-bot-auth cratesThese include some pretty significant and breaking changes:1. Dependency on `time` library is now required instead of `std::time` for all API users. As a bonus, however, we gain support on Cloudflare Workers as well as removal of a class of errors related to system clocks and `created` / `expires` parsing.2. A number of constructs were removed: `WebBotAuthSignedMessage`, `SignedMessage::fetch_all_signature_headers` and `SignedMessage::fetch_all_signature_inputs`. The library now exposes a single method to look up components to verify.3. `Signature-Agent` can now be parsed as a dictionary, but retains support for being parsed as a raw string.4. It enforces use of `req` parameter in `http-message-dir`. This is in line with the specification, but can break verification of existing sites.I also removed the pin to Rust v1.87 in the Github Actions handler. Thisensures we're building against the latest available Rust version.
1 parent6c16893 commite3d7684

File tree

9 files changed

+105
-77
lines changed

9 files changed

+105
-77
lines changed

‎.github/workflows/pullrequest.yml‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ jobs:
4747
target
4848
key:${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
4949
-name:Set rust toolchain
50-
run:rustupoverride set 1.87 && rustupcomponent add clippy rustfmt && rustup target add wasm32-unknown-unknown
50+
run:rustup component add clippy rustfmt && rustup target add wasm32-unknown-unknown
5151
-run:cargo fetch
52-
-run:cargo build --all --verbose --exclude plexi-cli --all-features --tests
53-
-run:cargo build --all --verbose --excludeplexi-cli --excludehttp-signature-directory --all-features --tests --target wasm32-unknown-unknown
52+
-run:cargo build --all --verbose --all-features --tests
53+
-run:cargo build --all --verbose --exclude http-signature-directory --all-features --tests --target wasm32-unknown-unknown
5454
-run:cargo check --tests --examples --benches --all-features
5555
-run:cargo clippy --all-features --all-targets -- -D warnings
5656
-run:cargo fmt --all -- --check
57-
-run:cargo doc --all --exclude plexi-cli --all-features --document-private-items
58-
-run:cargo test --all --verbose --exclude plexi-cli --all-features
57+
-run:cargo doc --all --all-features --document-private-items
58+
-run:cargo test --all --verbose --all-features
5959

6060
deploy-rust:
6161
name:Deploy Rust Crates
@@ -85,8 +85,6 @@ jobs:
8585
~/.cargo/git
8686
target
8787
key:${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
88-
-name:Set rust toolchain
89-
run:rustup override set 1.87
9088
-run:cargo publish -p web-bot-auth# will fail if we don't bump the version
9189
continue-on-error:true
9290
-run:cargo publish -p http-signature-directory# will fail if we don't bump the version

‎Cargo.lock‎

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ members = [
77
resolver ="2"
88

99
[workspace.package]
10-
version ="0.5.1"
10+
version ="0.6.0"
1111
authors = [
1212
"Akshat Mahajan <akshat@cloudflare.com>",
1313
"Gauri Baraskar <gbaraskar@cloudflare.com>",
@@ -35,4 +35,4 @@ regex = "1.12.2"
3535
time = {version ="0.3.44" }
3636

3737
# workspace dependencies
38-
web-bot-auth = {version ="0.5.1",path ="./crates/web-bot-auth" }
38+
web-bot-auth = {version ="0.6.0",path ="./crates/web-bot-auth" }

‎README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ This deployment allows to test your implementation.
3939
|[Caddy Plugin](./examples/caddy-plugin/)| Verify RFC 9421`Signature` for every incoming request|
4040
|[Rust](./examples/rust/)| Verify a sample test request|
4141

42+
###HTTP Signature Directories
43+
44+
| Example| Description|
45+
| :-----------------------------------------------------------------| :-------------------------------------------------------------|
46+
|[Cloudflare Workers](./examples/signature-agent-card-and-registry)| Host a signature directory on Cloudflare Workers, using the[signature agent card and registry](https://datatracker.ietf.org/doc/draft-meunier-webbotauth-registry/) format|
47+
4248
##Development
4349

4450
This repository uses[npm](https://docs.npmjs.com/cli/v11/using-npm/workspaces) and[cargo](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) workspaces. There are several packages which it provides:

‎crates/http-signature-directory/src/main.rs‎

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,28 +61,37 @@ struct RawKeyData {
6161
x:String,
6262
}
6363

64-
structSignedDirectory{
65-
signature:Vec<String>,
66-
input:Vec<String>,
64+
structSignedDirectory<'a>{
65+
headers:&'a reqwest::header::HeaderMap,
6766
authority:String,
6867
}
6968

70-
implSignedMessageforSignedDirectory{
69+
implSignedMessageforSignedDirectory<'_>{
7170
fnlookup_component(&self,name:&CoveredComponent) ->Vec<String>{
7271
match name{
7372
CoveredComponent::Derived(DerivedComponent::Authority{req:true}) =>{
74-
error!(
75-
"Expected `@authority`;req in signature input components, but did not find it"
73+
debug!(
74+
"Resolved {} for derived component {:?}",
75+
self.authority, name
7676
);
77+
7778
vec![self.authority.clone()]
7879
}
80+
CoveredComponent::Derived(DerivedComponent::Authority{req:false}) =>{
81+
error!(
82+
"You are signing a plain `@authority` without the `req` component parameter. Fix by signing with `req` so that Signature-Input uses `\"@authority\";req` instead",
83+
);
84+
vec![]
85+
}
7986
CoveredComponent::HTTP(HTTPField{ name, ..}) =>{
80-
ifname =="signature"{
81-
returnself.signature.clone();
82-
}
83-
if name =="signature-input"{
84-
returnself.input.clone();
87+
ifletSome(header) =self.headers.get(name)
88+
&&letOk(value) = header.to_str()
89+
{
90+
debug!("Found {} for header {}", value, name);
91+
returnvec![String::from(value)];
8592
}
93+
94+
debug!("No value for header {:?} found", name);
8695
vec![]
8796
}
8897
_ =>vec![],
@@ -175,9 +184,10 @@ fn main() -> Result<(), String> {
175184
warnings.push("No Content Type header found".to_string());
176185
}
177186

187+
let headers = response.headers().clone();
188+
178189
// Extract signature headers
179-
let signature_headers:Vec<String> = response
180-
.headers()
190+
let signature_headers:Vec<String> = headers
181191
.get_all("Signature")
182192
.iter()
183193
.filter_map(|header| header.to_str().map(String::from).ok())
@@ -188,8 +198,7 @@ fn main() -> Result<(), String> {
188198
signature_headers
189199
);
190200

191-
let signature_inputs:Vec<String> = response
192-
.headers()
201+
let signature_inputs:Vec<String> = headers
193202
.get_all("Signature-Input")
194203
.iter()
195204
.filter_map(|header| header.to_str().map(String::from).ok())
@@ -284,8 +293,7 @@ fn main() -> Result<(), String> {
284293
None =>{
285294
// Key imported successfully, now verify signature
286295
let directory =SignedDirectory{
287-
signature: signature_headers.clone(),
288-
input: signature_inputs.clone(),
296+
headers:&headers,
289297
authority:String::from(authority),
290298
};
291299

@@ -305,7 +313,9 @@ fn main() -> Result<(), String> {
305313
.and_then(|tag| tag.as_string())
306314
.is_some_and(|tag| tag.as_str() == thumbprint)
307315
&& innerlist.items.iter().any(|item|{
308-
*item == sfv::Item::new(sfv::StringRef::constant("@authority"))
316+
item.bare_item
317+
.as_string()
318+
.is_some_and(|s|(*s).as_str() =="@authority")
309319
})
310320
}){
311321
Ok(verifier) =>{

‎crates/web-bot-auth/src/lib.rs‎

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,13 @@ impl WebBotAuthVerifier {
149149

150150
letmut signature_agent_key:Option<String> =None;
151151
'outer_loop:for(component, _)in message_verifier.parsed.base.components.iter(){
152-
ifletCoveredComponent::HTTP(HTTPField{ name, parameters}) = component{
153-
if name =="signature-agent"{
154-
for parameterin parameters.0.iter(){
155-
ifletHTTPFieldParameters::Key(key) = parameter{
156-
signature_agent_key =Some(key.clone());
157-
break'outer_loop;
158-
}
152+
ifletCoveredComponent::HTTP(HTTPField{ name, parameters}) = component
153+
&& name =="signature-agent"
154+
{
155+
for parameterin parameters.0.iter(){
156+
ifletHTTPFieldParameters::Key(key) = parameter{
157+
signature_agent_key =Some(key.clone());
158+
break'outer_loop;
159159
}
160160
}
161161
}
@@ -171,12 +171,10 @@ impl WebBotAuthVerifier {
171171
let mediatype = url.mime_type();
172172
if mediatype.type_ =="application"
173173
&& mediatype.subtype =="http-message-signatures-directory"
174+
&&letOk((body, _)) = url.decode_to_vec()
175+
&&letOk(jwks) = serde_json::from_slice::<JSONWebKeySet>(&body)
174176
{
175-
ifletOk((body, _)) = url.decode_to_vec(){
176-
ifletOk(jwks) = serde_json::from_slice::<JSONWebKeySet>(&body){
177-
returnSome(SignatureAgentLink::Inline(jwks));
178-
}
179-
}
177+
returnSome(SignatureAgentLink::Inline(jwks));
180178
}
181179
}
182180

‎crates/web-bot-auth/src/message_signatures.rs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ pub trait SignedMessage {
239239
/// care should be taken to ensure HTTP field names in the message are checked in a
240240
/// case-insensitive way. Only `CoveredComponent::Http` should return a vector with
241241
/// more than one element.
242+
///
243+
/// This function is also used to look up the values of `Signature-Input`, `Signature`
244+
/// and (if used for web bot auth) `Signature-Agent` as standard HTTP headers.
245+
/// Implementations should return those headers as well.
242246
fnlookup_component(&self,name:&CoveredComponent) ->Vec<String>;
243247
}
244248

@@ -325,6 +329,19 @@ impl MessageSigner {
325329
),
326330
);
327331

332+
sfv_parameters.insert(
333+
sfv::KeyRef::constant("alg").to_owned(),
334+
sfv::BareItem::String(
335+
sfv::StringRef::from_str(&format!("{}", algorithm))
336+
.map_err(|_|{
337+
ImplementationError::ParsingError(
338+
"tag contains non-printable ASCII characters".into(),
339+
)
340+
})?
341+
.to_owned(),
342+
),
343+
);
344+
328345
let created =UtcDateTime::now();
329346
let expiry = created + expires;
330347

‎examples/signature-agent-card-and-registry/Cargo.toml‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ worker = { version = "0.7", features = ['http'] }
1919
worker-macros = {version ="0.7",features = ['http'] }
2020
web-bot-auth = {workspace =true }
2121

22-
# The following libraries are deliberately held back to these versions.
23-
# `ed25519-dalek` doesn't support latest `rand` in its latest stable version,
24-
# so we pin to the version of `rand` and `rand_chaca` the latest versions do support.
2522
ed25519-dalek = {version ="2.2.0",features = ['rand_core'] }
2623
rand = {version ="0.8",default-features =false,features = ["getrandom"] }
2724
getrandom = {version ="0.2",features = ["js"] }

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp