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.
189 lines
5.9 KiB
189 lines
5.9 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"}
|
|
|
|
# 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 $?
|