summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2013-11-04 01:22:24 -0500
committerjoe <joe@jerkface.net>2013-11-04 01:22:24 -0500
commite80d9038d89b2f298ae94fafe058e5f18cb03ff0 (patch)
tree7a517fbc4e1de477c1cf2568953ca46701701f4f
parent67df213456f470ba7e46b6193550bb28eabfb7e7 (diff)
Ability to output public keys in PEM format.
-rw-r--r--kiki.hs94
1 files changed, 89 insertions, 5 deletions
diff --git a/kiki.hs b/kiki.hs
index 2194059..e8ef2ad 100644
--- a/kiki.hs
+++ b/kiki.hs
@@ -9,6 +9,7 @@ module Main where
9 9
10import Debug.Trace 10import Debug.Trace
11import GHC.Exts (Down(..)) 11import GHC.Exts (Down(..))
12import Data.Tuple
12import Data.Binary 13import Data.Binary
13import Data.OpenPGP 14import Data.OpenPGP
14import qualified Data.ByteString.Lazy as L 15import qualified Data.ByteString.Lazy as L
@@ -34,6 +35,7 @@ import Crypto.Random (newGenIO,SystemRandom)
34import Data.ASN1.Types 35import Data.ASN1.Types
35import Data.ASN1.Encoding 36import Data.ASN1.Encoding
36import Data.ASN1.BinaryEncoding 37import Data.ASN1.BinaryEncoding
38import Data.ASN1.BitArray
37import Control.Applicative 39import Control.Applicative
38import System.Environment 40import System.Environment
39import System.Directory 41import System.Directory
@@ -50,17 +52,45 @@ import System.Posix.Files
50import Data.Monoid ((<>)) 52import Data.Monoid ((<>))
51-- import Data.X509 53-- import Data.X509
52 54
55unprefix c spec = if null (snd p) then swap p else (fst p, tail (snd p))
56 where p = break (==c) spec
57
58
53data RSAPublicKey = RSAKey MPI MPI deriving Show 59data RSAPublicKey = RSAKey MPI MPI deriving Show
54 60
55instance ASN1Object RSAPublicKey where 61instance ASN1Object RSAPublicKey where
62 {-
63 -- PKCS #1 RSA Public Key
56 toASN1 (RSAKey (MPI n) (MPI e)) 64 toASN1 (RSAKey (MPI n) (MPI e))
57 = \xs -> Start Sequence 65 = \xs -> Start Sequence
58 : IntVal n 66 : IntVal n
59 : IntVal e 67 : IntVal e
60 : End Sequence 68 : End Sequence
61 : xs 69 : xs
70 -}
71
72 -- PKCS #8 Public key data
73 toASN1 (RSAKey (MPI n) (MPI e))
74 = \xs -> Start Sequence
75 : Start Sequence
76 : OID [1,2,840,113549,1,1,1]
77 : End Sequence
78 : BitString (toBitArray bs 0)
79 : End Sequence
80 : xs
81 where
82 pubkey = Start Sequence : IntVal n : IntVal e : End Sequence : []
83 bs = encodeASN1' DER pubkey
84
62 fromASN1 (Start Sequence:IntVal modulus:IntVal pubexp:End Sequence:xs) = 85 fromASN1 (Start Sequence:IntVal modulus:IntVal pubexp:End Sequence:xs) =
63 Right (RSAKey (MPI modulus) (MPI pubexp) , xs) 86 Right (RSAKey (MPI modulus) (MPI pubexp) , xs)
87 fromASN1 (Start Sequence:Start Sequence:OID [1,2,840,113549,1,1,1]:End Sequence:BitString b:End Sequence:xs) =
88 case decodeASN1' DER bs of
89 Right as -> fromASN1 as
90 Left e -> Left ("fromASN1: RSAPublicKey: "++show e)
91 where
92 BitArray _ bs = b
93
64 fromASN1 _ = 94 fromASN1 _ =
65 Left "fromASN1: RSAPublicKey: unexpected format" 95 Left "fromASN1: RSAPublicKey: unexpected format"
66 96
@@ -758,6 +788,10 @@ getPassphrase cmd =
758 788
759#define HOMEOPTION (def &= explicit &= name "homedir" &= typDir ) 789#define HOMEOPTION (def &= explicit &= name "homedir" &= typDir )
760 790
791data KeySpec =
792 KeyGrip String
793 | KeyTag Packet String
794
761main = do 795main = do
762 args <- cmdArgs $ modes 796 args <- cmdArgs $ modes
763 [ List HOMEOPTION 797 [ List HOMEOPTION
@@ -1041,8 +1075,39 @@ main = do
1041 1075
1042 doCmd cmd@(CatPub {}) = do 1076 doCmd cmd@(CatPub {}) = do
1043 let spec:files = catpub_args cmd 1077 let spec:files = catpub_args cmd
1044 putStrLn $ "spec = " ++show spec 1078 let (topspec,subspec) = unprefix '/' spec
1079 (toptyp,top) = unprefix ':' topspec
1080 (subtyp,sub) = unprefix ':' subspec
1081
1082 {-
1045 putStrLn $ "files = " ++ show files 1083 putStrLn $ "files = " ++ show files
1084 putStrLn $ "topspec = " ++show (toptyp,top)
1085 putStrLn $ "subspec = " ++show (subtyp,sub)
1086 -}
1087 ( homedir -- e3ozbhvej4jvlu43.onion/gpg/gnupghome
1088 , sec -- e3ozbhvej4jvlu43.onion/gpg/gnupghome/secring.gpg
1089 , grip -- Just "AD1CA892FCF4ED9829C762269BDEA5B4D5643321"
1090 ) <- getPGPEnviron cmd
1091
1092 flip (maybe (error "No working key?")) grip $ \grip -> do
1093
1094 let (pre, wk:subs) = seek_key (KeyGrip grip) sec
1095 (xs,ys) = seek_key (KeyTag wk sub) subs
1096 when (not (null ys)) $ do
1097 let k = head ys
1098 rsa = fromJust $ rsaKeyFromPacket k
1099 der = encodeASN1 DER (toASN1 rsa [])
1100 qq = Base64.encode (L.unpack der)
1101 split64 [] = []
1102 split64 qq = as : split64 bs where (as,bs) = splitAt 64 qq
1103 {-
1104 putStrLn $ fingerprint k
1105 putStrLn $ show rsa
1106 putStrLn $ show der
1107 -}
1108 putStr $ unlines (["-----BEGIN PUBLIC KEY-----"]
1109 ++split64 qq
1110 ++["-----END PUBLIC KEY-----"])
1046 return () 1111 return ()
1047 1112
1048 doCmd cmd@(Add {}) = do 1113 doCmd cmd@(Add {}) = do
@@ -1054,7 +1119,7 @@ main = do
1054 1119
1055 flip (maybe (error "No working key?")) grip $ \grip -> do 1120 flip (maybe (error "No working key?")) grip $ \grip -> do
1056 1121
1057 let (pre, wk:subs) = seek_key grip sec 1122 let (pre, wk:subs) = seek_key (KeyGrip grip) sec
1058 wkun = if symmetric_algorithm wk == Unencrypted 1123 wkun = if symmetric_algorithm wk == Unencrypted
1059 then Just wk 1124 then Just wk
1060 else do 1125 else do
@@ -1079,7 +1144,7 @@ main = do
1079 Message parsedkey <- readKeyFromFile False secfmt secfile 1144 Message parsedkey <- readKeyFromFile False secfmt secfile
1080 1145
1081 let pkf = fingerprint (head parsedkey) 1146 let pkf = fingerprint (head parsedkey)
1082 (prepk,pks) = seek_key pkf subkeys' 1147 (prepk,pks) = seek_key (KeyGrip pkf) subkeys'
1083 1148
1084 if not (null pks) 1149 if not (null pks)
1085 then existingKey (prepk,pks) remainder wkun wk parsedkey (key_usage cmd) pre uids subkeys (output cmd) grip 1150 then existingKey (prepk,pks) remainder wkun wk parsedkey (key_usage cmd) pre uids subkeys (output cmd) grip
@@ -1283,10 +1348,29 @@ groupBindings pub =
1283 gs = {- filter matchgrip $ -} groupBy sameMaster (sortBy (comparing code) bindings') 1348 gs = {- filter matchgrip $ -} groupBy sameMaster (sortBy (comparing code) bindings')
1284 in gs 1349 in gs
1285 1350
1351isTopKey p@(SecretKeyPacket {}) | not (is_subkey p) = True
1352isTopKey p@(PublicKeyPacket {}) | not (is_subkey p) = True
1353isTopKey _ = False
1286 1354
1287seek_key :: String -> [Packet] -> ([Packet],[Packet]) 1355seek_key :: KeySpec -> [Packet] -> ([Packet],[Packet])
1288seek_key grip sec = (pre, subs) 1356seek_key (KeyGrip grip) sec = (pre, subs)
1289 where 1357 where
1290 (pre,subs) = break pred sec 1358 (pre,subs) = break pred sec
1291 pred p@(SecretKeyPacket {}) = matchpr grip p == grip 1359 pred p@(SecretKeyPacket {}) = matchpr grip p == grip
1292 pred _ = False 1360 pred _ = False
1361
1362seek_key (KeyTag key tag) ps = if null bs || null qs
1363 then (ps,[])
1364 else (reverse (tail qs), head qs : reverse rs ++ bs)
1365 where
1366 (as,bs) = break (\p -> isSignaturePacket p
1367 && has_tag tag p
1368 && isJust (signature_issuer p)
1369 && matchpr (fromJust $ signature_issuer p) key == fromJust (signature_issuer p) )
1370 ps
1371 (rs,qs) = break isKey (reverse as)
1372
1373 has_tag tag p = tag `elem` mapMaybe usage (hashed_subpackets p)
1374 || tag `elem` map usageString (mapMaybe keyflags (hashed_subpackets p))
1375
1376groupTops ps = groupBy (\_ b -> not (isTopKey b)) ps