Signature verification

The chapter describes signature verification algorithm with a list and description of the methods used to download public signature keys.

List of methods


Signature verification

 

Signature verification algorithm:

  1. Recipient receives signed request with headers:

    1. x-signature - signature

    2. x-signature-timestamp - ISO8601 datetime string in UTC timezone with time of signature generation ex. 2023-05-11T15:02:23.429Z

    3. x-public-key-ver - version of keys used to generate signature

    4. x-public-key-hash - SHA-256 hash of public key used to generate signature

  2. Recipient checks if already have cached public key with given version

    1. key present in cache:

      • recipient checks if public key hash matches calculated as: SHA-256 hash from public_key_base64 field. if verification is:

        • positive - continue

        • negative - reject request with http: 401 {   "error_code": "INVALID_SIGNATURE",   "error_message": "error description" }

    2. key not present in cache:

      • obtain public key from /v1/izi/signing-keys/public/{keyVersion} or /api/v1/izi/signing-keys/public and verify hash as above

  3. Prepare base64 string that consists of DIGEST,external-merchant-id,x-public-key-ver,x-signature-timestamp. Values are separated with commas

    1. x-public-key-ver, x-signature-timestamp from headers, use empty value if header is missing.

    2. merchant_external_id value comes from endpoints /v1/izi/signing-keys/public/{keyVersion} and /v1/izi/signing-keys/public as merchant_external_id field

    3. DIGEST: base64 form of SHA-256 hash (Message Digest) generated from request body. Use empty byte array as request body if body is missing.

  4. Decode base64 signature and verify it with the SHA256withRSA algorithm for the given public key and signature string. If verification:

    1. positive - continue

    2. negative - reject request with http: 401 {   "error_code": "INVALID_SIGNATURE",   "error_message": "error description" }

  5. Recipient compares x-signature-timestamp value to current time. If difference is:

    1. less or equal to 240s - continue

    2. bigger than 240s - reject request with http: 401 {   "error_code": "INVALID_SIGNATURE",   "error_message": "error description" }

 

Manual signature verification:

  • curl --location 'http://{basket-app-host}/basket-app/api/v1/izi/signing-keys/public/{keyVersion}' replace {Unknown macro: { {keyVersion}}}

    with value from header: x-public-key-ver

  • echo "$PUBLIC_KEY_BASE64" | openssl base64 -d -A | openssl rsa -pubin -inform DER -outform PEM -out pubkey.pem replace $PUBLIC_KEY_BASE64 with value from field: public_key_base64

  • DIGEST=$(echo -n "$(<message_body)" | openssl dgst -sha256 -binary | openssl enc -base64 -A) where message_body is a file with EXACT request body (without any additions, whitespaces etc.)

  • echo -n "$DIGEST,$EXTERNAL_MERCHANT_ID,$KEY_VERSION,$SIGNATURE_TIMESTAMP" | openssl enc -base64 -A -out signature_string where $EXTERNAL_MERCHANT_ID value is from public key endpoint - field merchant_external_id, $KEY_VERSION value is from header x-public-key-ver and $SIGNATURE_TIMESTAMP value is from x-signature-timestamp

  • openssl enc -base64 -d -A -in request_signature -out signature.bin where request_signature is a file with value from header x-signature

  • openssl dgst -sha256 -verify pubkey.pem -signature signature.bin signature_string should print Verified OK