#!/bin/bash # Check for required commands for cmd in openssl xxd jq curl base64; do if ! command -v $cmd &> /dev/null; then echo "Error: $cmd is not installed. Please install it first." echo "On Arch Linux: sudo pacman -S $cmd" exit 1 fi done # Load environment variables if [ -f .env ]; then export $(cat .env | grep -v '^#' | xargs) fi # Default values 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/v2/claim"} # Function to generate a new keypair generate_keypair() { echo "Generating new keypair..." # Create a temporary directory for key operations TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' EXIT # Generate private key openssl ecparam -name secp256k1 -genkey -noout > "$TMPDIR/private.pem" # Extract raw private key PRIVATE_KEY=$(openssl ec -in "$TMPDIR/private.pem" -text -noout 2>/dev/null | \ grep priv -A 3 | tail -n +2 | \ tr -d '\n[:space:]:' | \ sed 's/^00//') # Generate public key (compressed format) PUBLIC_KEY=$(openssl ec -in "$TMPDIR/private.pem" -pubout -outform DER 2>/dev/null | \ tail -c 65 | \ xxd -p -c 65 | \ sed 's/^04/02/') # Generate Ethereum address ADDRESS=$(echo -n "$PUBLIC_KEY" | \ xxd -r -p | \ openssl dgst -sha3-256 -binary | \ tail -c 20 | \ xxd -p) # Create DID DID="did:ethr:0x$ADDRESS" echo "Generated DID Details:" echo "----------------------" echo "DID: $DID" echo "Address: 0x$ADDRESS" echo "Private Key: $PRIVATE_KEY" echo "Public Key: $PUBLIC_KEY" # Export variables for other functions export DID PRIVATE_KEY PUBLIC_KEY ADDRESS return 0 } # Function to hex_to_dec hex_to_dec() { printf "%d" "0x$1" } # Function to create and sign JWT create_jwt() { local now=$(date +%s) local exp=$((now + 300)) # Create header (compact JSON) local header='{"typ":"JWT","alg":"ES256K"}' # Create registration claim (compact JSON) local claim="{\"iat\":$now,\"exp\":$exp,\"sub\":\"RegisterAction\",\"vc\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\"],\"credentialSubject\":{\"@context\":\"https://schema.org\",\"@type\":\"RegisterAction\",\"agent\":{\"did\":\"$ADMIN_DID\"},\"participant\":{\"did\":\"$DID\"},\"object\":\"endorser.ch\"}},\"iss\":\"$ADMIN_DID\"}" # Base64url encode header and claim header_b64=$(echo -n "$header" | base64 -w 0 | tr '/+' '_-' | tr -d '=') claim_b64=$(echo -n "$claim" | base64 -w 0 | tr '/+' '_-' | tr -d '=') # Create message to sign message="$header_b64.$claim_b64" # Create temporary directory for key operations TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' EXIT # Create private key PEM file 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 echo -n "$message" > "$TMPDIR/message.txt" # Sign message and get DER format signature openssl dgst -sha256 -sign "$TMPDIR/private.pem" "$TMPDIR/message.txt" 2>/dev/null > "$TMPDIR/signature.der" # Convert DER signature to R+S format der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der") # Debug the full DER signature echo "Debug - Full DER signature:" echo "$der_sig" # Parse DER structure - more robust version 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 seq_len="${BASH_REMATCH[1]}" r_len="${BASH_REMATCH[2]}" r_val="${BASH_REMATCH[3]}" s_len="${BASH_REMATCH[4]}" s_val="${BASH_REMATCH[5]}" echo "Debug - DER parsing:" echo "Sequence length: $seq_len" echo "R length: $r_len" echo "R value: $r_val" echo "S length: $s_len" echo "S value: $s_val" # Remove leading zeros if present r_val=${r_val#"00"} s_val=${s_val#"00"} # Pad R and S to 32 bytes each r_val=$(printf "%064s" "$r_val" | tr ' ' '0') s_val=$(printf "%064s" "$s_val" | tr ' ' '0') # Concatenate R+S and convert to base64url signature=$(echo -n "${r_val}${s_val}" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=') else echo "Error: Invalid DER signature format" echo "DER: $der_sig" return 1 fi # Create final JWT JWT="$message.$signature" echo -e "\nCreated JWT: ${JWT:0:50}..." export JWT return 0 } # Function to register DID register_did() { echo "Attempting registration..." # Create request body body="{\"jwtEncoded\":\"$JWT\"}" # Send registration request response=$(curl -s -X POST "$API_URL" \ -H "Content-Type: application/json" \ -d "$body") # Check response if echo "$response" | jq -e '.success' >/dev/null 2>&1; then echo "Registration successful!" echo "Response:" echo "$response" | jq '.' else echo "Registration failed!" echo "Error: $(echo "$response" | jq -r '.error.message // empty')" echo "Full response:" echo "$response" | jq '.' || echo "$response" fi } # Main execution echo "Starting DID Generation..." echo "Using admin DID: $ADMIN_DID" echo "API URL: $API_URL" generate_keypair && \ create_jwt && \ register_did exit $?