@instun/sm2-multikey
Version:
A JavaScript library for generating and working with SM2Multikey key pairs and digital signatures. Compatible with both Node.js and fibjs runtimes.
662 lines (629 loc) • 18.3 kB
JavaScript
/*!
* Copyright (c) 2024 Instun, Inc. All rights reserved.
*/
/**
* @fileoverview Proof Purpose Management for SM2 Digital Signatures
*
* This module implements the W3C Verifiable Credentials proof purpose model,
* providing a framework for validating the intended usage of digital signatures.
* It ensures that signatures are used appropriately within their intended context
* and authorization scope.
*
* Key Features:
* - Extensible proof purpose framework
* - W3C standard purpose implementations
* - DID-based verification
* - Capability validation
* - Chain of trust verification
*
* Security Considerations:
* - Strict verification method validation
* - Capability chain verification
* - Status and revocation checking
* - Purpose scope enforcement
* - Authorization validation
*
* Performance Notes:
* - Lazy DID document loading
* - Efficient chain validation
* - Cached verification results
* - Early validation failures
*
* Usage Example:
* ```javascript
* import { createProofPurpose } from './purposes.js';
*
* // Create a proof purpose for authentication
* const purpose = createProofPurpose('authentication');
*
* // Validate a proof
* try {
* const isValid = purpose.validate(proof, document, {
* verificationMethod: 'did:example:123#key-1'
* });
* console.log('Proof is valid:', isValid);
* } catch (error) {
* console.error('Validation failed:', error.message);
* }
* ```
*
* Standards Compliance:
* - W3C Verifiable Credentials Data Model
* - W3C Decentralized Identifiers (DIDs)
* - W3C Linked Data Proofs
* - IETF OAuth 2.0 Capability Tokens
* - GM/T 0009-2012: SM2 Digital Signature Algorithm
*
* @module purposes
* @see {@link https://w3c.github.io/vc-data-model/#proof-purposes}
* @see {@link https://w3c.github.io/did-core/}
* @see {@link https://w3c-ccg.github.io/ld-proofs/}
*/
import { ArgumentError, OperationError, VerificationError } from '../core/errors.js';
/**
* Base class for all proof purposes
*
* This abstract class provides the foundation for implementing different proof
* purposes as defined in the W3C Verifiable Credentials specification. It
* establishes a common interface and shared functionality for all purpose types.
*
* Processing Steps:
* 1. Parameter validation
* 2. Purpose term verification
* 3. Proof structure validation
* 4. Verification method validation
*
* Security Considerations:
* - Input validation for all parameters
* - Purpose term verification
* - Error isolation and handling
* - Type safety enforcement
*
* Performance Notes:
* - Early parameter validation
* - Minimal object creation
* - Efficient error handling
* - Reusable validation logic
*
* @abstract
* @class
*/
export class ProofPurpose {
/**
* Create a new proof purpose
*
* Initializes a proof purpose with its identifying term. The term is used
* to match against proof declarations and determine validation rules.
*
* @param {string} term - The proof purpose term (e.g., 'assertionMethod')
* @throws {ArgumentError} If term is not a non-empty string
*
* @example
* ```javascript
* class CustomPurpose extends ProofPurpose {
* constructor() {
* super('customPurpose');
* }
* }
* ```
*/
constructor(term) {
if (!term || typeof term !== 'string') {
throw new ArgumentError(
'term must be a string',
'E_INVALID_TERM'
);
}
this.term = term;
}
/**
* Validate a proof against its stated purpose
*
* This method performs basic validation common to all proof purposes.
* Subclasses should extend this method to add purpose-specific validation
* logic while maintaining the base validation guarantees.
*
* Processing Steps:
* 1. Validate input parameters
* 2. Check proof structure
* 3. Verify purpose declaration
* 4. Match purpose term
*
* Security Considerations:
* - Type checking for all inputs
* - Null/undefined handling
* - Purpose term validation
* - Error isolation
*
* Performance Notes:
* - Early validation failures
* - Minimal object access
* - Reusable validation
* - Efficient error creation
*
* @param {object} proof - The proof to validate
* @param {object} document - The document being proved
* @param {object} [options={}] - Additional validation options
* @returns {boolean} True if validation succeeds
* @throws {ArgumentError} If parameters are invalid
* @throws {VerificationError} If validation fails
*
* @example
* ```javascript
* const purpose = new ProofPurpose('test');
* try {
* const isValid = purpose.validate({
* type: 'SM2Signature2024',
* purpose: 'test',
* verificationMethod: 'did:example:123#key-1'
* }, document);
* console.log('Validation result:', isValid);
* } catch (error) {
* console.error('Validation failed:', error);
* }
* ```
*/
validate(proof, document, options = {}) {
if (!proof || typeof proof !== 'object') {
throw new ArgumentError(
'proof must be an object',
'E_INVALID_PROOF'
);
}
if (!document || typeof document !== 'object') {
throw new ArgumentError(
'document must be an object',
'E_INVALID_DOCUMENT'
);
}
if (typeof options !== 'object') {
throw new ArgumentError(
'options must be an object',
'E_INVALID_OPTIONS'
);
}
// Verify proof.purpose or proof.proofPurpose
const purpose = proof.purpose || proof.proofPurpose;
if (!purpose) {
throw new VerificationError(
'proof purpose not found',
'E_PURPOSE_MISSING'
);
}
if (purpose !== this.term) {
throw new VerificationError(
`proof purpose must be "${this.term}"`,
'E_PURPOSE_MISMATCH'
);
}
return true;
}
}
/**
* Proof purpose for making assertions about a subject
*
* This purpose is used when a subject is making verifiable claims or
* statements. It verifies that the signing key is authorized for making
* assertions in the subject's DID document through the assertionMethod
* relationship.
*
* Processing Steps:
* 1. Base validation (ProofPurpose)
* 2. Verification method presence
* 3. DID document resolution
* 4. assertionMethod verification
* 5. Status validation
*
* Security Considerations:
* - DID document integrity
* - Key authorization scope
* - Status verification
* - Chain of trust validation
*
* Performance Notes:
* - Cached DID resolution
* - Early validation exit
* - Minimal parsing
* - Efficient lookups
*
* Common Use Cases:
* - Issuing verifiable credentials
* - Making verifiable presentations
* - Creating verifiable statements
* - Signing data objects
*
* @extends ProofPurpose
*
* @example
* ```javascript
* const purpose = new AssertionMethod();
* const isValid = purpose.validate(proof, document, {
* verificationMethod: 'did:example:123#key-1',
* documentLoader: customLoader
* });
* ```
*/
export class AssertionMethod extends ProofPurpose {
constructor() {
super('assertionMethod');
}
/**
* Validate proof purpose
*
* @param {object} proof - signature proof
* @param {object} document - document to be validated
* @param {object} options - validation options
* @returns {boolean} validation result
* @throws {VerificationError} if validation fails
*/
validate(proof, document, options) {
super.validate(proof, document, options);
if (!proof.verificationMethod) {
throw new VerificationError(
'verificationMethod not found',
'E_VERIFICATION_METHOD_MISSING'
);
}
// TODO: Implement DID document parsing and verification
// 1. Parse verificationMethod
// 2. Verify if verificationMethod is in the DID document's assertionMethod list
// 3. Verify verificationMethod status (expiration, revocation, etc.)
return true;
}
}
/**
* Proof purpose for authentication
*
* This purpose is used when proving control over an identity through the
* authentication relationship in a DID document. It ensures that the
* signing key is explicitly authorized for authentication purposes.
*
* Processing Steps:
* 1. Base validation (ProofPurpose)
* 2. Verification method presence
* 3. DID document resolution
* 4. Authentication verification
* 5. Status validation
*
* Security Considerations:
* - Identity verification
* - Key authorization scope
* - Challenge verification
* - Replay protection
*
* Performance Notes:
* - Cached authentication checks
* - Minimal DID resolution
* - Efficient key lookup
* - Quick validation path
*
* Common Use Cases:
* - Identity verification
* - Login/authentication flows
* - Challenge-response protocols
* - Session establishment
*
* @extends ProofPurpose
*
* @example
* ```javascript
* const purpose = new Authentication();
* const isValid = purpose.validate(proof, document, {
* challenge: 'abc123',
* domain: 'example.com'
* });
* ```
*/
export class Authentication extends ProofPurpose {
constructor() {
super('authentication');
}
/**
* Validate proof purpose
*
* @param {object} proof - signature proof
* @param {object} document - document to be validated
* @param {object} options - validation options
* @returns {boolean} validation result
* @throws {VerificationError} if validation fails
*/
validate(proof, document, options) {
super.validate(proof, document, options);
if (!proof.verificationMethod) {
throw new VerificationError(
'verificationMethod not found',
'E_VERIFICATION_METHOD_MISSING'
);
}
// TODO: Implement DID document parsing and verification
// 1. Parse verificationMethod
// 2. Verify if verificationMethod is in the DID document's authentication list
// 3. Verify verificationMethod status (expiration, revocation, etc.)
return true;
}
}
/**
* Proof purpose for key agreement
*
* This purpose is used for establishing shared secrets and secure
* communication channels through the keyAgreement relationship in
* a DID document. It verifies key authorization for encryption
* and key exchange operations.
*
* Processing Steps:
* 1. Base validation (ProofPurpose)
* 2. Verification method presence
* 3. DID document resolution
* 4. keyAgreement verification
* 5. Key type validation
*
* Security Considerations:
* - Key agreement protocol
* - Forward secrecy
* - Key freshness
* - Protocol binding
*
* Performance Notes:
* - Efficient key validation
* - Minimal protocol overhead
* - Cached DID lookups
* - Quick failure paths
*
* Common Use Cases:
* - Establishing encrypted channels
* - Key exchange protocols
* - Secure messaging setup
* - End-to-end encryption
*
* @extends ProofPurpose
*
* @example
* ```javascript
* const purpose = new KeyAgreement();
* const isValid = purpose.validate(proof, document, {
* verificationMethod: 'did:example:123#key-1',
* keyType: 'SM2'
* });
* ```
*/
export class KeyAgreement extends ProofPurpose {
constructor() {
super('keyAgreement');
}
/**
* Validate proof purpose
*
* @param {object} proof - signature proof
* @param {object} document - document to be validated
* @param {object} options - validation options
* @returns {boolean} validation result
* @throws {VerificationError} if validation fails
*/
validate(proof, document, options) {
super.validate(proof, document, options);
if (!proof.verificationMethod) {
throw new VerificationError(
'verificationMethod not found',
'E_VERIFICATION_METHOD_MISSING'
);
}
// TODO: Implement DID document parsing and verification
// 1. Parse verificationMethod
// 2. Verify if verificationMethod is in the DID document's keyAgreement list
// 3. Verify verificationMethod status (expiration, revocation, etc.)
return true;
}
}
/**
* Proof purpose for capability invocation
*
* This purpose is used when exercising authorized capabilities through
* the capabilityInvocation relationship. It verifies the authorization
* to invoke a capability and validates the entire capability chain.
*
* Processing Steps:
* 1. Base validation (ProofPurpose)
* 2. Verification method presence
* 3. DID document resolution
* 4. Capability chain validation
* 5. Invocation verification
*
* Security Considerations:
* - Capability chain integrity
* - Authorization scope
* - Delegation depth
* - Revocation status
*
* Performance Notes:
* - Cached chain validation
* - Efficient graph traversal
* - Quick authorization check
* - Minimal recursion
*
* Common Use Cases:
* - Exercising delegated permissions
* - Accessing controlled resources
* - Executing authorized actions
* - API access control
*
* @extends ProofPurpose
*
* @example
* ```javascript
* const purpose = new CapabilityInvocation();
* const isValid = purpose.validate(proof, document, {
* capability: 'did:example:123/capabilities/1',
* action: 'read'
* });
* ```
*/
export class CapabilityInvocation extends ProofPurpose {
constructor() {
super('capabilityInvocation');
}
/**
* Validate proof purpose
*
* @param {object} proof - signature proof
* @param {object} document - document to be validated
* @param {object} options - validation options
* @returns {boolean} validation result
* @throws {VerificationError} if validation fails
*/
validate(proof, document, options) {
super.validate(proof, document, options);
if (!proof.verificationMethod) {
throw new VerificationError(
'verificationMethod not found',
'E_VERIFICATION_METHOD_MISSING'
);
}
// TODO: Implement DID document parsing and verification
// 1. Parse verificationMethod
// 2. Verify if verificationMethod is in the DID document's capabilityInvocation list
// 3. Verify verificationMethod status (expiration, revocation, etc.)
// 4. Verify capability chain
return true;
}
}
/**
* Proof purpose for capability delegation
*
* This purpose is used when delegating capabilities to others through
* the capabilityDelegation relationship. It verifies the authority
* to delegate capabilities and validates the delegation chain.
*
* Processing Steps:
* 1. Base validation (ProofPurpose)
* 2. Verification method presence
* 3. DID document resolution
* 4. Delegation chain validation
* 5. Authority verification
*
* Security Considerations:
* - Delegation authority
* - Chain of trust
* - Scope limitations
* - Revocation handling
*
* Performance Notes:
* - Efficient chain traversal
* - Cached authority checks
* - Quick validation path
* - Minimal recursion
*
* Common Use Cases:
* - Delegating permissions
* - Creating capability chains
* - Authorization transfer
* - Access management
*
* @extends ProofPurpose
*
* @example
* ```javascript
* const purpose = new CapabilityDelegation();
* const isValid = purpose.validate(proof, document, {
* delegator: 'did:example:123',
* scope: ['read', 'write']
* });
* ```
*/
export class CapabilityDelegation extends ProofPurpose {
constructor() {
super('capabilityDelegation');
}
/**
* Validate proof purpose
*
* @param {object} proof - signature proof
* @param {object} document - document to be validated
* @param {object} options - validation options
* @returns {boolean} validation result
* @throws {VerificationError} if validation fails
*/
validate(proof, document, options) {
super.validate(proof, document, options);
if (!proof.verificationMethod) {
throw new VerificationError(
'verificationMethod not found',
'E_VERIFICATION_METHOD_MISSING'
);
}
// TODO: Implement DID document parsing and verification
// 1. Parse verificationMethod
// 2. Verify if verificationMethod is in the DID document's capabilityDelegation list
// 3. Verify verificationMethod status (expiration, revocation, etc.)
// 4. Verify delegation chain
return true;
}
}
/**
* Factory function to create proof purpose instances
*
* This function instantiates the appropriate proof purpose class based
* on the provided term. It provides a convenient way to create purpose
* instances while ensuring proper initialization and validation.
*
* Processing Steps:
* 1. Validate input term
* 2. Match purpose type
* 3. Create instance
* 4. Validate creation
*
* Security Considerations:
* - Input validation
* - Type safety
* - Instance validation
* - Error handling
*
* Performance Notes:
* - Single instance creation
* - Minimal validation
* - Quick type matching
* - Efficient error paths
*
* Supported Terms:
* - assertionMethod: For making verifiable claims
* - authentication: For identity verification
* - keyAgreement: For secure key exchange
* - capabilityInvocation: For using capabilities
* - capabilityDelegation: For delegating capabilities
*
* @param {string} term - The proof purpose term
* @returns {ProofPurpose} An instance of the appropriate proof purpose class
* @throws {OperationError} If the term is not supported
*
* @example
* ```javascript
* // Create an authentication purpose
* const authPurpose = createProofPurpose('authentication');
*
* // Create a capability invocation purpose
* const capPurpose = createProofPurpose('capabilityInvocation');
*
* // Validate a proof
* const isValid = authPurpose.validate(proof, document, {
* verificationMethod: 'did:example:123#key-1'
* });
* ```
*/
export function createProofPurpose(term) {
switch (term) {
case 'assertionMethod':
return new AssertionMethod();
case 'authentication':
return new Authentication();
case 'keyAgreement':
return new KeyAgreement();
case 'capabilityInvocation':
return new CapabilityInvocation();
case 'capabilityDelegation':
return new CapabilityDelegation();
default:
throw new OperationError(
`unsupported proof purpose: ${term}`,
'E_UNSUPPORTED_PURPOSE'
);
}
}