Skip to content
This repository has been archived by the owner on Apr 17, 2024. It is now read-only.

Commit

Permalink
Support integrity proofs with DataIntegrityProof type
Browse files Browse the repository at this point in the history
  • Loading branch information
silverpill authored and rafaelcaricio committed Apr 24, 2023
1 parent 05eeb5a commit b6e7fa5
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

- Added support for content warnings.
- Support integrity proofs with `DataIntegrityProof` type.

### Changed

Expand Down
8 changes: 4 additions & 4 deletions mitra-utils/src/crypto_rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn deserialize_public_key(
}

/// RSASSA-PKCS1-v1_5 signature
pub fn create_rsa_signature(
pub fn create_rsa_sha256_signature(
private_key: &RsaPrivateKey,
message: &str,
) -> Result<Vec<u8>, rsa::errors::Error> {
Expand All @@ -63,7 +63,7 @@ pub fn get_message_digest(message: &str) -> String {
digest_b64
}

pub fn verify_rsa_signature(
pub fn verify_rsa_sha256_signature(
public_key: &RsaPublicKey,
message: &str,
signature: &[u8],
Expand Down Expand Up @@ -102,13 +102,13 @@ YsFtrgWDQ/s8k86sNBU+Ce2GOL7seh46kyAWgJeohh4Rcrr23rftHbvxOcRM8VzYuCeb1DgVhPGtA0xU
fn test_verify_rsa_signature() {
let private_key = generate_weak_rsa_key().unwrap();
let message = "test".to_string();
let signature = create_rsa_signature(
let signature = create_rsa_sha256_signature(
&private_key,
&message,
).unwrap();
let public_key = RsaPublicKey::from(&private_key);

let is_valid = verify_rsa_signature(
let is_valid = verify_rsa_sha256_signature(
&public_key,
&message,
&signature,
Expand Down
4 changes: 2 additions & 2 deletions src/http_signatures/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use chrono::Utc;
use rsa::RsaPrivateKey;

use mitra_utils::crypto_rsa::{
create_rsa_signature,
create_rsa_sha256_signature,
get_message_digest,
};

Expand Down Expand Up @@ -72,7 +72,7 @@ pub fn create_http_signature(
.map(|(name, _)| name.to_string())
.collect::<Vec<String>>()
.join(" ");
let signature = create_rsa_signature(signer_key, &message)?;
let signature = create_rsa_sha256_signature(signer_key, &message)?;
let signature_parameter = base64::encode(signature);
let signature_header = format!(
r#"keyId="{}",algorithm="{}",headers="{}",signature="{}""#,
Expand Down
4 changes: 2 additions & 2 deletions src/http_signatures/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use chrono::{DateTime, Duration, TimeZone, Utc};
use regex::Regex;
use rsa::RsaPublicKey;

use mitra_utils::crypto_rsa::verify_rsa_signature;
use mitra_utils::crypto_rsa::verify_rsa_sha256_signature;

const SIGNATURE_PARAMETER_RE: &str = r#"^(?P<key>[a-zA-Z]+)="(?P<value>.+)"$"#;

Expand Down Expand Up @@ -134,7 +134,7 @@ pub fn verify_http_signature(
log::warn!("signature has expired");
};
let signature = base64::decode(&signature_data.signature)?;
let is_valid_signature = verify_rsa_signature(
let is_valid_signature = verify_rsa_sha256_signature(
signer_key,
&signature_data.message,
&signature,
Expand Down
20 changes: 14 additions & 6 deletions src/json_signatures/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use mitra_utils::{
canonicalize_object,
CanonicalizationError,
},
crypto_rsa::create_rsa_signature,
crypto_rsa::create_rsa_sha256_signature,
did_key::DidKey,
did_pkh::DidPkh,
multibase::encode_multibase_base58btc,
Expand All @@ -30,6 +30,8 @@ pub(super) const PROOF_PURPOSE: &str = "assertionMethod";
pub struct IntegrityProof {
#[serde(rename = "type")]
pub proof_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cryptosuite: Option<String>,
pub proof_purpose: String,
pub verification_method: String,
pub created: DateTime<Utc>,
Expand All @@ -43,6 +45,7 @@ impl IntegrityProof {
) -> Self {
Self {
proof_type: PROOF_TYPE_JCS_RSA.to_string(),
cryptosuite: None,
proof_purpose: PROOF_PURPOSE.to_string(),
verification_method: signer_key_id.to_string(),
created: Utc::now(),
Expand All @@ -56,6 +59,7 @@ impl IntegrityProof {
) -> Self {
Self {
proof_type: PROOF_TYPE_JCS_EIP191.to_string(),
cryptosuite: None,
proof_purpose: PROOF_PURPOSE.to_string(),
verification_method: signer.to_string(),
created: Utc::now(),
Expand All @@ -69,6 +73,7 @@ impl IntegrityProof {
) -> Self {
Self {
proof_type: PROOF_TYPE_JCS_ED25519.to_string(),
cryptosuite: None,
proof_purpose: PROOF_PURPOSE.to_string(),
verification_method: signer.to_string(),
created: Utc::now(),
Expand Down Expand Up @@ -115,14 +120,17 @@ pub fn sign_object(
signer_key_id: &str,
) -> Result<Value, JsonSignatureError> {
// Canonicalize
let message = canonicalize_object(object)?;
let transformed_object = canonicalize_object(object)?;
// Sign
let signature = create_rsa_signature(signer_key, &message)?;
let signature = create_rsa_sha256_signature(
signer_key,
&transformed_object,
)?;
// Insert proof
let proof = IntegrityProof::jcs_rsa(signer_key_id, &signature);
let mut object_value = serde_json::to_value(object)?;
add_integrity_proof(&mut object_value, proof)?;
Ok(object_value)
let mut signed_object = object.clone();
add_integrity_proof(&mut signed_object, proof)?;
Ok(signed_object)
}

pub fn is_object_signed(object: &Value) -> bool {
Expand Down
14 changes: 14 additions & 0 deletions src/json_signatures/proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ pub const PROOF_TYPE_ID_EIP191: &str = "ethereum-eip191-00";
// Identity proof, version 2022A
pub const PROOF_TYPE_ID_MINISIGN: &str = "MitraMinisignSignature2022A";

// https://w3c.github.io/vc-data-integrity/#dataintegrityproof
pub const DATA_INTEGRITY_PROOF: &str = "DataIntegrityProof";

// Similar to https://identity.foundation/JcsEd25519Signature2020/
// - Canonicalization algorithm: JCS
// - Digest algorithm: SHA-256
// - Signature algorithm: RSASSA-PKCS1-v1_5
pub const PROOF_TYPE_JCS_RSA: &str = "MitraJcsRsaSignature2022";
pub const PROOF_TYPE_JCS_RSA_LEGACY: &str = "JcsRsaSignature2022";
pub const CRYPTOSUITE_JCS_RSA: &str = "mitra-jcs-rsa-2022";

// Similar to EthereumPersonalSignature2021 but with JCS
pub const PROOF_TYPE_JCS_EIP191: &str = "MitraJcsEip191Signature2022";
Expand Down Expand Up @@ -49,3 +53,13 @@ impl FromStr for ProofType {
Ok(proof_type)
}
}

impl ProofType {
pub fn from_cryptosuite(value: &str) -> Result<Self, ConversionError> {
let proof_type = match value {
CRYPTOSUITE_JCS_RSA => Self::JcsRsaSignature,
_ => return Err(ConversionError),
};
Ok(proof_type)
}
}
23 changes: 15 additions & 8 deletions src/json_signatures/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use mitra_utils::{
canonicalize_object,
CanonicalizationError,
},
crypto_rsa::verify_rsa_signature,
crypto_rsa::verify_rsa_sha256_signature,
did::Did,
did_key::DidKey,
did_pkh::DidPkh,
Expand All @@ -24,7 +24,7 @@ use super::create::{
PROOF_KEY,
PROOF_PURPOSE,
};
use super::proofs::ProofType;
use super::proofs::{ProofType, DATA_INTEGRITY_PROOF};

#[derive(Debug, PartialEq)]
pub enum JsonSigner {
Expand Down Expand Up @@ -75,21 +75,28 @@ pub fn get_json_signature(
if proof.proof_purpose != PROOF_PURPOSE {
return Err(VerificationError::InvalidProof("invalid proof purpose"));
};
let signature_type = proof.proof_type.parse()
.map_err(|_| VerificationError::InvalidProof("unsupported proof type"))?;
let proof_type = if proof.proof_type == DATA_INTEGRITY_PROOF {
let cryptosuite = proof.cryptosuite.as_ref()
.ok_or(VerificationError::InvalidProof("cryptosuite is not specified"))?;
ProofType::from_cryptosuite(cryptosuite)
.map_err(|_| VerificationError::InvalidProof("unsupported proof type"))?
} else {
proof.proof_type.parse()
.map_err(|_| VerificationError::InvalidProof("unsupported proof type"))?
};
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"));
};
let message = canonicalize_object(&object)?;
let transformed_object = canonicalize_object(&object)?;
let signature = decode_multibase_base58btc(&proof.proof_value)?;
let signature_data = SignatureData {
signature_type,
signature_type: proof_type,
signer,
message,
message: transformed_object,
signature,
};
Ok(signature_data)
Expand All @@ -99,7 +106,7 @@ pub fn verify_rsa_json_signature(
signature_data: &SignatureData,
signer_key: &RsaPublicKey,
) -> Result<(), VerificationError> {
let is_valid_signature = verify_rsa_signature(
let is_valid_signature = verify_rsa_sha256_signature(
signer_key,
&signature_data.message,
&signature_data.signature,
Expand Down

0 comments on commit b6e7fa5

Please sign in to comment.