fedimovies/src/json_signatures/create.rs

106 lines
3.7 KiB
Rust
Raw Normal View History

2022-10-28 13:27:36 +00:00
use chrono::{DateTime, Utc};
2022-10-20 23:18:45 +00:00
use rsa::RsaPrivateKey;
2022-10-23 23:46:51 +00:00
use serde::{Deserialize, Serialize};
2022-10-20 23:18:45 +00:00
use serde_json::Value;
use crate::utils::crypto::sign_message;
2022-10-31 20:12:19 +00:00
use super::canonicalization::{canonicalize_object, CanonicalizationError};
2022-10-20 23:18:45 +00:00
/// Data Integrity Proof
/// https://w3c.github.io/vc-data-integrity/
2022-10-23 23:46:51 +00:00
#[derive(Deserialize, Serialize)]
2022-10-20 23:18:45 +00:00
#[serde(rename_all = "camelCase")]
2022-10-23 23:46:51 +00:00
pub struct Proof {
2022-10-20 23:18:45 +00:00
#[serde(rename = "type")]
2022-10-23 23:46:51 +00:00
pub proof_type: String,
pub proof_purpose: String,
pub verification_method: String,
2022-10-28 13:27:36 +00:00
pub created: DateTime<Utc>,
2022-10-23 23:46:51 +00:00
pub proof_value: String,
2022-10-20 23:18:45 +00:00
}
// Similar to https://identity.foundation/JcsEd25519Signature2020/
// - Canonicalization algorithm: JCS
// - Digest algorithm: SHA-256
// - Signature algorithm: RSASSA-PKCS1-v1_5
2022-10-23 23:46:51 +00:00
pub const PROOF_TYPE: &str = "JcsRsaSignature2022";
2022-10-20 23:18:45 +00:00
2022-10-23 23:46:51 +00:00
pub const PROOF_PURPOSE: &str = "assertionMethod";
2022-10-20 23:18:45 +00:00
#[derive(thiserror::Error, Debug)]
pub enum JsonSignatureError {
#[error(transparent)]
JsonError(#[from] serde_json::Error),
2022-10-31 20:12:19 +00:00
#[error(transparent)]
CanonicalizationError(#[from] CanonicalizationError),
2022-10-20 23:18:45 +00:00
#[error("signing error")]
SigningError(#[from] rsa::errors::Error),
2022-10-23 23:46:51 +00:00
#[error("invalid object")]
InvalidObject,
2022-10-20 23:18:45 +00:00
}
pub fn sign_object(
object: &impl Serialize,
signer_key: &RsaPrivateKey,
signer_key_id: &str,
) -> Result<Value, JsonSignatureError> {
// Canonicalize
2022-10-31 20:12:19 +00:00
let message = canonicalize_object(object)?;
2022-10-20 23:18:45 +00:00
// Sign
2022-10-31 20:12:19 +00:00
let signature_b64 = sign_message(signer_key, &message)?;
2022-10-20 23:18:45 +00:00
// Insert proof
let proof = Proof {
proof_type: PROOF_TYPE.to_string(),
proof_purpose: PROOF_PURPOSE.to_string(),
verification_method: signer_key_id.to_string(),
2022-10-28 13:27:36 +00:00
created: Utc::now(),
2022-10-20 23:18:45 +00:00
proof_value: signature_b64,
};
let proof_value = serde_json::to_value(proof)?;
let mut object_value = serde_json::to_value(object)?;
let object_map = object_value.as_object_mut()
2022-10-23 23:46:51 +00:00
.ok_or(JsonSignatureError::InvalidObject)?;
2022-10-20 23:18:45 +00:00
object_map.insert("proof".to_string(), proof_value);
Ok(object_value)
}
#[cfg(test)]
mod tests {
use serde_json::json;
use crate::utils::crypto::generate_weak_private_key;
use super::*;
#[test]
fn test_sign_object() {
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 result = sign_object(&object, &signer_key, signer_key_id).unwrap();
2022-10-28 13:27:36 +00:00
assert_eq!(result["actor"], object["actor"]);
assert_eq!(result["object"], object["object"]);
let signature_date = result["proof"]["created"].as_str().unwrap();
// Put * in place of date to avoid escaping all curly brackets
let expected_result = r#"{"actor":"https://example.org/users/test","id":"https://example.org/objects/1","object":{"content":"test","type":"Note"},"proof":{"created":"*","proofPurpose":"assertionMethod","proofValue":"P4ye1hDvrGQCCClzHfCU9xobMAeqlUfgEWGlZfOTE3WmjH8JC/OJwlsjUMOUwTVlyKStp+AY+zzU4z6mjZN0Ug==","type":"JcsRsaSignature2022","verificationMethod":"https://example.org/users/test#main-key"},"to":["https://example.org/users/yyy","https://example.org/users/xxx"],"type":"Create"}"#;
2022-10-20 23:18:45 +00:00
assert_eq!(
2022-10-28 13:27:36 +00:00
serde_json::to_string(&result).unwrap(),
expected_result.replace('*', signature_date),
2022-10-20 23:18:45 +00:00
);
}
}