{-# LANGUAGE OverloadedStrings #-} -- | A library for DKIM (). -- 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: " -- ,"Date: Thu, 4 Apr 2024 10:53:59 +0900" -- ,"From: Kazu Yamamoto " -- ,"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