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