How to … Generate a Public Key for the Azure B2C Tenant to verify the JWT
In my last project, I got the requirement to deliver the Public Key for the Azure B2C Tenant so that they can use this to validate the JWT in the target System… UH... Okay, I figured out that there is no public Key available on the Frontend and other Endpoints. But it’s not impossible to generate a Key.
Get the required information
Fortunately Azure B2C will give you the required information to generate the identity just navigate to the URL
https://mytenant.b2clogin.com/{your_tenantname}/b2c_1_susi/discovery/v2.0/keys`
First, I will fetch the two operands, the modulus, and the exponent, from a JWKS (JSON Web Key Set). Here is a partial representation:
{
"keys": [
{
"kty": "RSA",
"kid": "K14p_n3IB1eTrez6cRjUWB0GOWc",
"use": "sig",
"n": "3bmGZLQSl3-wvGZVrZeI-HGz0XjB6F1lcwyxGRNl4GN3c7qHJyK5EiTqBNHKCQ76njmbERvIph8NlrH4G5l8tWUbB5z3vQYBkegc-fK0q7-QAZMJ9GglxjbppeIHpvYlk5G04CNedzyxA4SG2KNPdELgXYZDOVKtmd2jSSVys1P81H7olm1TS_3jTZP9PScY0t0fOibzzOFK7pdpfz6yjMt2FMLwMtLYNcZ2QaBRqFntNZ5biDiSsk60M5f_DwwAAKnDMZ5pT0qDeFMo8JQfhGMhr8a46oNXXbRmLXGUEytbiesQPVaTMpDkWqyxq_pOFhn2Er99i698YS6LNuZpeQ",
"e": "AQAB"
}
]
}
Where the n
the field stands for the modulus and the e
the field is the exponent.
Also, from that single JWK, one can observe that the type is RSA and that its purpose is to sign payloads. Refer to the RFC if any doubt 😄
If you were not sure, yes, based on these two attributes, one can compute the public key.
Let's assume these values are given:
export n="3bmGZLQSl3-wvGZVrZeI-HGz0XjB6F1lcwyxGRNl4GN3c7qHJyK5EiTqBNHKCQ76njmbERvIph8NlrH4G5l8tWUbB5z3vQYBkegc-fK0q7-QAZMJ9GglxjbppeIHpvYlk5G04CNedzyxA4SG2KNPdELgXYZDOVKtmd2jSSVys1P81H7olm1TS_3jTZP9PScY0t0fOibzzOFK7pdpfz6yjMt2FMLwMtLYNcZ2QaBRqFntNZ5biDiSsk60M5f_DwwAAKnDMZ5pT0qDeFMo8JQfhGMhr8a46oNXXbRmLXGUEytbiesQPVaTMpDkWqyxq_pOFhn2Er99i698YS6LNuZpeQ"export e="AQAB"
Base64 URL-decode the modulus. I suggest using that short bash script:
#!/usr/bin/env bash
# Encode to / decode from Base64-URL without padding.
# USAGE:
# bash base64url.sh encode 'Hello!'
# bash base64url.sh decode SGVsbG8h
function encode {
echo -n "$1" | openssl enc -a -A | tr -d '=' | tr '/+' '_-'
}
function decode {
_l=$((${#1} % 4))
if [ $_l -eq 2 ]; then _s="$1"'=='
elif [ $_l -eq 3 ]; then _s="$1"'='
else _s="$1" ; fi
echo "$_s" | tr '_-' '/+' | openssl enc -d -a -A
}
case $1 in
encode) encode "$2" ;;
decode) decode $2 ;;
e) encode "$2" ;;
d) decode $2 ;;
esac
Then call it
# chmod u+x decoder.sh./decoder.sh decode $n > modulus.bin
The next step is, that you must convert it to a hex code with this command:
xxd -ps -c 256 modulus.bin
Repeat the same operations for the exponent:
./decoder.sh decode $e > exponent.binxxd -ps -c 256 exponent.bin
Now it’s time to build a PEM file.
Building the PEM
Here, we will use openssl
commands and a ASN.1 definition file with our computed values inserted in.
# Start with a SEQUENCE
asn1=SEQUENCE:pubkeyinfo
# pubkeyinfo contains an algorithm identifier and the public key wrapped
# in a BIT STRING
[pubkeyinfo]
algorithm=SEQUENCE:rsa_alg
pubkey=BITWRAP,SEQUENCE:rsapubkey
# algorithm ID for RSA is just an OID and a NULL
[rsa_alg]
algorithm=OID:rsaEncryption
parameter=NULL
# Actual public key: modulus and exponent
[rsapubkey]
n=INTEGER:0xddb98664b412977fb0bc6655ad9788f871b3d178c1e85d65730cb1191365e0637773ba872722b91224ea04d1ca090efa9e399b111bc8a61f0d96b1f81b997cb5651b079cf7bd060191e81cf9f2b4abbf90019309f46825c636e9a5e207a6f6259391b4e0235e773cb1038486d8a34f7442e05d86433952ad99dda3492572b353fcd47ee8966d534bfde34d93fd3d2718d2dd1f3a26f3cce14aee97697f3eb28ccb7614c2f032d2d835c67641a051a859ed359e5b883892b24eb43397ff0f0c0000a9c3319e694f4a83785328f0941f846321afc6b8ea83575db4662d7194132b5b89eb103d56933290e45aacb1abfa4e1619f612bf7d8baf7c612e8b36e669
e=INTEGER:0x010001
First of all place, the modulus hex (generated above) code right after n=INTEGER:0x
same for the exponent hex code (also generated above)
Now it's possible to generate a DER File (BInary version of the certificate).
openssl asn1parse -genconf def.asn1 -out pubkey.der -noout
When we got the DER-File you will be able to convert it to a PEM (Texfile version from the certificate).
openssl rsa -in pubkey.der -inform der -pubin -out pubkey.pem
Finally, you can check that you got a 2048 bits public key with this command:
openssl rsa -pubin -in pubkey.pem -text -noout
In the next step, let's build a public key.
Building the SSH public key
Also, you might need to convert that PEM file to the SSH public key format:
ssh-keygen -i -m PKCS8 -f pubkey.pem
Here it is:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAADduZlktBKXf7C8ZlWtl4j4cbPReMHoXWVzDLEZE2XgY3dzuocnIrkSJOoE0coJDvqeOZsRG8imHw2WsfgbmXy1ZRsHnPe9BgGR6Bz58rSrf5ABkwn0aCXGNuml4gem9iWTkbTgI153PLEDhIbYo090QuBdhkM5Uq2Z3aNJJXKzU/zUfuiWbVNL/eNNk/09JxjS3R86JvPM4Urul2l/PrgMy3YUwvAy0tg1xnZBoFGoWe01nluIOJKyTrQzl/8PDAAAqcMxnmlPSoN4UyjwlB+EYyGvxrjqg1ddtGYtcZQTK1uJ64A9VpMykORarLGr/E4WGfYSv32Lr3xhLos25mk=
Et voila you got the public key for your azure B2C Tenant. You can use that to add this into every System that will verify every SAML or JWT Token against this key.