You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

266 lines
8.3 KiB

#!/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"}
DEBUG=${DEBUG:-0}
# Function to log debug info
debug_log() {
if [ "$DEBUG" = "1" ]; then
echo "$@" >&2
fi
}
# Function to generate a new keypair
generate_keypair() {
debug_log "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"
# Print debug info if enabled
debug_log "Generated DID Details:"
debug_log "----------------------"
debug_log "DID: $DID"
debug_log "Address: $ADDRESS"
debug_log "Private Key: $PRIVATE_KEY"
debug_log "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 attempt signing with retries
attempt_signing() {
local max_attempts=5
local attempt=1
while [ $attempt -le $max_attempts ]; do
debug_log "Signing attempt $attempt of $max_attempts..."
# 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 hex
der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der")
debug_log "Debug - Full DER signature:"
debug_log "$der_sig"
# Parse DER structure with length checking
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]}"
# Convert lengths to decimal
r_len_dec=$((16#$r_len))
s_len_dec=$((16#$s_len))
debug_log "R length: $r_len_dec bytes"
debug_log "S length: $s_len_dec bytes"
# Handle R value
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
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
# Validate final lengths
if [ ${#r_val} -eq 64 ] && [ ${#s_val} -eq 64 ]; then
debug_log "Valid signature found on attempt $attempt"
return 0
fi
fi
debug_log "Invalid signature on attempt $attempt, retrying..."
attempt=$((attempt + 1))
done
echo "Failed to generate valid signature after $max_attempts attempts" >&2
return 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"
# Attempt signing with retries
if attempt_signing; then
# Create final JWT
concat_sig="${r_val}${s_val}"
signature=$(echo -n "$concat_sig" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=')
JWT="$message.$signature"
debug_log "Created JWT: ${JWT:0:50}..."
export JWT
return 0
else
echo "Failed to generate valid signature" >&2
return 1
fi
}
# Function to register DID
register_did() {
debug_log "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
debug_log "Registration successful!"
debug_log "Response: $(echo "$response" | jq -c '.')"
# Output only the JSON result
debug_log "About to output JSON..."
jq -n \
--arg did "$DID" \
--arg private_key "$PRIVATE_KEY" \
--arg registration_id "$(echo "$response" | jq -r '.success.registrationId')" \
--arg claim_id "$(echo "$response" | jq -r '.success.claimId')" \
'{
status: "success",
did: $did,
privateKey: $private_key,
registrationId: $registration_id,
claimId: $claim_id
}'
debug_log "JSON output complete"
exit 0
else
error_msg=$(echo "$response" | jq -r '.error.message // "Unknown error"')
debug_log "Registration failed: $error_msg"
debug_log "Full response: $(echo "$response" | jq -c '.' || echo "$response")"
# Output error as JSON
jq -n \
--arg error "$error_msg" \
--arg stage "registration" \
'{
status: "error",
stage: $stage,
error: $error
}'
exit 1
fi
}
# Main execution
debug_log "Starting DID Generation..."
debug_log "Using admin DID: $ADMIN_DID"
debug_log "API URL: $API_URL"
if ! generate_keypair; then
jq -n '{
status: "error",
stage: "keypair",
error: "Failed to generate keypair"
}'
exit 1
fi
if ! create_jwt; then
jq -n '{
status: "error",
stage: "jwt",
error: "Failed to generate valid signature"
}'
exit 1
fi
register_did