0 | module Network.TLS.Parse.PEM
2 | import Control.Monad.Trans
4 | import Data.String.Extra
5 | import Data.String.Parser
11 | record PEMBlob where
12 | constructor MkPEMBlob
14 | content : List Bits8
18 | show (MkPEMBlob label content) = label <+> ": " <+> xxd content
20 | is_label_char : Char -> Bool
21 | is_label_char c = (not (isControl c)) && (c /= '-')
23 | label_char : Applicative m => ParseT m Char
24 | label_char = satisfy is_label_char <?> "expected label character"
26 | base64_char : Applicative m => ParseT m Char
27 | base64_char = satisfy is_base64_char <?> "expected base64 character"
29 | takeUntil : Monad m => (stop : String) -> ParseT m ()
31 | let StrCons s top = strM stop
35 | takeUntil' : Monad m' => (s : Char) -> (top : String) -> ParseT m' ()
36 | takeUntil' s top = do
37 | init <- takeWhile (/= s)
38 | skip $
char s <?> "end of string reached - \{show stop} not found"
39 | case !(succeeds $
string top) of
40 | False => takeUntil' s top
44 | parse_pem_blob : Parser PEMBlob
46 | takeUntil "-----BEGIN "
47 | label' <- many label_char
48 | let label = pack label'
51 | content <- many ((some base64_char) <* spaces)
52 | _ <- string "-----END "
56 | case base64_decode $
pack $
concat content of
57 | Right str => pure $
MkPEMBlob label str
58 | Left err => fail $
"failed parsing PEM content: " <+> err
60 | fold_string : String -> String
61 | fold_string str = pack $
foldl (<+>) [] $
map (<+> ['\n']) $
chunk 64 $
unpack str
64 | encode_pem_blob : PEMBlob -> String
65 | encode_pem_blob blob =
66 | "-----BEGIN " <+> blob.label <+> "-----\n"
67 | <+> (fold_string $
base64_encode blob.content)
68 | <+> "-----END " <+> blob.label <+> "-----"