fedimovies/src/json_signatures/verify.rs

139 lines
4 KiB
Rust
Raw Normal View History

2022-10-23 23:46:51 +00:00
use rsa::RsaPublicKey;
use serde_json::Value;
2022-10-29 00:24:17 +00:00
use crate::ethereum::{
identity::DidPkh,
signatures::recover_address,
utils::address_to_string,
};
2022-10-23 23:46:51 +00:00
use crate::utils::crypto::verify_signature;
2022-10-31 20:12:19 +00:00
use super::canonicalization::{canonicalize_object, CanonicalizationError};
use super::create::{
IntegrityProof,
PROOF_TYPE_JCS_RSA,
PROOF_KEY,
PROOF_PURPOSE,
};
2022-10-23 23:46:51 +00:00
pub struct SignatureData {
pub key_id: String,
pub message: String,
pub signature: String,
}
#[derive(thiserror::Error, Debug)]
pub enum JsonSignatureVerificationError {
#[error("invalid object")]
InvalidObject,
#[error("no proof")]
NoProof,
#[error("{0}")]
InvalidProof(&'static str),
2022-10-31 20:12:19 +00:00
#[error(transparent)]
CanonicalizationError(#[from] CanonicalizationError),
2022-10-23 23:46:51 +00:00
#[error("invalid encoding")]
InvalidEncoding(#[from] base64::DecodeError),
#[error("invalid signature")]
InvalidSignature,
}
type VerificationError = JsonSignatureVerificationError;
pub fn get_json_signature(
object: &Value,
) -> Result<SignatureData, VerificationError> {
let mut object = object.clone();
let object_map = object.as_object_mut()
.ok_or(VerificationError::InvalidObject)?;
let proof_value = object_map.remove(PROOF_KEY)
2022-10-23 23:46:51 +00:00
.ok_or(VerificationError::NoProof)?;
let proof: IntegrityProof = serde_json::from_value(proof_value)
2022-10-23 23:46:51 +00:00
.map_err(|_| VerificationError::InvalidProof("invalid proof"))?;
if proof.proof_type != PROOF_TYPE_JCS_RSA ||
2022-10-23 23:46:51 +00:00
proof.proof_purpose != PROOF_PURPOSE
{
return Err(VerificationError::InvalidProof("unsupported proof type"));
2022-10-23 23:46:51 +00:00
};
2022-10-31 20:12:19 +00:00
let message = canonicalize_object(&object)?;
2022-10-23 23:46:51 +00:00
let signature_data = SignatureData {
key_id: proof.verification_method,
2022-10-31 20:12:19 +00:00
message: message,
2022-10-23 23:46:51 +00:00
signature: proof.proof_value,
};
Ok(signature_data)
}
pub fn verify_json_signature(
signature_data: &SignatureData,
signer_key: &RsaPublicKey,
) -> Result<(), VerificationError> {
let is_valid_signature = verify_signature(
signer_key,
&signature_data.message,
&signature_data.signature,
)?;
if !is_valid_signature {
return Err(VerificationError::InvalidSignature);
};
Ok(())
}
2022-10-29 00:24:17 +00:00
pub fn verify_jcs_eip191_signature(
signer: &DidPkh,
message: &str,
signature: &str,
) -> Result<(), VerificationError> {
let signature_data = signature.parse()
.map_err(|_| VerificationError::InvalidProof("invalid proof"))?;
let signer_address = recover_address(message.as_bytes(), &signature_data)
.map_err(|_| VerificationError::InvalidSignature)?;
if address_to_string(signer_address) != signer.address.to_lowercase() {
return Err(VerificationError::InvalidSignature);
};
Ok(())
}
2022-10-23 23:46:51 +00:00
#[cfg(test)]
mod tests {
use serde_json::json;
use crate::json_signatures::create::sign_object;
use crate::utils::crypto::generate_weak_private_key;
use super::*;
#[test]
fn test_create_and_verify_signature() {
let signer_key = generate_weak_private_key().unwrap();
let signer_key_id = "https://example.org/users/test#main-key";
let object = json!({
"type": "Create",
"actor": "https://example.org/users/test",
"id": "https://example.org/objects/1",
"to": [
"https://example.org/users/yyy",
"https://example.org/users/xxx",
],
"object": {
"type": "Note",
"content": "test",
},
});
let signed_object = sign_object(
&object,
&signer_key,
signer_key_id,
).unwrap();
let signature_data = get_json_signature(&signed_object).unwrap();
assert_eq!(signature_data.key_id, signer_key_id);
let signer_public_key = RsaPublicKey::from(signer_key);
let result = verify_json_signature(&signature_data, &signer_public_key);
assert_eq!(result.is_ok(), true);
}
}