Read HTTP signature expiration date from (expires) pseudo-header
This commit is contained in:
parent
7d204ab150
commit
581e72ce65
1 changed files with 15 additions and 7 deletions
|
@ -7,6 +7,10 @@ use rsa::RsaPublicKey;
|
||||||
|
|
||||||
use crate::utils::crypto_rsa::verify_rsa_signature;
|
use crate::utils::crypto_rsa::verify_rsa_signature;
|
||||||
|
|
||||||
|
const SIGNATURE_PARAMETER_RE: &str = r#"^(?P<key>[a-zA-Z]+)="(?P<value>.+)"$"#;
|
||||||
|
|
||||||
|
const SIGNATURE_EXPIRES_IN: i64 = 12; // 12 hours
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum HttpSignatureVerificationError {
|
pub enum HttpSignatureVerificationError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
@ -28,11 +32,9 @@ pub struct HttpSignatureData {
|
||||||
pub key_id: String,
|
pub key_id: String,
|
||||||
pub message: String, // reconstructed message
|
pub message: String, // reconstructed message
|
||||||
pub signature: String, // base64-encoded signature
|
pub signature: String, // base64-encoded signature
|
||||||
pub created_at: DateTime<Utc>,
|
pub expires_at: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIGNATURE_PARAMETER_RE: &str = r#"^(?P<key>[a-zA-Z]+)="(?P<value>.+)"$"#;
|
|
||||||
|
|
||||||
pub fn parse_http_signature(
|
pub fn parse_http_signature(
|
||||||
request_method: &Method,
|
request_method: &Method,
|
||||||
request_uri: &Uri,
|
request_uri: &Uri,
|
||||||
|
@ -75,6 +77,13 @@ pub fn parse_http_signature(
|
||||||
.map_err(|_| VerificationError::ParseError("invalid date"))?;
|
.map_err(|_| VerificationError::ParseError("invalid date"))?;
|
||||||
date.with_timezone(&Utc)
|
date.with_timezone(&Utc)
|
||||||
};
|
};
|
||||||
|
let expires_at = if let Some(expires_at) = signature_parameters.get("expires") {
|
||||||
|
let expires_at_timestamp = expires_at.parse()
|
||||||
|
.map_err(|_| VerificationError::ParseError("invalid timestamp"))?;
|
||||||
|
Utc.timestamp(expires_at_timestamp, 0)
|
||||||
|
} else {
|
||||||
|
created_at + Duration::hours(SIGNATURE_EXPIRES_IN)
|
||||||
|
};
|
||||||
|
|
||||||
let mut message_parts = vec![];
|
let mut message_parts = vec![];
|
||||||
for header in headers_parameter.split(' ') {
|
for header in headers_parameter.split(' ') {
|
||||||
|
@ -107,7 +116,7 @@ pub fn parse_http_signature(
|
||||||
key_id,
|
key_id,
|
||||||
message,
|
message,
|
||||||
signature,
|
signature,
|
||||||
created_at,
|
expires_at,
|
||||||
};
|
};
|
||||||
Ok(signature_data)
|
Ok(signature_data)
|
||||||
}
|
}
|
||||||
|
@ -116,8 +125,7 @@ pub fn verify_http_signature(
|
||||||
signature_data: &HttpSignatureData,
|
signature_data: &HttpSignatureData,
|
||||||
signer_key: &RsaPublicKey,
|
signer_key: &RsaPublicKey,
|
||||||
) -> Result<(), VerificationError> {
|
) -> Result<(), VerificationError> {
|
||||||
let expires_at = signature_data.created_at + Duration::hours(12);
|
if signature_data.expires_at < Utc::now() {
|
||||||
if expires_at < Utc::now() {
|
|
||||||
log::warn!("signature has expired");
|
log::warn!("signature has expired");
|
||||||
};
|
};
|
||||||
let signature = base64::decode(&signature_data.signature)?;
|
let signature = base64::decode(&signature_data.signature)?;
|
||||||
|
@ -178,7 +186,7 @@ mod tests {
|
||||||
"(request-target): post /user/123/inbox\nhost: example.com\ndate: 20 Oct 2022 20:00:00 GMT",
|
"(request-target): post /user/123/inbox\nhost: example.com\ndate: 20 Oct 2022 20:00:00 GMT",
|
||||||
);
|
);
|
||||||
assert_eq!(signature_data.signature, "test");
|
assert_eq!(signature_data.signature, "test");
|
||||||
assert!(signature_data.created_at < Utc::now());
|
assert!(signature_data.expires_at < Utc::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue