crypto-pubkey-openssh 0.2.6 → 0.2.7
raw patch · 5 files changed
+230/−26 lines, 5 filesdep ~QuickCheckdep ~asn1-encodingdep ~asn1-typesPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: QuickCheck, asn1-encoding, asn1-types, attoparsec, base, base64-bytestring, bytestring, cereal, crypto-pubkey-types, deepseq, filepath, pem, process, tasty, tasty-quickcheck, temporary
API changes (from Hackage documentation)
Files
- README.md +19/−0
- crypto-pubkey-openssh.cabal +33/−26
- tests/Crypto/PubKey/OpenSsh/Decode/Tests.hs +87/−0
- tests/Crypto/PubKey/OpenSsh/Encode/Tests.hs +20/−0
- tests/SshKeygen.hs +71/−0
+ README.md view
@@ -0,0 +1,19 @@+crypto-pubkey-openssh [](http://travis-ci.org/knsd/crypto-pubkey-openssh)+=====================++OpenSSH keys decoder/encoder, example.++```haskell+import System.Environment (getArgs)+import qualified Data.ByteString as B++import Crypto.PubKey.OpenSsh (decodePrivate)++main :: IO ()+main = do+ fname <- fmap head getArgs+ content <- B.readFile fname+ case decodePrivate content of+ Left e -> error e+ Right key -> print key+```
crypto-pubkey-openssh.cabal view
@@ -1,5 +1,5 @@ Name: crypto-pubkey-openssh-Version: 0.2.6+Version: 0.2.7 Synopsis: OpenSSH keys decoder/encoder Description: OpenSSH keys decoder/encoder License: MIT@@ -17,6 +17,9 @@ Cabal-version: >= 1.12 Tested-with: GHC == 7.6.* +Extra-source-files:+ README.md+ Flag OpenSsh Description: Test with ssh-keygen Default: False@@ -25,15 +28,15 @@ Hs-source-dirs: src Ghc-options: -Wall -fno-warn-orphans Default-language: Haskell2010- Build-depends: base == 4.7.* || == 4.6.* || == 4.5.*- , bytestring == 0.10.* || == 0.9.*- , base64-bytestring == 1.0.*- , cereal == 0.4.*- , attoparsec >= 0.10- , crypto-pubkey-types == 0.4.*- , pem == 0.2.*- , asn1-types == 0.2.*- , asn1-encoding == 0.8.*+ Build-depends: base >= 4.5 && < 5+ , bytestring+ , base64-bytestring+ , cereal+ , attoparsec+ , crypto-pubkey-types+ , pem+ , asn1-types+ , asn1-encoding Exposed-modules: Crypto.PubKey.OpenSsh Other-modules: Crypto.PubKey.OpenSsh.Types@@ -49,23 +52,27 @@ if flag(OpenSsh) cpp-options: -DOPENSSH - Build-depends: base == 4.7.* || == 4.6.* || == 4.5.*- , bytestring == 0.10.* || == 0.9.*- , base64-bytestring == 1.0.*- , cereal == 0.4.*- , attoparsec >= 0.10- , crypto-pubkey-types == 0.4.*- , pem == 0.2.*- , asn1-types == 0.2.*- , asn1-encoding == 0.8.*+ Build-depends: base >= 4.5 && < 5+ , bytestring+ , base64-bytestring+ , cereal+ , attoparsec+ , crypto-pubkey-types+ , pem+ , asn1-types+ , asn1-encoding - , tasty == 0.8.*- , tasty-quickcheck == 0.8.*- , QuickCheck >= 2.6- , temporary == 1.2.* || == 1.1.*- , process == 1.2.*- , filepath == 1.3.*- , deepseq == 1.3.*+ , tasty+ , tasty-quickcheck+ , QuickCheck+ , temporary+ , process+ , filepath+ , deepseq++ Other-modules: Crypto.PubKey.OpenSsh.Encode.Tests+ Crypto.PubKey.OpenSsh.Decode.Tests+ SshKeygen Source-repository head Type: git
+ tests/Crypto/PubKey/OpenSsh/Decode/Tests.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE OverloadedStrings #-}+module Crypto.PubKey.OpenSsh.Decode.Tests+ ( tests+ ) where++import Test.Tasty (TestTree, testGroup)+import Test.Tasty.QuickCheck (testProperty, once)++import Crypto.PubKey.OpenSsh.Decode (decodePublic, decodePrivate)+import Data.ByteString.Char8 ()++testDecodeRSAPublic :: Bool+testDecodeRSAPublic =+ case decodePublic rsaPub of+ Left _ -> False+ Right _ -> True+ where+ rsaPub = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtuy+p1/IHUtofNeUg6Ex2Sc3f0B+97VsfAq65pyKvAAqAtZpR96Vr35hbaNEb+j3fpAXjrxouM87q5KksWD+0qFWNhDv7rBg6ENQJNLf5lfssiFacrVv1/SG2UP8VDkCMxpJyzcHE5ajmSzcjEFoerRudV2g05PPlw4fNyuhVaMQjNUejg+17CUPS8e7TxUoRvnVuBVSMezMn11n81djakzuit7nXj1L7WVqNHtAlbstK2aDdCB3yBOtOwBQVwvFwQfHpQ8hwrYoKAXPw3YTd9sPTtJ0qz0cZH89t7redHABRhOWdf7+cm0LpubqwWvv0SLlFRMwefoMsGcnJ6E7P tommd@Vodka"++testDecodeRSAPrivate :: Bool+testDecodeRSAPrivate =+ case decodePrivate rsaPriv of+ Left _ -> False+ Right _ -> True+ where+ rsaPriv = "-----BEGIN RSA PRIVATE KEY-----\n\+\MIIEpAIBAAKCAQEAw6s7oDCoXjEkrLDRVZDyWLVaiqxZyOTA33TyGSELv9ZiQzkr\n\+\ti+AOyuTWkmZjHYdLDWBYYQvwEjufzneHvNLw87/1zsQrd6ZPUwEOkh0RqG9mxoV\n\+\JFgpruzKoG6BNgnUti/S9idErit+XEx9ff8bmmjawdC10czAdL3zCpZaEXw4JAwC\n\+\sgQB1J1/Mw4cnzMqKyxPtSPZjhiZZ6y2bVCfNfnOZ9dvIDa/unEWlFSDPjX0+zSM\n\+\mjRzDoE04jtoAI0v3iynZ26kea+YU4oni2MQ7EL4Y1CmLAWm4/9APhf3Xt0EJOIt\n\+\Ngv1j2468+8WF5aTEitb8D2ZRFYPiLWMaJlhGwIDAQABAoIBAQCWAPXLDsJkw4P8\n\+\J+mzkVVZEF8DJLIIQuZh6MOY5C6fuPjH1FJgbvX9ZqCmfPoMJpiixboUSkRZQxAj\n\+\1Pcl/xq8WDrmg897m8UaquYq0FTjuScketBudnAuPDXy3ASOqua5bNxr/Rq383wB\n\+\wloKd8Jvk6bxItHgrvl0BhMGsNEHyT36SXmc7HsgCzifuXMo5E3uqTGP/+wLWCRy\n\+\NO+AqStSjQbQZtLVOvNdQYknv+uqm/m5LyO1Vi2pPl0vEgpwiq4C/8W+YT2ya3dz\n\+\QfG+Fsewu5WDdHTBgTN4F/p2tgG6Zg+fdfRkF2NNwJXiGb1TTmR1IMZtzqDQ5mys\n\+\dk40xuAxAoGBAOTMhUpINw2rSaduEWAxnSAZFMAIozKBOJD1Q2+kYbYMHPOPN+CN\n\+\NCUrWpEiFa+vM+BIrQsG6M7Nb9VmefOKuS7vetIUYWsJ2hO8oX2+8ZiPcBwU3izX\n\+\wAoGq0yeUaG4yGZUrkP2Gfm+jUdj/AoGOnG9pd/CYDevVNnOSyWko8RVAoGBANru\n\+\Zupv8fIXDcnqYGBAbHpBQkojAzccBHxyE/4BUJlFIZWDAMem50op49SsF6gKrxtO\n\+\IvXb1+58axGza84F7cXmQgR0nV8AXMzBlI31HyvftMv8Yb1h+oXbjCFI99lMz6/F\n\+\jkCSzoiLGo0NAEmqRb4TThSjj8vfiw+zxsllQH+vAoGAFmKcN+RQ3pl/n035jTvN\n\+\b7KEgTVXIj3aVvRoIKgolzMgMgQ1J1cpXuma9tAq5wFxReRWadnHNVSMOIjKLbXI\n\+\4Hq1vZAY5+wS1hOCiVcBNDf0dArmoeSJ+XElmV10ByqZEMoAMs4FRJYMJIv3wNNT\n\+\LIWtkPLnjwssdhLk703oZ/ECgYB/4JCsjwa7aUvcjNIOZpL2NfgKZbkTD4JvThLv\n\+\YsU5QXAEbKif9ZVTdHRnXL3Uoaj2QgWZpffSjUnc5PgrNrtTxNL610K0ovmRf+DN\n\+\qkey0NBB9gEBJaG3Xi3To1Nh0cPd337fqOCKUPYJPXbVkGd8Rrpsw7zSUJhha5jJ\n\+\OiMacQKBgQCxDCTOUqDksmXkDutXi/f/dMIwfMXaNuTc3ectyaBC05+0B10uLfnv\n\+\7jurNd89OFTHsu7CLfbwDzu+Q+GWTWemUk2ieq9z0Ct5aIzjxoALNnKiu5pH1YDH\n\+\Mf6ApFppkCpTkQ0sEERn0zH/hNQct1cwflfQi7JN+3GGax7oySmQRQ==\n\+\-----END RSA PRIVATE KEY-----"++testDecodeDSAPublic :: Bool+testDecodeDSAPublic =+ case decodePublic dsaPub of+ Left _ -> False+ Right _ -> True+ where+ dsaPub = "ssh-dss AAAAB3NzaC1kc3MAAACBALco1Yeq0uPETFRf72VbmH+sMttQMbs1GRF+9vbkI7GJZtaRCE2+jtVSiFXDBm4Yuxf+pqvdQ6Jl1X/zuED/YzN2GIVhHMzy12KQ27E8B63vIP/hhLaYv7Tw00yE7HzxBrbx4rfdkPguam0Mjzqhck4cwVKsKhuSinaGTwqMF+KRAAAAFQCziBsxBGOF2YDzsXnBs+Jv0p2GewAAAIEAiCaFUZcLEO5WTAi/lQNo42ZyXP2rl1jeugPVCtDSWhSEHU1EIJcmmCx//ofaOz/X2uJAv15ZjLY8xZW41N2wHA64mhjaXzBBUeVqAOgoYW8dQOo2XNFmU7idWsYxhsUUknWDf9A6v4blUgQNHn1u8c4Y3xcfCEHfZB6om6XA7aAAAACAI3H1hNNXWzd5Fuqpj1ZeUKFAOfFbYeD3XBIKwwMPdrVZW/PMJ3s+Ic90V0paKBA0+Sgvg+EHWK213+zEp29+lL50Nne7jh//smQ0zBKMiRre7iZ+rEDM4nWZOM3vzClfgilTDkkQ4TCjz7yMm21ZqApt+Lq5uNOK6DJB4PszCwI= tommd@Vodka"++testDecodeDSAPrivate :: Bool+testDecodeDSAPrivate =+ case decodePrivate dsaPriv of+ Left _ -> False+ Right _ -> True+ where+ dsaPriv = "-----BEGIN DSA PRIVATE KEY-----\n\+\MIIBuwIBAAKBgQC3KNWHqtLjxExUX+9lW5h/rDLbUDG7NRkRfvb25COxiWbWkQhN\n\+\vo7VUohVwwZuGLsX/qar3UOiZdV/87hA/2MzdhiFYRzM8tdikNuxPAet7yD/4YS2\n\+\mL+08NNMhOx88Qa28eK33ZD4LmptDI86oXJOHMFSrCobkop2hk8KjBfikQIVALOI\n\+\GzEEY4XZgPOxecGz4m/SnYZ7AoGBAIgmhVGXCxDuVkwIv5UDaONmclz9q5dY3roD\n\+\1QrQ0loUhB1NRCCXJpgsf/6H2js/19riQL9eWYy2PMWVuNTdsBwOuJoY2l8wQVHl\n\+\agDoKGFvHUDqNlzRZlO4nVrGMYbFFJJ1g3/QOr+G5VIEDR59bvHOGN8XHwhB32Qe\n\+\qJulwO2gAoGAI3H1hNNXWzd5Fuqpj1ZeUKFAOfFbYeD3XBIKwwMPdrVZW/PMJ3s+\n\+\Ic90V0paKBA0+Sgvg+EHWK213+zEp29+lL50Nne7jh//smQ0zBKMiRre7iZ+rEDM\n\+\4nWZOM3vzClfgilTDkkQ4TCjz7yMm21ZqApt+Lq5uNOK6DJB4PszCwICFAG6JRA/\n\+\iyaf5dPPUem5PxQeKx1b\n\+\-----END DSA PRIVATE KEY-----"++tests :: TestTree+tests = testGroup "Crypto.PubKey.OpenSsh.Decode.Tests"+ [ testProperty "Decode Public RSA" $ once testDecodeRSAPublic+ , testProperty "Decode Private RSA" $ once testDecodeRSAPrivate+ , testProperty "Decode Public DSA" $ once testDecodeDSAPublic+ , testProperty "Decode Private DSA" $ once testDecodeDSAPrivate+ ]
+ tests/Crypto/PubKey/OpenSsh/Encode/Tests.hs view
@@ -0,0 +1,20 @@+module Crypto.PubKey.OpenSsh.Encode.Tests+ ( tests+ ) where++import Control.DeepSeq (deepseq)+import Data.Word (Word8)++import Test.Tasty (TestTree, testGroup)+import Test.Tasty.QuickCheck (testProperty)++import Crypto.PubKey.OpenSsh.Encode (fixZeroByte)++-- | In version 0.2.0 `fixZeroByte` function fails with empty input+testFixZeroByte :: [Word8] -> Bool+testFixZeroByte i = fixZeroByte i `deepseq` True++tests :: TestTree+tests = testGroup "Crypto.PubKey.OpenSsh.Encode.Tests"+ [ testProperty "regression test testFixZeroByte" testFixZeroByte+ ]
+ tests/SshKeygen.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE TypeSynonymInstances #-}++module SshKeygen where++import Data.Monoid ((<>))+import System.FilePath.Posix ((</>), (<.>))+import System.Process (runCommand, waitForProcess)+import System.IO.Temp (withSystemTempDirectory)+import qualified Data.ByteString.Char8 as SB++import Test.Tasty (TestTree, testGroup)+import Test.Tasty.QuickCheck (Property, Arbitrary(..), elements, suchThat, testProperty)+import Test.QuickCheck.Monadic (monadicIO, run, assert)++import Crypto.PubKey.OpenSsh.Types (OpenSshKeyType(..), OpenSshPublicKey(..),+ OpenSshPrivateKey(..))+import Crypto.PubKey.OpenSsh (encodePublic, decodePublic,+ encodePrivate, decodePrivate)++import qualified Crypto.PubKey.OpenSsh.Encode.Tests++type StrictByteString = SB.ByteString+type PrivateKey = StrictByteString+type PublicKey = StrictByteString++instance Arbitrary OpenSshKeyType where+ arbitrary = elements [OpenSshKeyTypeRsa, OpenSshKeyTypeDsa]++openSshKeys :: OpenSshKeyType -> IO (PrivateKey, PublicKey)+openSshKeys t = withSystemTempDirectory base $ \dir -> do+ let path = dir </> typ+ let run = "ssh-keygen -t " <> typ <> " -N \"\" -f " <> path+ waitForProcess =<< runCommand run+ priv <- SB.readFile $ path+ pub <- fmap SB.init $ SB.readFile $ path <.> "pub"+ return (priv, pub)+ where+ base = "crypto-pubkey-openssh-tests"+ typ = case t of+ OpenSshKeyTypeRsa -> "rsa"+ OpenSshKeyTypeDsa -> "dsa"++testWithOpenSsh :: OpenSshKeyType -> Property+testWithOpenSsh t = monadicIO $ do+ (priv, pub) <- run $ openSshKeys t+ assert $ checkPublic (decodePublic pub) pub+ assert $ checkPrivate (decodePrivate priv) priv+ where+ checkPublic = case t of+ OpenSshKeyTypeRsa -> \r b -> case r of+ Right k@(OpenSshPublicKeyRsa _ _) ->+ encodePublic k == b+ _ -> False+ OpenSshKeyTypeDsa -> \r b -> case r of+ Right k@(OpenSshPublicKeyDsa _ _) ->+ encodePublic k == b+ _ -> False+ checkPrivate = case t of+ OpenSshKeyTypeRsa -> \r b -> case r of+ Right k@(OpenSshPrivateKeyRsa _) ->+ encodePrivate k == b+ _ -> False+ OpenSshKeyTypeDsa -> \r b -> case r of+ Right k@(OpenSshPrivateKeyDsa _ _) ->+ encodePrivate k == b+ _ -> False++tests :: TestTree+tests = testGroup "SshKeygen"+ [ testProperty "decode/encode" $ testWithOpenSsh+ ]