-
-
Save joostd/6a55084a7171214372b7ce3c5dc43dd5 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# step 1 - generate a new key pair on a YubiKey | |
yubico-piv-tool -a generate -s 9c -A ECCP256 -o pub.pem | |
# step 2 - generate data to be signed | |
jo iss=issuer aud=audience > payload.json | |
jo alg=ES256 typ=JWT > header.json | |
# base64-encode header and payload | |
basenc --base64url header.json | tr -d '\n=' > header.b64 | |
basenc --base64url payload.json | tr -d '\n=' > payload.b64 | |
echo -n . > dot | |
cat header.b64 dot payload.b64 > datatosign | |
# step 3 - sign using yubikey | |
yubico-piv-tool -a verify-pin --sign -s 9c -H SHA256 -A ECCP256 -i datatosign -o signature.der | |
# step 4 - verify | |
# verify using openssl | |
openssl dgst -sha256 -verify pub.pem -signature signature.der datatosign | |
# convert openssl signature | |
cat signature.der | openssl asn1parse -inform der | egrep -o '[A-F0-9]{62,64}' | xargs printf "%064s" | xxd -r -p | basenc --base64url | tr -d '\n=' > signature.b64 | |
# construct jwt | |
cat datatosign dot signature.b64 > token.jwt | |
# verify using step | |
cat token.jwt | step crypto jwt verify --key pub.pem --iss issuer --aud audience | |
# verify using jwt.io | |
echo "Open the following URL in your browser:" | |
echo "https://jwt.io/#debugger-io?token=$(cat token.jwt)&publicKey=$(jq -sRr @uri pub.pem)" |
Well, that greatly reduced the occurance, but the problem still exists, because the string can be just 60 characters if the first two bytes are zero, and so on.
I'm using the regex INTEGER\s*:([0-9A-F]*)
, even :([0-9A-F]*)
should do the job. The hex string is returned as group, but it seems egrep does not support to return a specific group, and returns the entire string, only. So, some more adjustment is necessary on the command line.
By the way, the credit goes to someone writing a comment(!) on StackExchange below an answer about asn1parse pointing to the sometimes too short hex strings. If I hadn't read the comments, I would wonder about the 1% failure rate at a customer, soon...
Another way is
cat signature.der | openssl asn1parse -inform der | tail -2 | sed -E 's/.*:([A-F0-9]+)/\1/' | xargs printf "%064s" | xxd -r -p | basenc --base64url | tr -d '\n=' > signature.b64
Still a kludge of course. This example is not intended to be used as is, just as a quick and dirty example of how to sign JWTs using YubiKeys. It should be easy to translate into something more robust in any programming language.
Ah, good catch!
That command doing the signature conversion is a bit of a kludge. Fixing it requires some extra ugliness:
I'll update the gist - thanks!