Browse Source
			
			
			
			
				
		Adds dids_seen.sh script to check DID visibility permissions in endorser.ch system. Key features: - JWT creation and signing using ES256K-R - DID visibility checking via API - Environment variable and .env file support - Debug logging with DEBUG=1 flag - Command line argument parsing for specific DID checks - Secure key handling with temporary files - Pretty-printed JSON output Security: - Uses secure temporary files with cleanup - Validates DER signature format - Handles key material securely - Supports environment variable configuration
				 1 changed files with 186 additions and 0 deletions
			
			
		| @ -0,0 +1,186 @@ | |||||
|  | #!/bin/bash | ||||
|  | # DID Visibility Check Script | ||||
|  | # @author Matthew Raymer | ||||
|  | # | ||||
|  | # This script checks visibility permissions for DIDs within the endorser.ch system. | ||||
|  | # It creates a signed JWT using admin credentials and queries the visibility API. | ||||
|  | # | ||||
|  | # Features: | ||||
|  | # - JWT creation and signing using ES256K-R | ||||
|  | # - DID visibility checking | ||||
|  | # - Environment variable support | ||||
|  | # - Debug logging | ||||
|  | # - Command line argument parsing | ||||
|  | # | ||||
|  | # Usage: | ||||
|  | #   ./dids_seen.sh [-d did_to_check] | ||||
|  | #   DEBUG=1 ./dids_seen.sh  # For debug output | ||||
|  | # | ||||
|  | # Environment Variables: | ||||
|  | #   ADMIN_DID          - Admin DID for authorization | ||||
|  | #   ADMIN_PRIVATE_KEY  - Private key for signing | ||||
|  | #   ENDORSER_API_URL   - API endpoint (defaults to test) | ||||
|  | #   DEBUG              - Enable debug logging when set to 1 | ||||
|  | 
 | ||||
|  | # Add debug logging function | ||||
|  | debug_log() { | ||||
|  |     if [ "${DEBUG:-0}" = "1" ]; then | ||||
|  |         echo "DEBUG: $*" >&2 | ||||
|  |     fi | ||||
|  | } | ||||
|  | 
 | ||||
|  | # Parse command line arguments | ||||
|  | # -d: Specific DID to check visibility for | ||||
|  | CHECK_DID="" | ||||
|  | while getopts "d:" opt; do | ||||
|  |     case $opt in | ||||
|  |         d) CHECK_DID="$OPTARG" ;; | ||||
|  |         \?) echo "Usage: $0 [-d did_to_check]" >&2; exit 1 ;; | ||||
|  |     esac | ||||
|  | done | ||||
|  | 
 | ||||
|  | # Load environment variables from .env file if present | ||||
|  | # Supports: | ||||
|  | # - ADMIN_DID | ||||
|  | # - ADMIN_PRIVATE_KEY | ||||
|  | # - ENDORSER_API_URL | ||||
|  | if [ -f .env ]; then | ||||
|  |     export $(cat .env | grep -v '^#' | xargs) | ||||
|  | fi | ||||
|  | 
 | ||||
|  | # Default values for required parameters | ||||
|  | ADMIN_DID=${ADMIN_DID:-"did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"} | ||||
|  | ADMIN_PRIVATE_KEY=${ADMIN_PRIVATE_KEY:-"2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"} | ||||
|  | API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api/report/whichDidsICanSee"} | ||||
|  | 
 | ||||
|  | # Create JWT payload with: | ||||
|  | # - Issuer (iss) | ||||
|  | # - Subject (sub) | ||||
|  | # - Issued At (iat) | ||||
|  | # - Expiration (exp) | ||||
|  | now=$(date +%s) | ||||
|  | exp=$((now + 86400))  # 24 hours from now | ||||
|  | 
 | ||||
|  | payload=$(jq -n \ | ||||
|  |     --arg iss "$ADMIN_DID" \ | ||||
|  |     --arg sub "$ADMIN_DID" \ | ||||
|  |     --arg iat "$now" \ | ||||
|  |     --arg exp "$exp" \ | ||||
|  |     '{ | ||||
|  |         iss: $iss, | ||||
|  |         sub: $sub, | ||||
|  |         iat: ($iat | tonumber), | ||||
|  |         exp: ($exp | tonumber) | ||||
|  |     }') | ||||
|  | 
 | ||||
|  | # Base64url encode header and payload | ||||
|  | # Header specifies ES256K-R algorithm for Ethereum compatibility | ||||
|  | header='{"alg":"ES256K-R","typ":"JWT"}' | ||||
|  | header_b64=$(echo -n "$header" | base64 -w 0 | tr '/+' '_-' | tr -d '=') | ||||
|  | payload_b64=$(echo -n "$payload" | base64 -w 0 | tr '/+' '_-' | tr -d '=') | ||||
|  | 
 | ||||
|  | # Create message to sign (header.payload) | ||||
|  | message="$header_b64.$payload_b64" | ||||
|  | 
 | ||||
|  | # Create temporary directory for key operations | ||||
|  | # Uses trap to ensure cleanup on exit | ||||
|  | TMPDIR=$(mktemp -d) | ||||
|  | trap 'rm -rf "$TMPDIR"' EXIT | ||||
|  | 
 | ||||
|  | # Create private key PEM file | ||||
|  | # Converts raw private key to PEM format for OpenSSL | ||||
|  | echo "-----BEGIN EC PRIVATE KEY-----" > "$TMPDIR/private.pem" | ||||
|  | ( | ||||
|  |     echo "302e0201010420"  # Private key header | ||||
|  |     echo -n "$ADMIN_PRIVATE_KEY"  # Private key bytes | ||||
|  |     echo "a00706052b8104000a"  # secp256k1 OID | ||||
|  | ) | xxd -r -p | base64 >> "$TMPDIR/private.pem" | ||||
|  | echo "-----END EC PRIVATE KEY-----" >> "$TMPDIR/private.pem" | ||||
|  | 
 | ||||
|  | # Write message to file for signing | ||||
|  | echo -n "$message" > "$TMPDIR/message.txt" | ||||
|  | 
 | ||||
|  | # Sign message and get DER format signature | ||||
|  | openssl dgst -sha256 -sign "$TMPDIR/private.pem" "$TMPDIR/message.txt" > "$TMPDIR/signature.der" | ||||
|  | 
 | ||||
|  | # Convert DER signature to hex | ||||
|  | der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der") | ||||
|  | 
 | ||||
|  | # Parse DER structure | ||||
|  | # Extracts R and S values from signature | ||||
|  | if [[ $der_sig =~ ^30([0-9a-f]{2})02([0-9a-f]{2})([0-9a-f]*)02([0-9a-f]{2})([0-9a-f]*)$ ]]; then | ||||
|  |     r_len="${BASH_REMATCH[2]}" | ||||
|  |     r_val="${BASH_REMATCH[3]}" | ||||
|  |     s_len="${BASH_REMATCH[4]}" | ||||
|  |     s_val="${BASH_REMATCH[5]}" | ||||
|  |      | ||||
|  |     # Convert lengths to decimal | ||||
|  |     r_len_dec=$((16#$r_len)) | ||||
|  |     s_len_dec=$((16#$s_len)) | ||||
|  |      | ||||
|  |     # Handle R value padding | ||||
|  |     if [ $r_len_dec -gt 32 ]; then | ||||
|  |         r_val=${r_val: -64}  # Take last 32 bytes | ||||
|  |     elif [ $r_len_dec -lt 32 ]; then | ||||
|  |         r_val=$(printf "%064s" "$r_val" | tr ' ' '0')  # Left pad | ||||
|  |     fi | ||||
|  |      | ||||
|  |     # Handle S value padding | ||||
|  |     if [ $s_len_dec -gt 32 ]; then | ||||
|  |         s_val=${s_val: -64}  # Take last 32 bytes | ||||
|  |     elif [ $s_len_dec -lt 32 ]; then | ||||
|  |         s_val=$(printf "%064s" "$s_val" | tr ' ' '0')  # Left pad | ||||
|  |     fi | ||||
|  |      | ||||
|  |     # Create final signature | ||||
|  |     concat_sig="${r_val}${s_val}" | ||||
|  |      | ||||
|  |     # Calculate recovery bit (v) | ||||
|  |     # Try each possible recovery value (0-3) until we find one that works | ||||
|  |     for v in {0..3}; do | ||||
|  |         recovery_sig=$(printf "%s%02x" "$concat_sig" "$v") | ||||
|  |         debug_log "Trying recovery bit $v: $recovery_sig" | ||||
|  |          | ||||
|  |         # Convert to base64url | ||||
|  |         signature=$(echo -n "$recovery_sig" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=') | ||||
|  |          | ||||
|  |         # Create JWT with this signature | ||||
|  |         JWT="$message.$signature" | ||||
|  |          | ||||
|  |         # Test the JWT against the API | ||||
|  |         response=$(curl -s -X GET "$API_URL" \ | ||||
|  |              -H "Content-Type: application/json" \ | ||||
|  |              -H "Authorization: Bearer $JWT") | ||||
|  |          | ||||
|  |         # Check if the JWT worked | ||||
|  |         if ! echo "$response" | grep -q "JWT_VERIFY_FAILED"; then | ||||
|  |             echo "JWT Token:" | ||||
|  |             echo "$JWT" | ||||
|  |             echo | ||||
|  |             echo "Export command:" | ||||
|  |             echo "export TOKEN='$JWT'" | ||||
|  |             echo | ||||
|  |             if [ -n "$CHECK_DID" ]; then | ||||
|  |                 # Check if specific DID is in the list | ||||
|  |                 if echo "$response" | jq -e --arg did "$CHECK_DID" 'contains([$did])' > /dev/null; then | ||||
|  |                     echo "✅ DID $CHECK_DID is in the list" | ||||
|  |                     exit 0 | ||||
|  |                 else | ||||
|  |                     echo "❌ DID $CHECK_DID is not in the list" | ||||
|  |                     exit 1 | ||||
|  |                 fi | ||||
|  |             else | ||||
|  |                 # Show full list of visible DIDs | ||||
|  |                 echo "$response" | jq '.' --indent 2 | ||||
|  |             fi | ||||
|  |             exit 0 | ||||
|  |         fi | ||||
|  |     done | ||||
|  |      | ||||
|  |     echo "Error: Could not find valid recovery bit" | ||||
|  |     exit 1 | ||||
|  | else | ||||
|  |     echo "Error: Invalid DER signature format" | ||||
|  |     echo "DER: $der_sig" | ||||
|  |     exit 1 | ||||
|  | fi | ||||
					Loading…
					
					
				
		Reference in new issue