diff options
author | joe <joe@jerkface.net> | 2013-11-04 01:22:24 -0500 |
---|---|---|
committer | joe <joe@jerkface.net> | 2013-11-04 01:22:24 -0500 |
commit | e80d9038d89b2f298ae94fafe058e5f18cb03ff0 (patch) | |
tree | 7a517fbc4e1de477c1cf2568953ca46701701f4f | |
parent | 67df213456f470ba7e46b6193550bb28eabfb7e7 (diff) |
Ability to output public keys in PEM format.
-rw-r--r-- | kiki.hs | 94 |
1 files changed, 89 insertions, 5 deletions
@@ -9,6 +9,7 @@ module Main where | |||
9 | 9 | ||
10 | import Debug.Trace | 10 | import Debug.Trace |
11 | import GHC.Exts (Down(..)) | 11 | import GHC.Exts (Down(..)) |
12 | import Data.Tuple | ||
12 | import Data.Binary | 13 | import Data.Binary |
13 | import Data.OpenPGP | 14 | import Data.OpenPGP |
14 | import qualified Data.ByteString.Lazy as L | 15 | import qualified Data.ByteString.Lazy as L |
@@ -34,6 +35,7 @@ import Crypto.Random (newGenIO,SystemRandom) | |||
34 | import Data.ASN1.Types | 35 | import Data.ASN1.Types |
35 | import Data.ASN1.Encoding | 36 | import Data.ASN1.Encoding |
36 | import Data.ASN1.BinaryEncoding | 37 | import Data.ASN1.BinaryEncoding |
38 | import Data.ASN1.BitArray | ||
37 | import Control.Applicative | 39 | import Control.Applicative |
38 | import System.Environment | 40 | import System.Environment |
39 | import System.Directory | 41 | import System.Directory |
@@ -50,17 +52,45 @@ import System.Posix.Files | |||
50 | import Data.Monoid ((<>)) | 52 | import Data.Monoid ((<>)) |
51 | -- import Data.X509 | 53 | -- import Data.X509 |
52 | 54 | ||
55 | unprefix c spec = if null (snd p) then swap p else (fst p, tail (snd p)) | ||
56 | where p = break (==c) spec | ||
57 | |||
58 | |||
53 | data RSAPublicKey = RSAKey MPI MPI deriving Show | 59 | data RSAPublicKey = RSAKey MPI MPI deriving Show |
54 | 60 | ||
55 | instance ASN1Object RSAPublicKey where | 61 | instance 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 | ||
791 | data KeySpec = | ||
792 | KeyGrip String | ||
793 | | KeyTag Packet String | ||
794 | |||
761 | main = do | 795 | main = 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 | ||
1351 | isTopKey p@(SecretKeyPacket {}) | not (is_subkey p) = True | ||
1352 | isTopKey p@(PublicKeyPacket {}) | not (is_subkey p) = True | ||
1353 | isTopKey _ = False | ||
1286 | 1354 | ||
1287 | seek_key :: String -> [Packet] -> ([Packet],[Packet]) | 1355 | seek_key :: KeySpec -> [Packet] -> ([Packet],[Packet]) |
1288 | seek_key grip sec = (pre, subs) | 1356 | seek_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 | |||
1362 | seek_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 | |||
1376 | groupTops ps = groupBy (\_ b -> not (isTopKey b)) ps | ||