haskell-tls / hs-certificate

Certificate and Key Reader/Writer in haskell
60 stars 57 forks source link

[question] [help-wanted] What format of public keys can be decoded? #100

Open ecthiender opened 5 years ago

ecthiender commented 5 years ago

I'm a little confused with what format of public keys can be decoded by the x509 package? (Also I'm not really super familiar with crypto formats etc.)

I have a public key in two formats generated via openssh (converted using openssl):

Now I'm using pem to read the file first, and then trying to decodeSignedObject it. Is that correct?

import qualified Data.PEM as PEM
import qualified Data.X509 as X509
import qualified Data.ByteString as B

main :: IO ()
main = do
  rc <- B.readFile "test_rsa.pub.pkcs1"  -- "test_rsa.pub.pkcs8"
  let Right [pem] = PEM.parseBS rc
  let res = X509.decodeSignedObject (PEM.pemContent pem) :: Either String (X509.SignedExact X509.PubKey)
  print res

I get the following output, with:

How can I decode a public key from any of these popular formats of public key?

ecthiender commented 5 years ago

Ok, after searching around, I kind of understand. I cannot use decodeSignedObject because I'm not using a signed certificate. I'm just using the public key. So x509 is not going to help me here?

I actually discovered https://hackage.haskell.org/package/certificate-1.3.9 first and found out that is deprecated. Ideally, I would need the decodePublic function from Data.Certificate.KeyRSA in certificate package. But as this is deprecated, I can't seem to find any package/function which will help.

Any help in the right direction would be much appreciated!

ocheron commented 5 years ago

You can use the ASN1Object instance like this:

import qualified Data.PEM as PEM
import qualified Data.X509 as X509
import qualified Data.ByteString as B

import Data.ASN1.BinaryEncoding
import Data.ASN1.Types
import Data.ASN1.Encoding

main :: IO ()
main = do
  rc <- B.readFile "test_rsa.pub.pkcs8"
  let Right [pem] = PEM.pemParseBS rc
      Right asn1 = decodeASN1' BER (PEM.pemContent pem)
      Right (pub, []) = fromASN1 asn1
  print (pub :: X509.PubKey)

(with help from packages asn1-types and asn1-encoding)

ecthiender commented 5 years ago

Thanks! So this works for PKCS8 formats. Is PKCS1 format also an instance of ASN1Object ? Do I have to decodeASN1 in a different way (for PKCS1) ?

ocheron commented 5 years ago

The ASN1Object instance implements format SubjectPublicKeyInfo, i.e. the one used in X.509 certificates.

The PKCS#1 format you referenced maps to the BitString inside this structure and is only possible for RSA because the algorithm has no parameter. I don't think there is API for this currently.

Btw PKCS#8 is a format for private keys, not public keys.