2022-11-23 11:40:36 +00:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
2022-10-23 23:46:51 +00:00
|
|
|
use rsa::RsaPublicKey;
|
|
|
|
use serde_json::Value;
|
2022-11-23 11:40:36 +00:00
|
|
|
use url::Url;
|
2022-10-23 23:46:51 +00:00
|
|
|
|
2022-11-10 21:52:45 +00:00
|
|
|
use crate::ethereum::identity::verify_eip191_signature;
|
2022-11-10 19:06:10 +00:00
|
|
|
use crate::identity::{
|
2022-11-10 18:47:22 +00:00
|
|
|
did::Did,
|
|
|
|
did_key::DidKey,
|
2022-11-10 19:06:10 +00:00
|
|
|
did_pkh::DidPkh,
|
2022-11-19 14:54:33 +00:00
|
|
|
minisign::verify_ed25519_signature,
|
2022-11-23 14:37:32 +00:00
|
|
|
signatures::SignatureType,
|
2022-11-10 19:06:10 +00:00
|
|
|
};
|
2022-11-19 15:08:40 +00:00
|
|
|
use crate::utils::{
|
|
|
|
canonicalization::{
|
|
|
|
canonicalize_object,
|
|
|
|
CanonicalizationError,
|
|
|
|
},
|
|
|
|
crypto_rsa::verify_rsa_signature,
|
|
|
|
multibase::{decode_multibase_base58btc, MultibaseError},
|
2022-11-10 16:44:05 +00:00
|
|
|
};
|
2022-11-01 17:39:42 +00:00
|
|
|
use super::create::{
|
|
|
|
IntegrityProof,
|
|
|
|
PROOF_KEY,
|
|
|
|
PROOF_PURPOSE,
|
|
|
|
};
|
2022-10-23 23:46:51 +00:00
|
|
|
|
2022-11-02 17:15:15 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum JsonSigner {
|
|
|
|
ActorKeyId(String),
|
2022-11-10 18:47:22 +00:00
|
|
|
Did(Did),
|
2022-11-02 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2022-10-23 23:46:51 +00:00
|
|
|
pub struct SignatureData {
|
2022-11-23 14:37:32 +00:00
|
|
|
pub signature_type: SignatureType,
|
2022-11-02 17:15:15 +00:00
|
|
|
pub signer: JsonSigner,
|
2022-10-23 23:46:51 +00:00
|
|
|
pub message: String,
|
2022-11-19 15:08:40 +00:00
|
|
|
pub signature: Vec<u8>,
|
2022-10-23 23:46:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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")]
|
2022-11-19 15:08:40 +00:00
|
|
|
InvalidEncoding(#[from] MultibaseError),
|
2022-10-23 23:46:51 +00:00
|
|
|
|
|
|
|
#[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)?;
|
2022-11-01 00:02:25 +00:00
|
|
|
let proof_value = object_map.remove(PROOF_KEY)
|
2022-10-23 23:46:51 +00:00
|
|
|
.ok_or(VerificationError::NoProof)?;
|
2022-11-01 17:39:42 +00:00
|
|
|
let proof: IntegrityProof = serde_json::from_value(proof_value)
|
2022-10-23 23:46:51 +00:00
|
|
|
.map_err(|_| VerificationError::InvalidProof("invalid proof"))?;
|
2022-11-02 17:15:15 +00:00
|
|
|
if proof.proof_purpose != PROOF_PURPOSE {
|
|
|
|
return Err(VerificationError::InvalidProof("invalid proof purpose"));
|
|
|
|
};
|
2022-11-23 14:37:32 +00:00
|
|
|
let signature_type = proof.proof_type.parse()
|
|
|
|
.map_err(|_| VerificationError::InvalidProof("unsupported proof type"))?;
|
2022-11-23 11:40:36 +00:00
|
|
|
let signer = if let Ok(did) = Did::from_str(&proof.verification_method) {
|
|
|
|
JsonSigner::Did(did)
|
|
|
|
} else if Url::parse(&proof.verification_method).is_ok() {
|
|
|
|
JsonSigner::ActorKeyId(proof.verification_method)
|
|
|
|
} else {
|
|
|
|
return Err(VerificationError::InvalidProof("unsupported verification method"));
|
2022-10-23 23:46:51 +00:00
|
|
|
};
|
2022-10-31 20:12:19 +00:00
|
|
|
let message = canonicalize_object(&object)?;
|
2022-11-19 15:08:40 +00:00
|
|
|
let signature = decode_multibase_base58btc(&proof.proof_value)?;
|
2022-10-23 23:46:51 +00:00
|
|
|
let signature_data = SignatureData {
|
2022-11-23 14:37:32 +00:00
|
|
|
signature_type,
|
|
|
|
signer,
|
|
|
|
message,
|
|
|
|
signature,
|
2022-10-23 23:46:51 +00:00
|
|
|
};
|
|
|
|
Ok(signature_data)
|
|
|
|
}
|
|
|
|
|
2022-11-10 21:52:45 +00:00
|
|
|
pub fn verify_rsa_json_signature(
|
2022-10-23 23:46:51 +00:00
|
|
|
signature_data: &SignatureData,
|
|
|
|
signer_key: &RsaPublicKey,
|
|
|
|
) -> Result<(), VerificationError> {
|
2022-11-13 18:43:57 +00:00
|
|
|
let is_valid_signature = verify_rsa_signature(
|
2022-10-23 23:46:51 +00:00
|
|
|
signer_key,
|
|
|
|
&signature_data.message,
|
2022-11-19 15:08:40 +00:00
|
|
|
&signature_data.signature,
|
2022-11-18 23:22:24 +00:00
|
|
|
);
|
2022-10-23 23:46:51 +00:00
|
|
|
if !is_valid_signature {
|
|
|
|
return Err(VerificationError::InvalidSignature);
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-11-10 21:52:45 +00:00
|
|
|
pub fn verify_eip191_json_signature(
|
2022-10-29 00:24:17 +00:00
|
|
|
signer: &DidPkh,
|
|
|
|
message: &str,
|
2022-11-19 15:08:40 +00:00
|
|
|
signature: &[u8],
|
2022-10-29 00:24:17 +00:00
|
|
|
) -> Result<(), VerificationError> {
|
2022-11-19 15:08:40 +00:00
|
|
|
let signature_hex = hex::encode(signature);
|
2022-11-19 12:38:23 +00:00
|
|
|
verify_eip191_signature(signer, message, &signature_hex)
|
2022-11-10 21:52:45 +00:00
|
|
|
.map_err(|_| VerificationError::InvalidSignature)
|
2022-10-29 00:24:17 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 14:54:33 +00:00
|
|
|
pub fn verify_ed25519_json_signature(
|
2022-11-10 18:47:22 +00:00
|
|
|
signer: &DidKey,
|
|
|
|
message: &str,
|
2022-11-19 15:08:40 +00:00
|
|
|
signature: &[u8],
|
2022-11-10 18:47:22 +00:00
|
|
|
) -> Result<(), VerificationError> {
|
2022-11-19 15:08:40 +00:00
|
|
|
verify_ed25519_signature(signer, message, signature)
|
2022-11-10 18:47:22 +00:00
|
|
|
.map_err(|_| VerificationError::InvalidSignature)
|
|
|
|
}
|
|
|
|
|
2022-10-23 23:46:51 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use serde_json::json;
|
|
|
|
use crate::json_signatures::create::sign_object;
|
2022-11-13 18:43:57 +00:00
|
|
|
use crate::utils::crypto_rsa::generate_weak_rsa_key;
|
2022-11-02 12:16:10 +00:00
|
|
|
use crate::utils::currencies::Currency;
|
2022-10-23 23:46:51 +00:00
|
|
|
use super::*;
|
|
|
|
|
2022-11-02 12:16:10 +00:00
|
|
|
#[test]
|
2022-11-13 18:15:56 +00:00
|
|
|
fn test_get_json_signature_eip191() {
|
2022-11-02 12:16:10 +00:00
|
|
|
let signed_object = json!({
|
|
|
|
"type": "Test",
|
|
|
|
"id": "https://example.org/objects/1",
|
|
|
|
"proof": {
|
|
|
|
"type": "JcsEip191Signature2022",
|
|
|
|
"proofPurpose": "assertionMethod",
|
|
|
|
"verificationMethod": "did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a",
|
|
|
|
"created": "2020-11-05T19:23:24Z",
|
2022-11-19 15:08:40 +00:00
|
|
|
"proofValue": "zE5J",
|
2022-11-02 12:16:10 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
let signature_data = get_json_signature(&signed_object).unwrap();
|
2022-11-23 14:37:32 +00:00
|
|
|
assert_eq!(
|
|
|
|
signature_data.signature_type,
|
|
|
|
SignatureType::JcsEip191Signature,
|
|
|
|
);
|
2022-11-10 18:47:22 +00:00
|
|
|
let expected_signer = JsonSigner::Did(Did::Pkh(DidPkh::from_address(
|
2022-11-02 12:16:10 +00:00
|
|
|
&Currency::Ethereum,
|
|
|
|
"0xb9c5714089478a327f09197987f16f9e5d936e8a",
|
2022-11-10 18:47:22 +00:00
|
|
|
)));
|
2022-11-02 12:16:10 +00:00
|
|
|
assert_eq!(signature_data.signer, expected_signer);
|
2022-11-19 15:08:40 +00:00
|
|
|
assert_eq!(hex::encode(signature_data.signature), "abcd");
|
2022-11-02 12:16:10 +00:00
|
|
|
}
|
|
|
|
|
2022-10-23 23:46:51 +00:00
|
|
|
#[test]
|
|
|
|
fn test_create_and_verify_signature() {
|
2022-11-13 18:43:57 +00:00
|
|
|
let signer_key = generate_weak_rsa_key().unwrap();
|
2022-10-23 23:46:51 +00:00
|
|
|
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();
|
2022-11-23 14:37:32 +00:00
|
|
|
assert_eq!(
|
|
|
|
signature_data.signature_type,
|
|
|
|
SignatureType::JcsRsaSignature,
|
|
|
|
);
|
2022-11-02 17:15:15 +00:00
|
|
|
let expected_signer = JsonSigner::ActorKeyId(signer_key_id.to_string());
|
|
|
|
assert_eq!(signature_data.signer, expected_signer);
|
2022-10-23 23:46:51 +00:00
|
|
|
|
|
|
|
let signer_public_key = RsaPublicKey::from(signer_key);
|
2022-11-10 21:52:45 +00:00
|
|
|
let result = verify_rsa_json_signature(
|
2022-11-02 17:15:15 +00:00
|
|
|
&signature_data,
|
|
|
|
&signer_public_key,
|
|
|
|
);
|
2022-10-23 23:46:51 +00:00
|
|
|
assert_eq!(result.is_ok(), true);
|
|
|
|
}
|
|
|
|
}
|