packages feed

domain-auth-0.1.0: Network/DomainAuth/Pubkey/RSAPub.hs

module Network.DomainAuth.Pubkey.RSAPub where

import Codec.Crypto.RSA
import Control.Applicative
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as LC (pack)
import Network.DNS (Domain)
import qualified Network.DNS as DNS hiding (Domain)
import Network.DomainAuth.Mail
import qualified Network.DomainAuth.Pubkey.Base64 as B
import qualified Network.DomainAuth.Pubkey.Der as D

lookupPublicKey :: DNS.Resolver -> Domain -> IO (Maybe PublicKey)
lookupPublicKey resolver domain = decode <$> lookupPublicKey' resolver domain
  where
    decode = (>>= return . decodeRSAPublicyKey)

lookupPublicKey' :: DNS.Resolver -> String -> IO (Maybe L.ByteString)
lookupPublicKey' resolver domain = extractPub <$> DNS.lookupTXT resolver domain

extractPub :: Maybe [L.ByteString] -> Maybe L.ByteString
extractPub = (>>= lookup (LC.pack "p") . parseTaggedValue . head)

decodeRSAPublicyKey :: L.ByteString -> PublicKey
decodeRSAPublicyKey bs = PublicKey size n e
  where
    subjectPublicKeyInfo = D.decode . B.decode $ bs
    [_, subjectPublicKey] = D.tlv subjectPublicKeyInfo
    rsaPublicKey = D.decode . bitString . D.cnt $ subjectPublicKey
    [bn',be'] = D.tlv rsaPublicKey
    bn = L.dropWhile (== 0) $ D.cnt bn'
    be = D.cnt be'
    n = toNum bn
    e = toNum be
    size = fromIntegral . L.length $ bn
    toNum = L.foldl' (\x y -> x*256 + fromIntegral y) 0
    bitString = L.tail