module Data.X509.Extended (certToString) where

import Crypto.Hash
import Data.ASN1.OID
import Data.ASN1.Types
import Data.ByteArray.Encoding qualified as BAE
import Data.Map qualified as Map
import Data.Text qualified as T
import Data.Text.Encoding qualified as T
import Data.X509
import Imports

certToString :: SignedCertificate -> String
certToString :: SignedCertificate -> String
certToString SignedCertificate
signedCert =
  let cert :: Certificate
cert = SignedCertificate -> Certificate
getCertificate SignedCertificate
signedCert
      issuer :: String
issuer = DistinguishedName -> String
dnToString (DistinguishedName -> String) -> DistinguishedName -> String
forall a b. (a -> b) -> a -> b
$ Certificate -> DistinguishedName
certIssuerDN Certificate
cert
      subject :: String
subject = DistinguishedName -> String
dnToString (DistinguishedName -> String) -> DistinguishedName -> String
forall a b. (a -> b) -> a -> b
$ Certificate -> DistinguishedName
certSubjectDN Certificate
cert
      der :: ByteString
der = SignedCertificate -> ByteString
forall a.
(Show a, Eq a, ASN1Object a) =>
SignedExact a -> ByteString
encodeSignedObject SignedCertificate
signedCert
      ByteString
fingerprint :: ByteString = Base -> Digest SHA1 -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> bout
BAE.convertToBase Base
BAE.Base16 (ByteString -> Digest SHA1
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
hash ByteString
der :: Digest SHA1)
      -- Split into pairs and join with ':'
      fingerprintStr :: String
fingerprintStr =
        let hex :: Text
hex = (ByteString -> Text
T.decodeUtf8 ByteString
fingerprint)
            pairs :: [String]
pairs = Text -> String
T.unpack (Text -> String) -> [Text] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Text -> [Text]
T.chunksOf Int
2 Text
hex
         in (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
":" [String]
pairs)
   in [String] -> String
forall a. Monoid a => [a] -> a
mconcat ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
"; " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
        [ String
"Issuer: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
issuer,
          String
"Subject: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
subject,
          String
"SHA1 Fingerprint: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
fingerprintStr
        ]

dnToString :: DistinguishedName -> String
dnToString :: DistinguishedName -> String
dnToString (DistinguishedName -> [(OID, ASN1CharacterString)]
getDistinguishedElements -> [(OID, ASN1CharacterString)]
es) =
  let [String]
dess :: [String] = ((OID, ASN1CharacterString) -> Maybe String)
-> [(OID, ASN1CharacterString)] -> [String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (OID, ASN1CharacterString) -> Maybe String
distinguishedElementString [(OID, ASN1CharacterString)]
es
   in [String] -> String
forall a. Monoid a => [a] -> a
mconcat ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
"," [String]
dess
  where
    distinguishedElementString :: (OID, ASN1CharacterString) -> Maybe String
    distinguishedElementString :: (OID, ASN1CharacterString) -> Maybe String
distinguishedElementString (OID
oid, ASN1CharacterString
aSN1CharacterString) = do
      (_element, desc) <- OID -> Map OID (DnElement, String) -> Maybe (DnElement, String)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup OID
oid Map OID (DnElement, String)
dnElementMap
      val <- asn1CharacterToString aSN1CharacterString
      pure $ desc <> "=" <> val

    dnElementMap :: Map OID (DnElement, String)
    dnElementMap :: Map OID (DnElement, String)
dnElementMap =
      [(OID, (DnElement, String))] -> Map OID (DnElement, String)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
        [ (DnElement -> String -> (OID, (DnElement, String))
mkEntry DnElement
DnCommonName String
"CN"),
          (DnElement -> String -> (OID, (DnElement, String))
mkEntry DnElement
DnCountry String
"Country"),
          (DnElement -> String -> (OID, (DnElement, String))
mkEntry DnElement
DnOrganization String
"O"),
          (DnElement -> String -> (OID, (DnElement, String))
mkEntry DnElement
DnOrganizationUnit String
"OU"),
          (DnElement -> String -> (OID, (DnElement, String))
mkEntry DnElement
DnEmailAddress String
"Email Address")
        ]
      where
        mkEntry :: DnElement -> String -> (OID, (DnElement, String))
        mkEntry :: DnElement -> String -> (OID, (DnElement, String))
mkEntry DnElement
e String
s = (DnElement -> OID
forall a. OIDable a => a -> OID
getObjectID DnElement
e, (DnElement
e, String
s))