Create function for inserting integrity proofs into JSON objects
This commit is contained in:
parent
3dbb922f3c
commit
dec9b1f3a4
2 changed files with 50 additions and 28 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue