domain-auth-0.2.4: Network/DomainAuth/DKIM.hs
{-# LANGUAGE OverloadedStrings #-}
-- | A library for DKIM (<http://www.ietf.org/rfc/rfc6376.txt>).
-- Currently, only receiver side is implemented.
module Network.DomainAuth.DKIM (
-- * Documentation
-- ** Authentication with DKIM
runDKIM,
runDKIM',
-- ** Parsing DKIM-Signature:
parseDKIM,
DKIM,
dkimDomain,
dkimSelector,
-- ** Field key for DKIM-Signature:
dkimFieldKey,
) where
import qualified Data.ByteString as BS
import Network.DNS as DNS (Resolver)
import Network.DomainAuth.DKIM.Parser
import Network.DomainAuth.DKIM.Types
import Network.DomainAuth.DKIM.Verify
import Network.DomainAuth.Mail
import Network.DomainAuth.Pubkey.RSAPub
import Network.DomainAuth.Types
-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Network.DNS
-- >>> import Data.ByteString.Char8 as BS8
-- | Verifying 'Mail' with DKIM.
--
-- >>> rs <- makeResolvSeed defaultResolvConf
-- >>> :{
-- let lst = ["DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;"
-- ," d=gmail.com; s=20230601; t=1712195651; x=1712800451; darn=iij.ad.jp;"
-- ," h=to:subject:message-id:date:from:mime-version:from:to:cc:subject"
-- ," :date:message-id:reply-to;"
-- ," bh=g3zLYH4xKxcPrHOD18z9YfpQcnk/GaJedfustWU5uGs=;"
-- ," b=YXB6AlsJFBYK+32OfzPKYoRHVHL/L01KgEV9YIxIiyF2LiLMgGlIdQdTnFnKKgaOKN"
-- ," EX/233mgKR3Vn4I9yTdlgli6d5Eni4XU064hJ4b4Xm+/AuiW67LiuZlDkQIHSOXYg7y9"
-- ," PiBPz5+5FQL2w/svoty7mYkUh59xWmbUCZXXUYoXA+MSnyNvV187TYlx/L6CWeb3Tc4E"
-- ," EX/DEROnzKST/O0LVrnYzqJWv/H0NTytA+JxE1dT/1/ObHkHWqb/ip4DxPlE6KB2ycOu"
-- ," vhtPyambWkKEsEtR5UTMcMweVc2qsdFciqupFAYIcJIopFyL4rxai8E32q6V1hZmpdzr"
-- ," uW/Q=="
-- ,"To: kazu@iij.ad.jp"
-- ,"Subject: test"
-- ,"Message-ID: <CAKipW39hxTzXh28waC4fuu=qVFfy9EF=H8zH_k8wgM9RBR6_dg@mail.gmail.com>"
-- ,"Date: Thu, 4 Apr 2024 10:53:59 +0900"
-- ,"From: Kazu Yamamoto <kazu.yamamoto@gmail.com>"
-- ,"MIME-Version: 1.0"
-- ,"Content-Type: text/plain; charset=\"UTF-8\""
-- ,""
-- ,"test"
-- ]
-- mail = getMail $ BS8.intercalate "\r\n" lst
-- in withResolver rs $ \rslv -> runDKIM rslv mail
-- :}
-- pass
runDKIM :: Resolver -> Mail -> IO DAResult
runDKIM resolver mail = dkim1
where
dkim1 =
maybe (return DANone) dkim2 $ lookupField dkimFieldKey (mailHeader mail)
dkim2 dkimv = maybe (return DAPermError) dkim3 $ parseDKIM (fieldValueUnfolded dkimv)
dkim3 = runDKIM' resolver mail
-- | Verifying 'Mail' with DKIM. The value of DKIM-Signature:
-- should be parsed beforehand.
runDKIM' :: Resolver -> Mail -> DKIM -> IO DAResult
runDKIM' resolver mail dkim = maybe DATempError (verify mail dkim) <$> pub
where
pub = lookupPublicKey resolver dom
dom = dkimSelector dkim +++ "._domainkey." +++ dkimDomain dkim
verify m d p = if verifyDKIM m d p then DAPass else DAFail
(+++) = BS.append