openssl already provides two ways of reading public keys in PEM format:
openssl ec -pubin -text -noout -in key.pemopenssl asn1parse < key.pem
Unfortunately, both provide text output which is hard to parse and use in an automated manner. This script provides a third way, and the output is structured JSON, using pure bash. See examples below.
bash public-key-to-json.sh id_ecdsa_prime256v1.pem id_ecdsa_secp384r1.pem id_rsa.pub This example outputs three json documents (one can easily consume them using jq -s):
{
"type": "SEQUENCE",
"value": [
{
"type": "SEQUENCE",
"value": [
{
"type": "OBJECT",
"value": "id-ecPublicKey"
},
{
"type": "OBJECT",
"value": "prime256v1"
}
]
},
{
"type": "BIT STRING",
"value": "AARMEQEDYHJtefNb/Xa/nbhJpX/HpkQG/FlK41IZoIpzcrdVbILBHnCymxvfJAQBWzfkvGfJTBsiqx6wG0E89O9t"
}
]
}{
"type": "SEQUENCE",
"value": [
{
"type": "SEQUENCE",
"value": [
{
"type": "OBJECT",
"value": "id-ecPublicKey"
},
{
"type": "OBJECT",
"value": "secp384r1"
}
]
},
{
"type": "BIT STRING",
"value": "AAQS7OEfjX47JZJcFmTwgGM7rg8xC6iCFKikvYWmQO9MBVjp4YW/LPP+2pMYLbr0yADhItUGJBFYIbb7ZW+/0YOeeXo43fk+UAaaAwzJdlU/C+CKgqrIKiWciwyzA/GtA7Y="
}
]
}{
"type": "SEQUENCE",
"value": [
{
"type": "SEQUENCE",
"value": [
{
"type": "OBJECT",
"value": "rsaEncryption"
},
{
"type": "NULL",
"value": ""
}
]
},
{
"type": "BIT STRING",
"value": {
"type": "SEQUENCE",
"value": [
{
"type": "INTEGER",
"value": "nwafJsdFdDZCKG9bgw7AJ9So/622Q/Gt9ClWH+uvYtv+ZwPQF3Bna4ibiAxT7kKlRMz1xusFFGNnb5wpI+r+AJa2H9gUcRbdNQurHTReB3W95hV3IeOlETbZcHDxglOqKaRU8QM92xhjiwD2eNfGNgNlYagGw5PsgpiJQkfA/KKAr8qI91FZMr6mtEvVb00eZHd6CqjM3HiNAIadLJAaE0gOXkGFXqRo+dEdpNHfuvTkwc5oHZPXNugVlZ9ncrlBAXYmI4TSN5eC6Kq0B92xK4mw64TqfKsvsMpcKg1Ek7SIVcYEmthdBTKtwc5NCEtoiWGmKvxWEUy4Wq+0AfRJlw=="
},
{
"type": "INTEGER",
"value": "AQAB"
}
]
}
}
]
}The ASN1 structure for public keys is the same for both RSA and ECDSA key types:
SEQUENCE
SEQUENCE
OBJECT # type of key
OBJECT # key params
BIT STRING # key payload
This means that you can reliably get the key details from the resulting JSON. For example, to get the key types:
bash public-key-to-json.sh id_ecdsa_prime256v1.pem id_ecdsa_secp384r1.pem id_rsa.pub | jq -r '.value[0].value[0].value'
# outputs:
# id-ecPublicKey
# id-ecPublicKey
# rsaEncryptionThe ECDSA key payload will be represented as a base64-encoded string. After decoding you can expect the following:
- First byte is always
0x00an artifact of the ASN1 encoding - Second byte is always
0x04indicating the „compressed” format, which basically tells you that the following data is x and y values concatenated - The rest is two integers
xandy, both taking half of the remaining payload. Their length depends on the curve type, and for example:
It’s left as an excercise to the reader to extract these values.
The RSA key payload is different. It contains the modulus and the exponent, but the BIT STRING
encodes them using DER/ASN1 format, so the script recursively parses it and embeds in the JSON
structure. You can expect this field to have two children (wrapped in a SEQUENCE), both of type
INTEGER, and their values are base64-encoded.
type openssl jq base64 xxd- RSA public key in PEM format (file starts with
-----BEGIN PUBLIC KEY-----) - ECDSA public key in PEM format
Since the script does not impose any output structure and just represents the ASN1 structure, it can technically be used to parse any PEM file, for example an SSL certificate.
Leave a comment below if there are any issues.