diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013-2014 Vincent Hanquez <vincent@snarc.org>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+asn1dump
+========
+
+Documentation: [asn1dump on hackage](http://hackage.haskell.org/package/asn1dump)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/asn1dump.cabal b/asn1dump.cabal
new file mode 100644
--- /dev/null
+++ b/asn1dump.cabal
@@ -0,0 +1,29 @@
+Name:                asn1dump
+Version:             0.1.0
+Synopsis:            Dump ASN1 structure
+Description:         dump ASN1 structure from file in raw or PEM format.
+License:             BSD3
+License-file:        LICENSE
+Copyright:           Vincent Hanquez <vincent@snarc.org>
+Author:              Vincent Hanquez <vincent@snarc.org>
+Maintainer:          vincent@snarc.org
+Category:            Debug
+Stability:           experimental
+Build-Type:          Simple
+Homepage:            http://github.com/vincenthz/hs-asn1dump
+Cabal-Version:       >=1.8
+data-files:          README.md
+
+Executable           asn1dump
+  Main-Is:           asn1dump.hs
+  ghc-options:       -Wall -fno-warn-missing-signatures
+  Hs-Source-Dirs:    .
+  Build-depends:     base >= 4 && < 5
+                   , bytestring
+                   , asn1-types
+                   , asn1-encoding
+                   , pem
+
+source-repository head
+  type: git
+  location: git://github.com/vincenthz/hs-asn1dump
diff --git a/asn1dump.hs b/asn1dump.hs
new file mode 100644
--- /dev/null
+++ b/asn1dump.hs
@@ -0,0 +1,78 @@
+module Main where
+
+import qualified Data.ByteString as B
+import Data.ASN1.Encoding
+import Data.ASN1.BinaryEncoding
+import Data.ASN1.Types
+import Data.ASN1.BitArray
+import Data.PEM
+import Control.Applicative
+import qualified Data.ByteString.Lazy as L
+import System.Environment
+
+import Numeric
+
+hexdump :: B.ByteString -> String
+hexdump bs = concatMap hex $ B.unpack bs
+    where hex n
+            | n > 0xa   = showHex n ""
+            | otherwise = "0" ++ showHex n ""
+
+hexdump' = hexdump
+
+showASN1 :: Int -> [ASN1] -> IO ()
+showASN1 at = prettyPrint at
+  where
+    indent n = putStr (replicate n ' ')
+
+    prettyPrint n []                 = return ()
+    prettyPrint n (x@(Start _) : xs) = indent n >> p x >> putStrLn "" >> prettyPrint (n+1) xs
+    prettyPrint n (x@(End _) : xs)   = indent (n-1) >> p x >> putStrLn "" >> prettyPrint (n-1) xs
+    prettyPrint n (x : xs)           = indent n >> p x >> putStrLn "" >> prettyPrint n xs
+
+    p (Boolean b)            = putStr ("bool: " ++ show b)
+    p (IntVal i)             = putStr ("int: " ++ showHex i "")
+    p (BitString bits)       = putStr ("bitstring: " ++ (hexdump $ bitArrayGetData bits))
+    p (OctetString bs)       = putStr ("octetstring: " ++ hexdump bs)
+    p (Null)                 = putStr "null"
+    p (OID is)               = putStr ("OID: " ++ show is)
+    p (Real d)               = putStr "real"
+    p (Enumerated _)         = putStr "enum"
+    p (Start Sequence)       = putStr "sequence"
+    p (End Sequence)         = putStr "end-sequence"
+    p (Start Set)            = putStr "set"
+    p (End Set)              = putStr "end-set"
+    p (Start _)              = putStr "container"
+    p (End _)                = putStr "end-container"
+    p (ASN1String cs)        = putCS cs
+    p (ASN1Time TimeUTC time tz)      = putStr ("utctime: " ++ show time)
+    p (ASN1Time TimeGeneralized time tz) = putStr ("generalizedtime: " ++ show time)
+    p (Other tc tn x)        = putStr ("other(" ++ show tc ++ "," ++ show tn ++ ")")
+
+    putCS (ASN1CharacterString UTF8 t)         = putStr ("utf8string:" ++ show t)
+    putCS (ASN1CharacterString Numeric bs)     = putStr "numericstring:"
+    putCS (ASN1CharacterString Printable t)    = putStr ("printablestring: " ++ show t)
+    putCS (ASN1CharacterString T61 bs)         = putStr "t61string:"
+    putCS (ASN1CharacterString VideoTex bs)    = putStr "videotexstring:"
+    putCS (ASN1CharacterString IA5 bs)         = putStr "ia5string:"
+    putCS (ASN1CharacterString Graphic bs)     = putStr "graphicstring:"
+    putCS (ASN1CharacterString Visible bs)     = putStr "visiblestring:"
+    putCS (ASN1CharacterString General bs)     = putStr "generalstring:"
+    putCS (ASN1CharacterString UTF32 t)        = putStr ("universalstring:" ++ show t)
+    putCS (ASN1CharacterString Character bs)   = putStr "characterstring:"
+    putCS (ASN1CharacterString BMP t)          = putStr ("bmpstring: " ++ show t)
+
+showASN1Simple (ASN1String s) =
+    case asn1CharacterToString s of
+        Nothing -> error ("cannot decode ASN1String " ++ show s)
+        Just ds -> "ASN1String " ++ ds
+showASN1Simple x = show x
+
+parseAndPrint a = do
+    r <- head . either error id . pemParseLBS <$> L.readFile a
+    let v = either (error . show) id $ decodeASN1' BER (pemContent r)
+    mapM_ (putStrLn . showASN1Simple) v
+
+main = do
+    args <- getArgs
+    mapM_ parseAndPrint args
