Create function for inserting integrity proofs into JSON objects

This commit is contained in:
silverpill 2022-11-01 17:39:42 +00:00
parent 3dbb922f3c
commit dec9b1f3a4
2 changed files with 50 additions and 28 deletions

View file

@ -6,11 +6,21 @@ use serde_json::Value;
use crate::utils::crypto::sign_message; use crate::utils::crypto::sign_message;
use super::canonicalization::{canonicalize_object, CanonicalizationError}; use super::canonicalization::{canonicalize_object, CanonicalizationError};
pub const PROOF_KEY: &str = "proof";
// 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 = "JcsRsaSignature2022";
pub const PROOF_PURPOSE: &str = "assertionMethod";
/// Data Integrity Proof /// Data Integrity Proof
/// https://w3c.github.io/vc-data-integrity/ /// https://w3c.github.io/vc-data-integrity/
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Proof { pub struct IntegrityProof {
#[serde(rename = "type")] #[serde(rename = "type")]
pub proof_type: String, pub proof_type: String,
pub proof_purpose: String, pub proof_purpose: String,
@ -19,15 +29,20 @@ pub struct Proof {
pub proof_value: String, pub proof_value: String,
} }
pub const PROOF_KEY: &str = "proof"; impl IntegrityProof {
fn jcs_rsa(
// Similar to https://identity.foundation/JcsEd25519Signature2020/ signer_key_id: &str,
// - Canonicalization algorithm: JCS signature: &str,
// - Digest algorithm: SHA-256 ) -> Self {
// - Signature algorithm: RSASSA-PKCS1-v1_5 Self {
pub const PROOF_TYPE: &str = "JcsRsaSignature2022"; proof_type: PROOF_TYPE_JCS_RSA.to_string(),
proof_purpose: PROOF_PURPOSE.to_string(),
pub const PROOF_PURPOSE: &str = "assertionMethod"; verification_method: signer_key_id.to_string(),
created: Utc::now(),
proof_value: signature.to_string(),
}
}
}
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum JsonSignatureError { pub enum JsonSignatureError {
@ -47,6 +62,20 @@ pub enum JsonSignatureError {
AlreadySigned, AlreadySigned,
} }
pub fn add_integrity_proof(
object_value: &mut Value,
proof: IntegrityProof,
) -> Result<(), JsonSignatureError> {
let object_map = object_value.as_object_mut()
.ok_or(JsonSignatureError::InvalidObject)?;
if object_map.contains_key(PROOF_KEY) {
return Err(JsonSignatureError::AlreadySigned);
};
let proof_value = serde_json::to_value(proof)?;
object_map.insert(PROOF_KEY.to_string(), proof_value);
Ok(())
}
pub fn sign_object( pub fn sign_object(
object: &Value, object: &Value,
signer_key: &RsaPrivateKey, signer_key: &RsaPrivateKey,
@ -57,21 +86,9 @@ pub fn sign_object(
// Sign // Sign
let signature_b64 = sign_message(signer_key, &message)?; let signature_b64 = sign_message(signer_key, &message)?;
// Insert proof // Insert proof
let proof = Proof { let proof = IntegrityProof::jcs_rsa(signer_key_id, &signature_b64);
proof_type: PROOF_TYPE.to_string(),
proof_purpose: PROOF_PURPOSE.to_string(),
verification_method: signer_key_id.to_string(),
created: Utc::now(),
proof_value: signature_b64,
};
let proof_value = serde_json::to_value(proof)?;
let mut object_value = serde_json::to_value(object)?; let mut object_value = serde_json::to_value(object)?;
let object_map = object_value.as_object_mut() add_integrity_proof(&mut object_value, proof)?;
.ok_or(JsonSignatureError::InvalidObject)?;
if object_map.contains_key(PROOF_KEY) {
return Err(JsonSignatureError::AlreadySigned);
};
object_map.insert(PROOF_KEY.to_string(), proof_value);
Ok(object_value) Ok(object_value)
} }

View file

@ -3,7 +3,12 @@ use serde_json::Value;
use crate::utils::crypto::verify_signature; use crate::utils::crypto::verify_signature;
use super::canonicalization::{canonicalize_object, CanonicalizationError}; use super::canonicalization::{canonicalize_object, CanonicalizationError};
use super::create::{Proof, PROOF_KEY, PROOF_TYPE, PROOF_PURPOSE}; use super::create::{
IntegrityProof,
PROOF_TYPE_JCS_RSA,
PROOF_KEY,
PROOF_PURPOSE,
};
pub struct SignatureData { pub struct SignatureData {
pub key_id: String, pub key_id: String,
@ -42,12 +47,12 @@ pub fn get_json_signature(
.ok_or(VerificationError::InvalidObject)?; .ok_or(VerificationError::InvalidObject)?;
let proof_value = object_map.remove(PROOF_KEY) let proof_value = object_map.remove(PROOF_KEY)
.ok_or(VerificationError::NoProof)?; .ok_or(VerificationError::NoProof)?;
let proof: Proof = serde_json::from_value(proof_value) let proof: IntegrityProof = serde_json::from_value(proof_value)
.map_err(|_| VerificationError::InvalidProof("invalid proof"))?; .map_err(|_| VerificationError::InvalidProof("invalid proof"))?;
if proof.proof_type != PROOF_TYPE || if proof.proof_type != PROOF_TYPE_JCS_RSA ||
proof.proof_purpose != PROOF_PURPOSE proof.proof_purpose != PROOF_PURPOSE
{ {
return Err(VerificationError::InvalidProof("invalid proof")); return Err(VerificationError::InvalidProof("unsupported proof type"));
}; };
let message = canonicalize_object(&object)?; let message = canonicalize_object(&object)?;
let signature_data = SignatureData { let signature_data = SignatureData {