radius 0.3.0.0 → 0.4.0.0
raw patch · 4 files changed
+123/−9 lines, 4 filesdep +cryptonitedep +memorydep −cryptohash-md5dep −pretty-hexPVP ok
version bump matches the API change (PVP)
Dependencies added: cryptonite, memory
Dependencies removed: cryptohash-md5, pretty-hex
API changes (from Hackage documentation)
- Network.RADIUS.Types: [getVendorSpecificAttributeId] :: PacketAttribute -> Word32
+ Network.RADIUS.Encoding: hashMD5 :: ByteString -> ByteString
+ Network.RADIUS.Microsoft: encodeMPPEEncryptionPolicyAttribute :: Word32 -> PacketAttribute
+ Network.RADIUS.Microsoft: encodeMPPEEncryptionTypesAttribute :: Word32 -> PacketAttribute
+ Network.RADIUS.Microsoft: encodeMPPERecvKeyAttribute :: Word16 -> ByteString -> ByteString -> ByteString -> PacketAttribute
+ Network.RADIUS.Microsoft: encodeMPPESendKeyAttribute :: Word16 -> ByteString -> ByteString -> ByteString -> PacketAttribute
+ Network.RADIUS.Types: [getVendorIdAttribute] :: PacketAttribute -> Word32
Files
- radius.cabal +4/−3
- src/Network/RADIUS/Encoding.hs +15/−5
- src/Network/RADIUS/Microsoft.hs +103/−0
- src/Network/RADIUS/Types.hs +1/−1
radius.cabal view
@@ -1,5 +1,5 @@ name: radius-version: 0.3.0.0+version: 0.4.0.0 synopsis: Remote Authentication Dial In User Service (RADIUS) description: This module provides types and on the wire de/coding of RADIUS packets as per RFC2865 homepage: https://github.com/erickg/radius#readme@@ -16,13 +16,14 @@ library hs-source-dirs: src exposed-modules: Network.RADIUS.Encoding+ , Network.RADIUS.Microsoft , Network.RADIUS.Types build-depends: base >= 4.7 && < 5 , binary , bytestring- , cryptohash-md5+ , cryptonite , iproute- , pretty-hex+ , memory default-language: Haskell2010 ghc-options: -Wall
src/Network/RADIUS/Encoding.hs view
@@ -18,15 +18,22 @@ import Control.Monad (when) import Data.Binary (Binary(..), encode) import Data.Binary.Put (Put, putLazyByteString, putWord8, putWord16be, putWord32be)-import Data.Binary.Get (Get, getLazyByteString, getWord8, getWord16be, getWord32be, isEmpty)+import Data.Binary.Get (Get,+ getLazyByteString,+ getWord8,+ getWord16be,+ getWord32be,+ isEmpty)+import Data.ByteArray (convert) import Data.ByteString.Lazy.Char8 (ByteString, append) import Data.IP (IPv4, IPv6) import Data.Int (Int64) import Data.Word (Word8, Word16)+import Crypto.Hash.Algorithms (MD5)+import Crypto.Hash (Digest, hashlazy) import Network.RADIUS.Types import qualified Data.ByteString.Lazy.Char8 as B-import qualified Crypto.Hash.MD5 as MD5 -- | Self explanatory. It can be useful when reading a RADIUS packet from a socket for example, -- so one can retrieve the packet header (containing the packet length) first and then use that@@ -77,11 +84,14 @@ sign :: ByteString -> ByteString -> ByteString sign packet secret =- let authenticator = B.fromStrict . MD5.hashlazy $ packet `append` secret+ let authenticator = hashMD5 $ packet `append` secret prologue = B.take 4 packet -- size of type, id, length attributes = B.drop (fromIntegral radiusHeaderSize) packet in prologue `append` authenticator `append` attributes +hashMD5 :: ByteString -> ByteString+hashMD5 = B.fromStrict . convert . (hashlazy :: ByteString -> Digest MD5)+ instance Binary PacketType where put = putWord8 . fromIntegral . fromEnum get = getWord8 >>= return . toEnum . fromIntegral@@ -174,11 +184,11 @@ putWord8 0 -- reserved putWord8 $ fromIntegral prefixLength putLazyByteString attr- put (VendorSpecificAttribute iD str) = do+ put (VendorSpecificAttribute vendorId str) = do let attrLen = (fromIntegral . B.length $ str) + 6 -- Attribute header length + string putWord8 26 -- Attribute Type putWord8 attrLen- put iD+ putWord32be vendorId putLazyByteString str put (CHAPPassword identity str) = do let attrLen = (fromIntegral . B.length $ str) + 3 -- Attribute header plus string
+ src/Network/RADIUS/Microsoft.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE RecordWildCards, OverloadedStrings #-}+{-|+Module : Network.RADIUS.Microsoft+Description : Microsoft specific RADIUS Attributes+Copyright : (c) Erick Gonzalez, 2017+License : BSD3+Maintainer : erick@codemonkeylabs.de+Stability : experimental+Portability : POSIX++This module provides encoding for some of the Microsoft specific attributes, particularly those+needed for MSCHAPv2.++-}+module Network.RADIUS.Microsoft (encodeMPPESendKeyAttribute,+ encodeMPPERecvKeyAttribute,+ encodeMPPEEncryptionPolicyAttribute,+ encodeMPPEEncryptionTypesAttribute) where++import Prelude hiding (zipWith)+import Crypto.Hash.Algorithms (MD5)+import Crypto.Hash (Digest, hash)+import Data.Binary.Put (Put, putByteString, putWord8, putWord16be, runPut, putWord32be)+import Data.Bits ((.|.), xor)+import Data.ByteArray (convert)+import Data.ByteString (ByteString, pack, zipWith)+import Data.ByteString.Internal (w2c)+import Data.Monoid ((<>))+import Data.Word (Word8, Word16, Word32)+import Network.RADIUS.Types++import qualified Data.ByteString.Lazy.Char8 as LB+import qualified Data.ByteString.Char8 as B++-- | Wraps the given encoded vendor specific attribute data into a PacketAttribute with+-- Microsoft SMI Network Management Enterprise Code+vendorSpecificAttribute :: LB.ByteString -> PacketAttribute+vendorSpecificAttribute = VendorSpecificAttribute 311++-- | Encode the MS-MPPE-Send-Key RADIUS attribute as per [RFC2548]+encodeMPPESendKeyAttribute :: Word16 -- ^ 16 bit random salt+ -> ByteString -- ^ MPPE send key+ -> ByteString -- ^ Password+ -> ByteString -- ^ Authenticator in Access-Request message+ -> PacketAttribute+encodeMPPESendKeyAttribute salt key secret authenticator =+ vendorSpecificAttribute . runPut $ encodeMPPEKeyAttribute 16 salt key secret authenticator++-- | Encode the MS-MPPE-Recv-Key RADIUS attribute as per [RFC2548]+encodeMPPERecvKeyAttribute :: Word16 -- ^ 16 bit random salt+ -> ByteString -- ^ MPPE recv key+ -> ByteString -- ^ Password+ -> ByteString -- ^ Authenticator in Access-Request message+ -> PacketAttribute+encodeMPPERecvKeyAttribute salt key secret authenticator =+ vendorSpecificAttribute . runPut $ encodeMPPEKeyAttribute 17 salt key secret authenticator++encodeMPPEKeyAttribute :: Word8+ -> Word16+ -> ByteString+ -> ByteString+ -> ByteString+ -> Put+encodeMPPEKeyAttribute vendorType salt key secret authenticator = do+ putWord8 vendorType+ let salt' = LB.toStrict . runPut . putWord16be $ salt .|. 0x8000 -- MSB in salt must be set+ keyLength = w2c . fromIntegral $ B.length key+ str = B.cons keyLength key+ n = B.length str `mod` 16+ m = if n == 0 then 0 else 16 - n+ str' = str <> B.replicate m '\NUL'+ (_,result) = foldl encrypt ((authenticator <> salt'), B.empty) $ partition 16 str'+ vendorLen = fromIntegral $ 4 + B.length result+ putWord8 vendorLen+ putByteString salt'+ putByteString result+ where md5 = convert . (hash :: ByteString -> Digest MD5)+ partition n = partition' [] n+ partition' acc _ "" = reverse acc+ partition' acc n str =+ let (x, xs) = B.splitAt n str+ in partition' (x:acc) n xs+ encrypt (bytes, acc) chunk =+ let c = pack $ zipWith xor chunk (md5 $ secret <> bytes)+ in (c, acc <> c)++-- | Encode MS-MPPE-Encryption-Policy as per [RFC2548]+encodeMPPEEncryptionPolicyAttribute :: Word32 -- ^ Policy value+ -> PacketAttribute+encodeMPPEEncryptionPolicyAttribute policy =+ vendorSpecificAttribute . runPut $ do+ putWord8 7 -- for MS-MPPE-Encryption-Policy.+ putWord8 6 -- fixed length+ putWord32be policy++-- | Encode MS-MPPE-Encryption-Types as per [RFC2548]+encodeMPPEEncryptionTypesAttribute :: Word32+ -> PacketAttribute -- ^ Encryption types value (see RFC)+encodeMPPEEncryptionTypesAttribute types =+ vendorSpecificAttribute . runPut $ do+ putWord8 8 -- for MS-MPPE-Encryption-Types.+ putWord8 6 -- fixed length+ putWord32be types
src/Network/RADIUS/Types.hs view
@@ -95,7 +95,7 @@ | FramedIPXNetworkAttribute { getFramedIPXNetworkAttribute :: Word32 } | StateAttribute { getStateAttribute :: ByteString } | ClassAttribute { getClassAttribute :: ByteString }- | VendorSpecificAttribute { getVendorSpecificAttributeId :: Word32,+ | VendorSpecificAttribute { getVendorIdAttribute :: Word32, getVendorSpecificAttribute :: ByteString } | SessionTimeoutAttribute { getSessionTimeoutAttribute :: Word32 } | IdleTimeoutAttribute { getIdleTimeoutAttribute :: Word32 }