haskell-tls / hs-certificate

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

ExtAuthorityKeyId in presence of authorityCertIssuer/authorityCertSerialNumber fields. #79

Open pbogdan opened 7 years ago

pbogdan commented 7 years ago

Firstly I apologise if any of my terminology is off or if this is a user error as I'm not very well versed in this domain.

While attempting to parse and use information provided by ExtAuthorityKeyId extension I came across an issue while trying to extract the extension from QuoVadis Root CA 2 certificate. The certificate is available at http://trust.quovadisglobal.com/qvrca2.crt and checking with openssl tool:

$ wget http://trust.quovadisglobal.com/qvrca2.crt -q -O - | openssl x509 -inform der -text -in -

yields the following data for ExtAuthorityKeyId:

            X509v3 Authority Key Identifier: 
                keyid:1A:84:62:BC:48:4C:33:25:04:D4:EE:D0:F6:03:C4:19:46:D1:94:6B
                DirName:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 2
                serial:05:09

and the following ExtensionRaw representation:

ExtensionRaw
{ extRawOID = [2, 5, 29, 35]
, extRawCritical = False
, extRawASN1 =
    [ Start Sequence
    , Other
        Context
        0
        "\SUB\132b\188HL3%\EOT\212\238\208\246\ETX\196\EMF\209\148k"
    , Start (Container Context 1)
    , Start (Container Context 4)
    , Start Sequence
    , Start Set
    , Start Sequence
    , OID [2, 5, 4, 6]
    , ASN1String
        (ASN1CharacterString
         {characterEncoding = Printable, getCharacterStringRawData = "BM"})
    , End Sequence
    , End Set
    , Start Set
    , Start Sequence
    , OID [2, 5, 4, 10]
    , ASN1String
        (ASN1CharacterString
         { characterEncoding = Printable
         , getCharacterStringRawData = "QuoVadis Limited"
         })
    , End Sequence
    , End Set
    , Start Set
    , Start Sequence
    , OID [2, 5, 4, 3]
    , ASN1String
        (ASN1CharacterString
         { characterEncoding = Printable
         , getCharacterStringRawData = "QuoVadis Root CA 2"
         })
    , End Sequence
    , End Set
    , End Sequence
    , End (Container Context 4)
    , End (Container Context 1)
    , Other Context 2 "\ENQ\t"
    , End Sequence
    ]
}

To my understanding current implementation of parsing ExtAuthorityKeyId expects that only keyIdentifier field will be present and as such fails to extract the extension in presence of the additional fields. According to this RFC authorityCertIssuer and authorityCertSerialNumber may also be present.

I was able to work around it by introducing the following instance:

instance Extension MyExtAuthorityKeyId where
    extOID _ = [2,5,29,35]
    extEncode (MyExtAuthorityKeyId keyid) =
        [Start Sequence,Other Context 0 keyid,End Sequence]
    extDecode (Start Sequence : Other Context 0 keyid : _) =
        Right $ MyExtAuthorityKeyId keyid
    extDecode _ = Left "unknown sequence"

with MyExtAuthorityKeyId having the same representation as ExtAuthorityKeyId. The instance has the unfortunate property of decoding and encoding losing data due to not being aware of the additional fields, while keeping the representation of ExtAuthorityKeyId the same which would otherwise be a breaking change.

In any case I wanted to check whether this was intentional behaviour, or perhaps your thoughts on changing its current implementation.

vincenthz commented 7 years ago

in the twisted maze of asn1, it's easy to miss full encoding of extensions. we shouldn't ignore the rest of the asn1, but someone need to add what's necessary. Changing the current implementation for making things more correct is not a problem.