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 configurationpull/127/head
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