Never ignore invalid HTTP signatures

This commit is contained in:
silverpill 2022-12-07 22:10:58 +00:00
parent d3db42ec9e
commit 06e172d9fa
3 changed files with 31 additions and 11 deletions

View file

@ -32,6 +32,9 @@ pub enum AuthenticationError {
#[error(transparent)]
HttpSignatureError(#[from] HttpSignatureError),
#[error("no HTTP signature")]
NoHttpSignature,
#[error(transparent)]
JsonSignatureError(#[from] JsonSignatureError),
@ -76,11 +79,17 @@ pub async fn verify_signed_request(
request: &HttpRequest,
no_fetch: bool,
) -> Result<DbActorProfile, AuthenticationError> {
let signature_data = parse_http_signature(
let signature_data = match parse_http_signature(
request.method(),
request.uri(),
request.headers(),
)?;
) {
Ok(signature_data) => signature_data,
Err(HttpSignatureError::NoSignature) => {
return Err(AuthenticationError::NoHttpSignature);
},
Err(other_error) => return Err(other_error.into()),
};
let actor_id = key_id_to_actor_id(&signature_data.key_id)?;
let actor_profile = if no_fetch {
@ -113,12 +122,13 @@ pub async fn verify_signed_activity(
db_client: &impl GenericClient,
activity: &Value,
) -> Result<DbActorProfile, AuthenticationError> {
let signature_data = get_json_signature(activity).map_err(|error| {
match error {
JsonSignatureError::NoProof => AuthenticationError::NoJsonSignature,
other_error => other_error.into(),
}
})?;
let signature_data = match get_json_signature(activity) {
Ok(signature_data) => signature_data,
Err(JsonSignatureError::NoProof) => {
return Err(AuthenticationError::NoJsonSignature);
},
Err(other_error) => return Err(other_error.into()),
};
let actor_profile = match signature_data.signer {
JsonSigner::ActorKeyId(ref key_id) => {

View file

@ -157,6 +157,8 @@ pub async fn receive_activity(
let object_id = find_object_id(&activity.object)?;
activity.actor == object_id
} else { false };
// HTTP signature is required
let mut signer = match verify_signed_request(
config,
db_client,
@ -169,8 +171,13 @@ pub async fn receive_activity(
request_signer
},
Err(error) => {
if is_self_delete {
if is_self_delete && matches!(
error,
AuthenticationError::NoHttpSignature |
AuthenticationError::DatabaseError(_)
) {
// Ignore Delete(Person) activities without HTTP signatures
// or if signer is not found in local database
return Ok(());
};
log::warn!("invalid HTTP signature: {}", error);
@ -178,7 +185,7 @@ pub async fn receive_activity(
},
};
// Verify embedded signature
// JSON signature is optional
match verify_signed_activity(config, db_client, activity_raw).await {
Ok(activity_signer) => {
if activity_signer.acct != signer.acct {

View file

@ -13,6 +13,9 @@ const SIGNATURE_EXPIRES_IN: i64 = 12; // 12 hours
#[derive(thiserror::Error, Debug)]
pub enum HttpSignatureVerificationError {
#[error("missing signature header")]
NoSignature,
#[error("{0}")]
HeaderError(&'static str),
@ -41,7 +44,7 @@ pub fn parse_http_signature(
request_headers: &HeaderMap,
) -> Result<HttpSignatureData, VerificationError> {
let signature_header = request_headers.get("signature")
.ok_or(VerificationError::HeaderError("missing signature header"))?
.ok_or(VerificationError::NoSignature)?
.to_str()
.map_err(|_| VerificationError::HeaderError("invalid signature header"))?;