Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signing with Azure Key Vault #462

Closed
jachin84 opened this issue Jun 27, 2024 · 7 comments
Closed

Signing with Azure Key Vault #462

jachin84 opened this issue Jun 27, 2024 · 7 comments
Assignees

Comments

@jachin84
Copy link

I am using the guidance available here and here in an attempt to perform signing using an EC-P256 key stored in Azure Key Vault. I am able to sign the firmware but both signature and hash fail when using the firmware.

I have an EC-P256 (SECP256R1) key that is generated and storaged in Azure Key Vault. For more info see MS Docs.

Here are the steps I am using:

## Get the Public Key from Azure Key Vault
az keyvault key download --vault-name <vault-name> -n test-signing-key -e DER -f test-signin-key_pub.der

# Add the public key to the wolfBoot keystore using `keygen -i`
./keygen --ecc256 -i public-key.der

# Generate Hash to Sign
./sign --ecc256 --sha-only --sha256 test-app/image.bin public-key.der 1

# Call an external script to submit the hash to key vault.
# This script does the following:
#   1. Read the test-app/image_v1_digest.bin
#   2. Convert to Base64 Url Safe Encoding as described in [rfc7515 Appendix C](https://datatracker.ietf.org/doc/html/rfc7515#appendix-C)
#  3. Call the Key Vault Sign endpoint
#  4. Convert the signature returned by azure to a using the base64url decoding and write to disk as test-app/image_v1.sig

# Sign the file
./sign --ecc256 --sha256 --manual-sign test-app/image.bin test-signin-key_pub.der 1 test-app/image_v1.sig

The steps above don't produce an error. Trying to run the firmware fails though. Some further investigation shows that Azure is using non-deterministic signing and they return the signature as a IEEE-P1363 signature. My simplistic understanding is this is the r and s values concatenated together.

What format does the signature need to be in to work with the sign tool?

As a debugging step I tried this same process using just openssl to do the signing but this also fails.

# Create EC key file with Public Key
openssl ecparam -name prime256v1 -genkey -noout -out my_key.pem
openssl ec -in  my_key.pem -pubout -out  my_public_key.der

# Add the public key to the wolfBoot keystore using `keygen -i`
./tools/keytools/keygen ----ecc256 -i my_public_key.der

# Generate Hash to Sign
./tools/keytools/sign ----ecc256 --sha-only --sha256 test-app/image.bin my_public_key.der 1

# Sign hash Example (here is where you would use an HSM)
openssl pkeyutl -sign -keyform der -inkey my_key.der -in test-app/image_v1_digest.bin > test-app/image_v1.sig

# Generate final signed binary
./tools/keytools/sign ----ecc256 --sha256 --manual-sign test-app/image.bin my_public_key.der 1 test-app/image_v1.sig

Any assistance you could provide on using a Cloud based HSM like Azure Key Vault would be much appreciated. I suspect the signature format from Azure is the issue but the fact that using just openssl to do the signing also fails make me think I've missed something. Thanks in advance.

@danielinux
Copy link
Member

Hi @jachin84
Your procedure looks correct, except for the double public key. test-signin-key_pub.der and public-key.der should be the same file. I'm assuming it's a c/p mistake.

The .sig file, if in the correct format, should be exactly 64B in size. Can you confirm that the public key imported by keygen is correct in the generated src/keystore.c? Have you ensured that wolfBoot has been linked with the correct public key in that file?

It might be that keygen -i is not importing the .DER of the public key properly. We had just included a few fixes in the keygen tool yesterday (see #461), and the changes may affect the import operation. Could you please also test with the latest keygen from master branch?

Thanks,

--
Daniele

@jachin84
Copy link
Author

Thanks @danielinux for the speedy reply. Yes, indeed a c/p error. I’ll pull the latest and try the process again in the morning. I suspect the changes in #461 will be part of the solution.

My signature from Key Vault is exactly 64B but I suspects it’s still wrong. The signature when using openssl is ASN.1 DER but Key Vault is P1363. What encoding does sign expect the signature to be in?

@danielinux
Copy link
Member

The format of the .sig file is raw encoding, meaning that it contains a concatenation of two big-endian integers of fixed size (key size, 32B each in case of ecc256). If the signature is contained in a DER structure instead, the resulting .sig file would vary in size but it would be > 64

@jachin84
Copy link
Author

jachin84 commented Jun 27, 2024

Thanks @danielinux about to try this again now and will report back.

Is there a way that you know of to verify the hash/signature without trying to boot the firmware?

@danielinux
Copy link
Member

Nice, thank you. Let us know about your findings.

Is there a way that you know of to verify the hash/signature without trying to boot the firmware?

There is a synthetic, simulated target that compiles wolfboot as ELF command line application. You can copy the .config file from config/examples/sim.config , adjust SIGN=ECC256, disable WOLFBOOT_SMALL_STACK. make will create wolfBoot.elf, containing the same keystore.c as the actual target board bootloader.

You can then run wolfBoot.elf get_version and if the test image is authenticated it will print its version, or a detailed error otherwise. Check the internal_flash.dd target inside Makefile to see how we create a simulated flash image that contains a signed image using the binassemble tool we provide, and replace the signing step with your custom HSM loop.

@jachin84
Copy link
Author

Thanks again for the assistance. We got this working in the end. For anyone else interested in how to sign with Key Vault.

##Helper functions
# base64url encode
function base64url_encode {
  (if [ -z "$1" ]; then cat -; else echo -n "$1"; fi) |
    openssl base64 -e -A |
      sed s/\\+/-/g |
      sed s/\\//_/g |
      sed -E s/=+$//
}

# base64url decode
function base64url_decode {
  INPUT=$(if [ -z "$1" ]; then echo -n $(cat -); else echo -n "$1"; fi)
  MOD=$(($(echo -n "$INPUT" | wc -c) % 4))
  PADDING=$(if [ $MOD -eq 2 ]; then echo -n '=='; elif [ $MOD -eq 3 ]; then echo -n '=' ; fi)
  echo -n "$INPUT$PADDING" |
    sed s/-/+/g |
    sed s/_/\\//g |
    openssl base64 -d -A
}

## Get the Public Key from Azure Key Vault
az keyvault key download --vault-name <vault-name> -n test-signing-key -e DER -f public-key.der

# Add the public key to the wolfBoot keystore using `keygen -i`
./keygen --ecc256 -i public-key.der

# Generate Hash to Sign
./sign --ecc256 --sha-only --sha256 test-app/image.bin public-key.der 1

DIGEST=$(cat test-app/image_v1_digest.bin | base64url_encode)
echo "The sha256 digest (base64url encoded) is: $DIGEST"

# Get an access token for Key Vault
ACCESS_TOKEN=$(az account get-access-token --resource "https://vault.azure.net" --query "accessToken" -o tsv)
KEY_IDENTIFIER="https://<vault-name>.vault.azure.net/keys/test-signing-key"

SIGNING_RESULT=$(curl -X POST \
    -s "${KEY_IDENTIFIER}/sign?api-version=7.4" \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H "Content-Type:application/json" \
    -H "Accept:application/json" \
    -d "{\"alg\":\"ES256\",\"value\":\"${DIGEST}\"}")
echo $SIGNING_RESULT
SIGNATURE=$(jq -jn "$SIGNING_RESULT|.value")
echo $SIGNATURE
echo $SIGNATURE| base64url_decode > test-app/image_v1_digest.sig

# Sign the file
./sign --ecc256 --sha256 --manual-sign test-app/image.bin test-signin-key_pub.der 1 test-app/image_v1_digest.sig

@dgarske
Copy link
Contributor

dgarske commented Jul 1, 2024

Thank you @jachin84 for this information!
@danielinux perhaps we can add a README Signing.md section for how to sign with Azure Key Vault?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants