|
Packit |
ae7d4f |
import Test.Tasty.QuickCheck
|
|
Packit |
ae7d4f |
import Test.Tasty
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
import Control.Applicative
|
|
Packit |
ae7d4f |
import Data.ASN1.Get (runGet, Result(..))
|
|
Packit |
ae7d4f |
import Data.ASN1.BitArray
|
|
Packit |
ae7d4f |
import Data.ASN1.Prim
|
|
Packit |
ae7d4f |
import Data.ASN1.Serialize
|
|
Packit |
ae7d4f |
import Data.ASN1.BinaryEncoding.Parse
|
|
Packit |
ae7d4f |
import Data.ASN1.BinaryEncoding.Writer
|
|
Packit |
ae7d4f |
import Data.ASN1.BinaryEncoding
|
|
Packit |
ae7d4f |
import Data.ASN1.Encoding
|
|
Packit |
ae7d4f |
import Data.ASN1.Types
|
|
Packit |
ae7d4f |
import Data.ASN1.Types.Lowlevel
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
import Data.Hourglass
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
import qualified Data.ByteString as B
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
import Control.Monad
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1Class where
|
|
Packit |
ae7d4f |
arbitrary = elements [ Universal, Application, Context, Private ]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1Length where
|
|
Packit |
ae7d4f |
arbitrary = do
|
|
Packit |
ae7d4f |
c <- choose (0,2) :: Gen Int
|
|
Packit |
ae7d4f |
case c of
|
|
Packit |
ae7d4f |
0 -> liftM LenShort (choose (0,0x79))
|
|
Packit |
ae7d4f |
1 -> do
|
|
Packit |
ae7d4f |
nb <- choose (0x80,0x1000)
|
|
Packit |
ae7d4f |
return $ mkSmallestLength nb
|
|
Packit |
ae7d4f |
_ -> return LenIndefinite
|
|
Packit |
ae7d4f |
where
|
|
Packit |
ae7d4f |
nbBytes nb = if nb > 255 then 1 + nbBytes (nb `div` 256) else 1
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryDefiniteLength :: Gen ASN1Length
|
|
Packit |
ae7d4f |
arbitraryDefiniteLength = arbitrary `suchThat` (\l -> l /= LenIndefinite)
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryTag :: Gen ASN1Tag
|
|
Packit |
ae7d4f |
arbitraryTag = choose(1,10000)
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1Header where
|
|
Packit |
ae7d4f |
arbitrary = liftM4 ASN1Header arbitrary arbitraryTag arbitrary arbitrary
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryEvents :: Gen ASN1Events
|
|
Packit |
ae7d4f |
arbitraryEvents = do
|
|
Packit |
ae7d4f |
hdr@(ASN1Header _ _ _ len) <- liftM4 ASN1Header arbitrary arbitraryTag (return False) arbitraryDefiniteLength
|
|
Packit |
ae7d4f |
let blen = case len of
|
|
Packit |
ae7d4f |
LenLong _ x -> x
|
|
Packit |
ae7d4f |
LenShort x -> x
|
|
Packit |
ae7d4f |
_ -> 0
|
|
Packit |
ae7d4f |
pr <- liftM Primitive (arbitraryBSsized blen)
|
|
Packit |
ae7d4f |
return (ASN1Events [Header hdr, pr])
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
newtype ASN1Events = ASN1Events [ASN1Event]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Show ASN1Events where
|
|
Packit |
ae7d4f |
show (ASN1Events x) = show x
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1Events where
|
|
Packit |
ae7d4f |
arbitrary = arbitraryEvents
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryOID :: Gen OID
|
|
Packit |
ae7d4f |
arbitraryOID = do
|
|
Packit |
ae7d4f |
i1 <- choose (0,2) :: Gen Integer
|
|
Packit |
ae7d4f |
i2 <- choose (0,39) :: Gen Integer
|
|
Packit |
ae7d4f |
ran <- choose (0,30) :: Gen Int
|
|
Packit |
ae7d4f |
l <- replicateM ran (suchThat arbitrary (\i -> i > 0))
|
|
Packit |
ae7d4f |
return $ (i1:i2:l)
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryBSsized :: Int -> Gen B.ByteString
|
|
Packit |
ae7d4f |
arbitraryBSsized len = do
|
|
Packit |
ae7d4f |
ws <- replicateM len (choose (0, 255) :: Gen Int)
|
|
Packit |
ae7d4f |
return $ B.pack $ map fromIntegral ws
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary B.ByteString where
|
|
Packit |
ae7d4f |
arbitrary = do
|
|
Packit |
ae7d4f |
len <- choose (0, 529) :: Gen Int
|
|
Packit |
ae7d4f |
arbitraryBSsized len
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary BitArray where
|
|
Packit |
ae7d4f |
arbitrary = do
|
|
Packit |
ae7d4f |
bs <- arbitrary
|
|
Packit |
ae7d4f |
w <- choose (0,7) :: Gen Int
|
|
Packit |
ae7d4f |
return $ toBitArray bs w
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary Date where
|
|
Packit |
ae7d4f |
arbitrary = do
|
|
Packit |
ae7d4f |
y <- choose (1951, 2050)
|
|
Packit |
ae7d4f |
m <- elements [ January .. December]
|
|
Packit |
ae7d4f |
d <- choose (1, 30)
|
|
Packit |
ae7d4f |
return $ normalizeDate $ Date y m d
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
normalizeDate :: Date -> Date
|
|
Packit |
ae7d4f |
normalizeDate origDate
|
|
Packit |
ae7d4f |
| y < 1951 = normalizeDate (Date (y + 50) m d)
|
|
Packit |
ae7d4f |
| otherwise = normalizedDate
|
|
Packit |
ae7d4f |
where
|
|
Packit |
ae7d4f |
normalizedDate@(Date y m d) = timeConvert (timeConvert origDate :: Elapsed)
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary TimeOfDay where
|
|
Packit |
ae7d4f |
arbitrary = do
|
|
Packit |
ae7d4f |
h <- choose (0, 23)
|
|
Packit |
ae7d4f |
mi <- choose (0, 59)
|
|
Packit |
ae7d4f |
se <- choose (0, 59)
|
|
Packit |
ae7d4f |
nsec <- return 0
|
|
Packit |
ae7d4f |
return $ TimeOfDay (Hours h) (Minutes mi) (Seconds se) nsec
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary DateTime where
|
|
Packit |
ae7d4f |
arbitrary = DateTime <$> arbitrary <*> arbitrary
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary TimezoneOffset where
|
|
Packit |
ae7d4f |
arbitrary = elements [ timezone_UTC, TimezoneOffset 60, TimezoneOffset 120, TimezoneOffset (-360) ]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary Elapsed where
|
|
Packit |
ae7d4f |
arbitrary = Elapsed . Seconds <$> arbitrary
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1TimeType where
|
|
Packit |
ae7d4f |
arbitrary = elements [TimeUTC, TimeGeneralized]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1StringEncoding where
|
|
Packit |
ae7d4f |
arbitrary = elements [UTF8, Numeric, Printable, T61, VideoTex, IA5, Graphic, Visible, General, UTF32, BMP]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryPrintString encoding = do
|
|
Packit |
ae7d4f |
let printableString = (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ " ()+,-./:=?")
|
|
Packit |
ae7d4f |
asn1CharacterString encoding <$> replicateM 21 (elements printableString)
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryBS encoding = ASN1CharacterString encoding . B.pack <$> replicateM 7 (choose (0,0xff))
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryIA5String = asn1CharacterString IA5 <$> replicateM 21 (choose (toEnum 0,toEnum 127))
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryUCS2 :: Gen ASN1CharacterString
|
|
Packit |
ae7d4f |
arbitraryUCS2 = asn1CharacterString BMP <$> replicateM 12 (choose (toEnum 0,toEnum 0xffff))
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
arbitraryUnicode :: ASN1StringEncoding -> Gen ASN1CharacterString
|
|
Packit |
ae7d4f |
arbitraryUnicode e = asn1CharacterString e <$> replicateM 35 (choose (toEnum 0,toEnum 0x10ffff))
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1CharacterString where
|
|
Packit |
ae7d4f |
arbitrary = oneof
|
|
Packit |
ae7d4f |
[ arbitraryUnicode UTF8
|
|
Packit |
ae7d4f |
, arbitraryUnicode UTF32
|
|
Packit |
ae7d4f |
, arbitraryUCS2
|
|
Packit |
ae7d4f |
, arbitraryPrintString Numeric
|
|
Packit |
ae7d4f |
, arbitraryPrintString Printable
|
|
Packit |
ae7d4f |
, arbitraryBS T61
|
|
Packit |
ae7d4f |
, arbitraryBS VideoTex
|
|
Packit |
ae7d4f |
, arbitraryIA5String
|
|
Packit |
ae7d4f |
, arbitraryPrintString Graphic
|
|
Packit |
ae7d4f |
, arbitraryPrintString Visible
|
|
Packit |
ae7d4f |
, arbitraryPrintString General
|
|
Packit |
ae7d4f |
]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1 where
|
|
Packit |
ae7d4f |
arbitrary = oneof
|
|
Packit |
ae7d4f |
[ liftM Boolean arbitrary
|
|
Packit |
ae7d4f |
, liftM IntVal arbitrary
|
|
Packit |
ae7d4f |
, liftM BitString arbitrary
|
|
Packit |
ae7d4f |
, liftM OctetString arbitrary
|
|
Packit |
ae7d4f |
, return Null
|
|
Packit |
ae7d4f |
, liftM OID arbitraryOID
|
|
Packit |
ae7d4f |
--, Real Double
|
|
Packit |
ae7d4f |
-- , return Enumerated
|
|
Packit |
ae7d4f |
, ASN1String <$> arbitrary
|
|
Packit |
ae7d4f |
, ASN1Time <$> arbitrary <*> arbitrary <*> arbitrary
|
|
Packit |
ae7d4f |
]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
newtype ASN1s = ASN1s [ASN1]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Show ASN1s where
|
|
Packit |
ae7d4f |
show (ASN1s x) = show x
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
instance Arbitrary ASN1s where
|
|
Packit |
ae7d4f |
arbitrary = do
|
|
Packit |
ae7d4f |
x <- choose (0,5) :: Gen Int
|
|
Packit |
ae7d4f |
z <- case x of
|
|
Packit |
ae7d4f |
4 -> makeList Sequence
|
|
Packit |
ae7d4f |
3 -> makeList Set
|
|
Packit |
ae7d4f |
_ -> resize 2 $ listOf1 arbitrary
|
|
Packit |
ae7d4f |
return $ ASN1s z
|
|
Packit |
ae7d4f |
where
|
|
Packit |
ae7d4f |
makeList str = do
|
|
Packit |
ae7d4f |
(ASN1s l) <- arbitrary
|
|
Packit |
ae7d4f |
return ([Start str] ++ l ++ [End str])
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
prop_header_marshalling_id :: ASN1Header -> Bool
|
|
Packit |
ae7d4f |
prop_header_marshalling_id v = (ofDone $ runGet getHeader $ putHeader v) == Right v
|
|
Packit |
ae7d4f |
where ofDone (Done r _ _) = Right r
|
|
Packit |
ae7d4f |
ofDone _ = Left "not done"
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
prop_event_marshalling_id :: ASN1Events -> Bool
|
|
Packit |
ae7d4f |
prop_event_marshalling_id (ASN1Events e) = (parseLBS $ toLazyByteString e) == Right e
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
prop_asn1_der_marshalling_id v = (decodeASN1 DER . encodeASN1 DER) v `assertEq` Right v
|
|
Packit |
ae7d4f |
where assertEq got expected
|
|
Packit |
ae7d4f |
| got /= expected = error ("got: " ++ show got ++ " expected: " ++ show expected)
|
|
Packit |
ae7d4f |
| otherwise = True
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
marshallingTests = testGroup "Marshalling"
|
|
Packit |
ae7d4f |
[ testProperty "Header" prop_header_marshalling_id
|
|
Packit |
ae7d4f |
, testProperty "Event" prop_event_marshalling_id
|
|
Packit |
ae7d4f |
, testProperty "DER" prop_asn1_der_marshalling_id
|
|
Packit |
ae7d4f |
]
|
|
Packit |
ae7d4f |
|
|
Packit |
ae7d4f |
main = defaultMain $ testGroup "asn1-encoding" [marshallingTests]
|