14

I have a .pem file (base64-encoded cryptography information). What OpenSSL command-line should I use to detect whether it contains a public key or a private key?

As explained in this StackOverflow question, a .pem can contain both.

Since the contents of the file are juste garbled base64, when sending a .pem certificate to some other machine, I would like to make sure I'm exporting the public key and not giving out my private key.

Community
  • 1
  • 1
Suzanne Soy
  • 3,027
  • 6
  • 38
  • 56

3 Answers3

2

I have a .pem file (base64-encoded cryptography information). What OpenSSL command-line should I use to detect whether it contains a public key or a private key?

In general, you have to inspect the the first line of the PEM file to determine what is present.

OpenSSL can detect a subset of available encoded things (for lack of a better term). You can see the list of what OpenSSL can decode by examining <openssl src>/crypto/pem/pem.h. From the file:

#define PEM_STRING_X509_OLD "X509 CERTIFICATE"
#define PEM_STRING_X509     "CERTIFICATE"
#define PEM_STRING_X509_PAIR    "CERTIFICATE PAIR"
#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE"
#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST"
#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST"
#define PEM_STRING_X509_CRL "X509 CRL"
#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY"
#define PEM_STRING_PUBLIC   "PUBLIC KEY"
#define PEM_STRING_RSA      "RSA PRIVATE KEY"
#define PEM_STRING_RSA_PUBLIC   "RSA PUBLIC KEY"
#define PEM_STRING_DSA      "DSA PRIVATE KEY"
#define PEM_STRING_DSA_PUBLIC   "DSA PUBLIC KEY"
#define PEM_STRING_PKCS7    "PKCS7"
#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA"
#define PEM_STRING_PKCS8    "ENCRYPTED PRIVATE KEY"
#define PEM_STRING_PKCS8INF "PRIVATE KEY"
#define PEM_STRING_DHPARAMS "DH PARAMETERS"
#define PEM_STRING_SSL_SESSION  "SSL SESSION PARAMETERS"
#define PEM_STRING_DSAPARAMS    "DSA PARAMETERS"
#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY"
#define PEM_STRING_ECPARAMETERS "EC PARAMETERS"
#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY"
#define PEM_STRING_PARAMETERS   "PARAMETERS"
#define PEM_STRING_CMS      "CMS"

Some things will be more difficult than others. For example, its obvious what a RSA PUBLIC KEY is, but its not so obvious what a PUBLIC KEY is. In this case, you do one of two things. First, you ASN.1/DER decode the thing and then look ups its OID if available. Second, you try and load into a data structure that you expect the thing to be.

As an example of the second strategy, you would attempt to load a PEM blob into a RSA private key with PEM_read_bio_RSAPrivateKey. If it succeeds, then its a RSA private key. If its fails, then it may be a damaged RSA private key, or it may be an EC private key, or it may not be a PEM blob.


In 2006, a request was made to standardize the names of the things with the PKIX working group. It fell on deaf ears within the IETF. See PEM file format rfc draft request.

jww
  • 97,681
  • 90
  • 411
  • 885
  • 4
    This answer goes into a lot of depth (which is great!), but fails to explain the most basic, necessary part: how to run an openssl command to retrieve some of this information. – jpaugh Oct 28 '19 at 22:37
  • Ironically, RFC 7468 came out only two months after this was written. BTW, `PEM_STRING_EVP_PKEY "ANY PRIVATE KEY"` and `PEM_STRING_PARAMETERS "PARAMETERS"` are dummy values used only between `crypto/pem/{pem_pkey,pem_lib}.c`, they never occur that way in an actual file. `read...RSAPrivateKey` also fails if it _is_ an RSA privatekey but is encrypted and you don't supply the correct password (although in that case giving it to someone else MAY not be excessively unsafe). – dave_thompson_085 May 17 '21 at 21:50
1

As a practical approximation that should catch most (all?) human mistakes I would recommend just file and grep:

(file $KEYFILE | grep -i private >/dev/null) && echo Private || echo Public-or-unknown

To screen some key material before it goes out:

 for f in *; do (file $f | grep -i private >/dev/null) && file $f; done

Empty output = hopefully no secrets, can proceed.

Dawid Toton
  • 767
  • 5
  • 8
  • 2
    Not working. `file` returns for my private key "ASCII text". – Carlo Wood Aug 07 '19 at 15:14
  • 1
    It would be better to grep for 'public', and then default to private, since being wrong is less problematic when your guess is conservative. – jpaugh Oct 28 '19 at 22:35
1

You can use openssl to look, what's inside:

openssl x509 -in cert.pem -noout -text
stackprotector
  • 10,498
  • 4
  • 35
  • 64