Data.X509.Validation

crypton-x509-validation-1.6.13: X.509 Certificate and CRL validation

License | BSD-style
Maintainer | Vincent Hanquez <vincent@snarc.org>
Stability | experimental
Portability | unknown
Safe Haskell | None
Language | Haskell2010

Data.X509.Validation

Contents

- Failed validation types
- Validation configuration types
- Validation
- Cache
- Signature verification

Description

X.509 Certificate checks and validations routines

Follows RFC5280 / RFC6818

Synopsis

- type ServiceID = (HostName, ByteString)
- type HostName = String
- newtype Fingerprint = Fingerprint ByteString
- data FailedReason
  - = UnknownCriticalExtension
  - | Expired
  - | InFuture
  - | SelfSigned
  - | UnknownCA
  - | NotAllowedToSign
  - | NotAnAuthority
  - | AuthorityTooDeep
  - | NoCommonName
  - | InvalidName String
  - | NameMismatch String
  - | InvalidWildcard
  - | LeafKeyUsageNotAllowed
  - | LeafKeyPurposeNotAllowed
  - | LeafNotV3
  - | EmptyChain
  - | CacheSaysNo String
  - | InvalidSignature SignatureFailure
- data SignatureFailure
  - = SignatureInvalid
  - | SignaturePubkeyMismatch
  - | SignatureUnimplemented
- data ValidationChecks = ValidationChecks {
  - checkTimeValidity :: Bool
  - checkAtTime :: Maybe DateTime
  - checkStrictOrdering :: Bool
  - checkCAConstraints :: Bool
  - checkExhaustive :: Bool
  - checkLeafV3 :: Bool
  - checkLeafKeyUsage :: [ExtKeyUsageFlag]
  - checkLeafKeyPurpose :: [ExtKeyUsagePurpose]
  - checkFQHN :: Bool
  }
- data ValidationHooks = ValidationHooks {
  - hookMatchSubjectIssuer :: DistinguishedName -> Certificate -> Bool
  - hookValidateTime :: DateTime -> Certificate -> [FailedReason]
  - hookValidateName :: HostName -> Certificate -> [FailedReason]
  - hookFilterReason :: [FailedReason] -> [FailedReason]
  }
- defaultChecks :: ValidationChecks
- defaultHooks :: ValidationHooks
- validate :: HashALG -> ValidationHooks -> ValidationChecks -> CertificateStore -> ValidationCache -> ServiceID -> CertificateChain -> IO [FailedReason]
- validatePure :: DateTime -> ValidationHooks -> ValidationChecks -> CertificateStore -> ServiceID -> CertificateChain -> [FailedReason]
- validateDefault :: CertificateStore -> ValidationCache -> ServiceID -> CertificateChain -> IO [FailedReason]
- getFingerprint :: (Show a, Eq a, ASN1Object a) => SignedExact a -> HashALG -> Fingerprint
- data ValidationCacheResult
  - = ValidationCachePass
  - | ValidationCacheDenied String
  - | ValidationCacheUnknown
- type ValidationCacheQueryCallback = ServiceID -> Fingerprint -> Certificate -> IO ValidationCacheResult
- type ValidationCacheAddCallback = ServiceID -> Fingerprint -> Certificate -> IO ()
- data ValidationCache = ValidationCache {
  - cacheQuery :: ValidationCacheQueryCallback
  - cacheAdd :: ValidationCacheAddCallback
  }
- defaultValidationCache :: ValidationCache
- exceptionValidationCache :: [(ServiceID, Fingerprint)] -> ValidationCache
- tofuValidationCache :: [(ServiceID, Fingerprint)] -> IO ValidationCache
- data SignatureFailure
  - = SignatureInvalid
  - | SignaturePubkeyMismatch
  - | SignatureUnimplemented
- verifySignedSignature :: (Show a, Eq a, ASN1Object a) => SignedExact a -> PubKey -> SignatureVerification
- verifySignature :: SignatureALG -> PubKey -> ByteString -> ByteString -> SignatureVerification
- data SignatureVerification
  - = SignaturePass
  - | SignatureFailed SignatureFailure

# Documentation

type ServiceID = (HostName, ByteString) #

identification of the connection consisting of the fully qualified host name (e.g. www.example.com) and an optional suffix.

The suffix is not used by the validation process, but is used by the optional cache to identity certificate per service on a specific host. For example, one might have a different certificate on 2 differents ports (443 and 995) for the same host.

for TCP connection, it's recommended to use: :port, or :service for the suffix.

type HostName = String #

newtype Fingerprint #

Fingerprint of a certificate

Constructors

Fingerprint ByteString |

#### Instances

Instances details

Show Fingerprint # |
Instance details Defined in Data.X509.Validation.Fingerprint Methods showsPrec :: Int -> Fingerprint -> ShowS # show :: Fingerprint -> String # showList :: [Fingerprint] -> ShowS #
Eq Fingerprint # |
Instance details Defined in Data.X509.Validation.Fingerprint Methods (==) :: Fingerprint -> Fingerprint -> Bool # (/=) :: Fingerprint -> Fingerprint -> Bool #
ByteArrayAccess Fingerprint # |
Instance details Defined in Data.X509.Validation.Fingerprint Methods length :: Fingerprint -> Int # withByteArray :: Fingerprint -> (Ptr p -> IO a) -> IO a # copyByteArrayToPtr :: Fingerprint -> Ptr p -> IO () #

# Failed validation types

data FailedReason #

Possible reason of certificate and chain failure.

The values `InvalidName` and `InvalidWildcard` are internal-only and are never returned by the validation functions. `NameMismatch` is returned instead.

Constructors

UnknownCriticalExtension | certificate contains an unknown critical extension
Expired | validity ends before checking time
InFuture | validity starts after checking time
SelfSigned | certificate is self signed
UnknownCA | unknown Certificate Authority (CA)
NotAllowedToSign | certificate is not allowed to sign
NotAnAuthority | not a CA
AuthorityTooDeep | Violation of the optional Basic constraint's path length
NoCommonName | Certificate doesn't have any common name (CN)
InvalidName String | Invalid name in certificate
NameMismatch String | connection name and certificate do not match
InvalidWildcard | invalid wildcard in certificate
LeafKeyUsageNotAllowed | the requested key usage is not compatible with the leaf certificate's key usage
LeafKeyPurposeNotAllowed | the requested key purpose is not compatible with the leaf certificate's extended key usage
LeafNotV3 | Only authorized an X509.V3 certificate as leaf certificate.
EmptyChain | empty chain of certificate
CacheSaysNo String | the cache explicitely denied this certificate
InvalidSignature SignatureFailure | signature failed

#### Instances

Instances details

Show FailedReason # |
Instance details Defined in Data.X509.Validation Methods showsPrec :: Int -> FailedReason -> ShowS # show :: FailedReason -> String # showList :: [FailedReason] -> ShowS #
Eq FailedReason # |
Instance details Defined in Data.X509.Validation Methods (==) :: FailedReason -> FailedReason -> Bool # (/=) :: FailedReason -> FailedReason -> Bool #

data SignatureFailure #

Various failure possible during signature checking

Constructors

SignatureInvalid | signature doesn't verify
SignaturePubkeyMismatch | algorithm and public key mismatch, cannot proceed
SignatureUnimplemented | unimplemented signature algorithm

#### Instances

Instances details

Show SignatureFailure # |
Instance details Defined in Data.X509.Validation.Signature Methods showsPrec :: Int -> SignatureFailure -> ShowS # show :: SignatureFailure -> String # showList :: [SignatureFailure] -> ShowS #
Eq SignatureFailure # |
Instance details Defined in Data.X509.Validation.Signature Methods (==) :: SignatureFailure -> SignatureFailure -> Bool # (/=) :: SignatureFailure -> SignatureFailure -> Bool #

# Validation configuration types

data ValidationChecks #

A set of checks to activate or parametrize to perform on certificates.

It's recommended to use `defaultChecks` to create the structure, to better cope with future changes or expansion of the structure.

Constructors

ValidationChecks |
Fields checkTimeValidity :: Bool check time validity of every certificate in the chain. the make sure that current time is between each validity bounds in the certificate checkAtTime :: Maybe DateTime The time when the validity check happens. When set to Nothing, the current time will be used checkStrictOrdering :: Bool Check that no certificate is included that shouldn't be included. unfortunately despite the specification violation, a lots of real world server serves useless and usually old certificates that are not relevant to the certificate sent, in their chain. checkCAConstraints :: Bool Check that signing certificate got the CA basic constraint. this is absolutely not recommended to turn it off. checkExhaustive :: Bool Check the whole certificate chain without stopping at the first failure. Allow gathering a exhaustive list of failure reasons. if this is turn off, it's absolutely not safe to ignore a failed reason even it doesn't look serious (e.g. Expired) as other more serious checks would not have been performed. checkLeafV3 :: Bool Check that the leaf certificate is version 3. If disable, version 2 certificate is authorized in leaf position and key usage cannot be checked. checkLeafKeyUsage :: [ExtKeyUsageFlag] Check that the leaf certificate is authorized to be used for certain usage. If set to empty list no check are performed, otherwise all the flags is the list need to exists in the key usage extension. If the extension is not present, the check will pass and behave as if the certificate key is not restricted to any specific usage. checkLeafKeyPurpose :: [ExtKeyUsagePurpose] Check that the leaf certificate is authorized to be used for certain purpose. If set to empty list no check are performed, otherwise all the flags is the list need to exists in the extended key usage extension if present. If the extension is not present, then the check will pass and behave as if the certificate is not restricted to any specific purpose. checkFQHN :: Bool Check the top certificate names matching the fully qualified hostname (FQHN). it's not recommended to turn this check off, if no other name checks are performed.

#### Instances

Instances details

Default ValidationChecks # |
Instance details Defined in Data.X509.Validation Methods def :: ValidationChecks #
Show ValidationChecks # |
Instance details Defined in Data.X509.Validation Methods showsPrec :: Int -> ValidationChecks -> ShowS # show :: ValidationChecks -> String # showList :: [ValidationChecks] -> ShowS #
Eq ValidationChecks # |
Instance details Defined in Data.X509.Validation Methods (==) :: ValidationChecks -> ValidationChecks -> Bool # (/=) :: ValidationChecks -> ValidationChecks -> Bool #

data ValidationHooks #

A set of hooks to manipulate the way the verification works.

BEWARE, it's easy to change behavior leading to compromised security.

Constructors

ValidationHooks |
Fields hookMatchSubjectIssuer :: DistinguishedName -> Certificate -> Bool check whether a given issuer `DistinguishedName` matches the subject `DistinguishedName` of a candidate issuer certificate. hookValidateTime :: DateTime -> Certificate -> [FailedReason] check whether the certificate in the second argument is valid at the time provided in the first argument. Return an empty list for success or else one or more failure reasons. hookValidateName :: HostName -> Certificate -> [FailedReason] validate the certificate leaf name with the DNS named used to connect hookFilterReason :: [FailedReason] -> [FailedReason] user filter to modify the list of failure reasons

#### Instances

Instances details

Default ValidationHooks # |
Instance details Defined in Data.X509.Validation Methods def :: ValidationHooks #

defaultChecks :: ValidationChecks #

Default checks to perform

The default checks are: * Each certificate time is valid * CA constraints is enforced for signing certificate * Leaf certificate is X.509 v3 * Check that the FQHN match

defaultHooks :: ValidationHooks #

Default hooks in the validation process

# Validation

validate #

Arguments

:: HashALG | the hash algorithm we want to use for hashing the leaf certificate
-> ValidationHooks | Hooks to use
-> ValidationChecks | Checks to do
-> CertificateStore | The trusted certificate store for CA
-> ValidationCache | the validation cache callbacks
-> ServiceID | identification of the connection
-> CertificateChain | the certificate chain we want to validate
-> IO [FailedReason] | the return failed reasons (empty list is no failure)

X509 validation

the function first interrogate the cache and if the validation fail, proper verification is done. If the verification pass, the add to cache callback is called.

validatePure #

Arguments

:: DateTime | The time for which to check validity for
-> ValidationHooks | Hooks to use
-> ValidationChecks | Checks to do
-> CertificateStore | The trusted certificate store for CA
-> ServiceID | Identification of the connection
-> CertificateChain | The certificate chain we want to validate
-> [FailedReason] | the return failed reasons (empty list is no failure)

Validate a certificate chain with explicit pure parameters

validateDefault #

Arguments

:: CertificateStore | The trusted certificate store for CA
-> ValidationCache | the validation cache callbacks
-> ServiceID | identification of the connection
-> CertificateChain | the certificate chain we want to validate
-> IO [FailedReason] | the return failed reasons (empty list is no failure)

Validate using the default hooks and checks and the SHA256 mechanism as hashing mechanism

getFingerprint #

Arguments

:: (Show a, Eq a, ASN1Object a) |
=> SignedExact a | object to fingerprint
-> HashALG | algorithm to compute the fingerprint
-> Fingerprint | fingerprint in binary form

Get the fingerprint of the whole signed object using the hashing algorithm specified

# Cache

data ValidationCacheResult #

The result of a cache query

Constructors

ValidationCachePass | cache allow this fingerprint to go through
ValidationCacheDenied String | cache denied this fingerprint for further validation
ValidationCacheUnknown | unknown fingerprint in cache

#### Instances

Instances details

Show ValidationCacheResult # |
Instance details Defined in Data.X509.Validation.Cache Methods showsPrec :: Int -> ValidationCacheResult -> ShowS # show :: ValidationCacheResult -> String # showList :: [ValidationCacheResult] -> ShowS #
Eq ValidationCacheResult # |
Instance details Defined in Data.X509.Validation.Cache Methods (==) :: ValidationCacheResult -> ValidationCacheResult -> Bool # (/=) :: ValidationCacheResult -> ValidationCacheResult -> Bool #

type ValidationCacheQueryCallback #

Arguments

= ServiceID | connection's identification
-> Fingerprint | fingerprint of the leaf certificate
-> Certificate | leaf certificate
-> IO ValidationCacheResult | return if the operation is succesful or not

Validation cache query callback type

type ValidationCacheAddCallback #

Arguments

= ServiceID | connection's identification
-> Fingerprint | fingerprint of the leaf certificate
-> Certificate | leaf certificate
-> IO () |

Validation cache callback type

data ValidationCache #

All the callbacks needed for querying and adding to the cache.

Constructors

ValidationCache |
Fields cacheQuery :: ValidationCacheQueryCallback cache querying callback cacheAdd :: ValidationCacheAddCallback cache adding callback

#### Instances

Instances details

Default ValidationCache # |
Instance details Defined in Data.X509.Validation.Cache Methods def :: ValidationCache #

defaultValidationCache :: ValidationCache #

exceptionValidationCache :: [(ServiceID, Fingerprint)] -> ValidationCache #

create a simple constant cache that list exceptions to the certification validation. Typically this is use to allow self-signed certificates for specific use, with out-of-bounds user checks.

No fingerprints will be added after the instance is created.

The underlying structure for the check is kept as a list, as usually the exception list will be short, but when the list go above a dozen exceptions it's recommended to use another cache mechanism with a faster lookup mechanism (hashtable, map, etc).

Note that only one fingerprint is allowed per ServiceID, for other use, another cache mechanism need to be use.

tofuValidationCache #

Arguments

:: [(ServiceID, Fingerprint)] | a list of exceptions
-> IO ValidationCache |

Trust on first use (TOFU) cache with an optional list of exceptions

this is similar to the exceptionCache, except that after each succesfull validation it does add the fingerprint to the database. This prevent any further modification of the fingerprint for the remaining

# Signature verification

data SignatureFailure #

Various failure possible during signature checking

Constructors

SignatureInvalid | signature doesn't verify
SignaturePubkeyMismatch | algorithm and public key mismatch, cannot proceed
SignatureUnimplemented | unimplemented signature algorithm

#### Instances

Instances details

Show SignatureFailure # |
Instance details Defined in Data.X509.Validation.Signature Methods showsPrec :: Int -> SignatureFailure -> ShowS # show :: SignatureFailure -> String # showList :: [SignatureFailure] -> ShowS #
Eq SignatureFailure # |
Instance details Defined in Data.X509.Validation.Signature Methods (==) :: SignatureFailure -> SignatureFailure -> Bool # (/=) :: SignatureFailure -> SignatureFailure -> Bool #

verifySignedSignature :: (Show a, Eq a, ASN1Object a) => SignedExact a -> PubKey -> SignatureVerification #

Verify a Signed object against a specified public key

verifySignature #

Arguments

:: SignatureALG | Signature algorithm used
-> PubKey | Public key to use for verify
-> ByteString | Certificate data that need to be verified
-> ByteString | Signature to verify
-> SignatureVerification |

verify signature using parameter

data SignatureVerification #

A set of possible return from signature verification.

When SignatureFailed is return, the signature shouldn't be accepted.

Other values are only useful to differentiate the failure reason, but are all equivalent to failure.

Constructors

SignaturePass | verification succeeded
SignatureFailed SignatureFailure | verification failed

#### Instances

Instances details

Show SignatureVerification # |
Instance details Defined in Data.X509.Validation.Signature Methods showsPrec :: Int -> SignatureVerification -> ShowS # show :: SignatureVerification -> String # showList :: [SignatureVerification] -> ShowS #
Eq SignatureVerification # |
Instance details Defined in Data.X509.Validation.Signature Methods (==) :: SignatureVerification -> SignatureVerification -> Bool # (/=) :: SignatureVerification -> SignatureVerification -> Bool #