diff options
author | Joe Crayne <joe@jerkface.net> | 2020-05-09 20:59:11 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-05-09 20:59:11 -0400 |
commit | 71048681d402d5f692bf293a2785dc83fb32d384 (patch) | |
tree | 6f327490f18ce1475479a4b959ed68c8c6ad49ed | |
parent | 8b9d7cfbb69aacb13be754c8dc94e985f60f5aea (diff) |
Added sign command to make detached signatures.
-rw-r--r-- | kiki.hs | 16 | ||||
-rw-r--r-- | lib/KeyDB.hs | 27 | ||||
-rw-r--r-- | lib/Kiki.hs | 51 | ||||
-rw-r--r-- | lib/Transforms.hs | 13 |
4 files changed, 91 insertions, 16 deletions
@@ -1636,6 +1636,21 @@ kiki "verify" argvals = | |||
1636 | Left er -> hPutStrLn stderr $ usageErrorMessage er | 1636 | Left er -> hPutStrLn stderr $ usageErrorMessage er |
1637 | Right io -> io | 1637 | Right io -> io |
1638 | 1638 | ||
1639 | kiki "sign" args | "--help" `elem` args = do | ||
1640 | putStr . unlines $ | ||
1641 | [ "kiki sign [--homedir HOMEDIR | --homeless] [[--keyring FILE] ...] --with-key KEYID FILE" | ||
1642 | ] | ||
1643 | kiki "sign" argvals = | ||
1644 | let opts = [("--homedir",1),("--keyring",1),("--homeless",0),("--with-key",1)] | ||
1645 | in case runArgs (parseInvocation (fancy opts [] "") argvals) | ||
1646 | (signFile <$> flag "--homeless" | ||
1647 | <*> dashdashHomedir | ||
1648 | <*> args "--keyring" | ||
1649 | <*> arg "--with-key" | ||
1650 | <*> param 0) of | ||
1651 | Left er -> hPutStrLn stderr $ usageErrorMessage er | ||
1652 | Right io -> io | ||
1653 | |||
1639 | kiki cmd args = hPutStrLn stderr $ "I don't know how to "++cmd++"." | 1654 | kiki cmd args = hPutStrLn stderr $ "I don't know how to "++cmd++"." |
1640 | 1655 | ||
1641 | sshkeyname :: Packet -> [FilePath] | 1656 | sshkeyname :: Packet -> [FilePath] |
@@ -1684,6 +1699,7 @@ commands = | |||
1684 | -- also repairs signature and adds missing cross-certification. | 1699 | -- also repairs signature and adds missing cross-certification. |
1685 | , ( "tar", "import or export system key files in tar format" ) | 1700 | , ( "tar", "import or export system key files in tar format" ) |
1686 | , ( "verify", "Check a clear-sign pgp signature." ) | 1701 | , ( "verify", "Check a clear-sign pgp signature." ) |
1702 | , ( "sign", "Create a detached signature for a given file.") | ||
1687 | ] | 1703 | ] |
1688 | 1704 | ||
1689 | main :: IO () | 1705 | main :: IO () |
diff --git a/lib/KeyDB.hs b/lib/KeyDB.hs index fd0a9ce..fc20b91 100644 --- a/lib/KeyDB.hs +++ b/lib/KeyDB.hs | |||
@@ -4,7 +4,7 @@ module KeyDB | |||
4 | , SigAndTrust | 4 | , SigAndTrust |
5 | , SubKey(..) | 5 | , SubKey(..) |
6 | , KeyData(..) | 6 | , KeyData(..) |
7 | , KeyDB | 7 | , KeyDB(..) |
8 | , KeyGrip(..) | 8 | , KeyGrip(..) |
9 | , emptyKeyDB | 9 | , emptyKeyDB |
10 | , keyData | 10 | , keyData |
@@ -68,6 +68,7 @@ data KeyData = KeyData | |||
68 | 68 | ||
69 | 69 | ||
70 | newtype KeyGrip = KeyInt Int | 70 | newtype KeyGrip = KeyInt Int |
71 | deriving Eq | ||
71 | 72 | ||
72 | fingerprintGrip :: Fingerprint -> KeyGrip | 73 | fingerprintGrip :: Fingerprint -> KeyGrip |
73 | fingerprintGrip (Fingerprint bs) = | 74 | fingerprintGrip (Fingerprint bs) = |
@@ -109,10 +110,20 @@ kkData db = Map.toList (byKeyKey db) | |||
109 | lookupKeyData :: KeyKey -> KeyDB -> Maybe KeyData | 110 | lookupKeyData :: KeyKey -> KeyDB -> Maybe KeyData |
110 | lookupKeyData kk db = Map.lookup kk (byKeyKey db) | 111 | lookupKeyData kk db = Map.lookup kk (byKeyKey db) |
111 | 112 | ||
112 | lookupByGrip :: KeyGrip -> KeyDB -> [KeyData] | 113 | lookupByGrip :: KeyGrip -> KeyDB -> [(MappedPacket,KeyData)] |
113 | lookupByGrip k db = mapMaybe (`Map.lookup` byKeyKey db) | 114 | lookupByGrip k db = do |
114 | $ concat . maybeToList | 115 | kk <- concat $ maybeToList $ I.lookup k (byGrip db) |
115 | $ I.lookup k (byGrip db) | 116 | case Map.lookup kk (byKeyKey db) of |
117 | Just kd | fingerprintGrip (fingerprint (packet $ keyMappedPacket kd)) == k -> [(keyMappedPacket kd, kd)] | ||
118 | | otherwise -> do | ||
119 | sub <- associatedKeys kd | ||
120 | guard (mpGrip sub == k) | ||
121 | [ (sub, kd) ] | ||
122 | Nothing -> do | ||
123 | kd <- Map.elems (byKeyKey db) | ||
124 | sub <- associatedKeys kd | ||
125 | guard (mpGrip sub == k) | ||
126 | [ (sub, kd) ] | ||
116 | 127 | ||
117 | transmute :: (Monad m, Monad kiki, Traversable kiki) => | 128 | transmute :: (Monad m, Monad kiki, Traversable kiki) => |
118 | ((KeyData, [info]) -> opcode -> m (kiki (KeyData, [info]))) -- ^ interpreter | 129 | ((KeyData, [info]) -> opcode -> m (kiki (KeyData, [info]))) -- ^ interpreter |
@@ -137,14 +148,14 @@ associatedKeys kd = keyMappedPacket kd : [ k | SubKey k _ <- Map.elems (keySubKe | |||
137 | alterKeyDB :: (Maybe KeyData -> Maybe KeyData) -> KeyKey -> KeyDB -> KeyDB | 148 | alterKeyDB :: (Maybe KeyData -> Maybe KeyData) -> KeyKey -> KeyDB -> KeyDB |
138 | alterKeyDB update kk db = db | 149 | alterKeyDB update kk db = db |
139 | { byKeyKey = Map.alter update kk (byKeyKey db) | 150 | { byKeyKey = Map.alter update kk (byKeyKey db) |
140 | , byGrip = case Map.lookup kk (byKeyKey db) of | 151 | , byGrip = {- case Map.lookup kk (byKeyKey db) of |
141 | Just _ -> byGrip db | 152 | Just _ -> byGrip db |
142 | Nothing -> case update Nothing of | 153 | Nothing -> -} case update Nothing of |
143 | Just kd -> let go g m = I.alter (\case Nothing -> Just [kk] | 154 | Just kd -> let go g m = I.alter (\case Nothing -> Just [kk] |
144 | Just kks -> Just $ mergeL [kk] kks) | 155 | Just kks -> Just $ mergeL [kk] kks) |
145 | g | 156 | g |
146 | m | 157 | m |
147 | in foldr go (byGrip db) $ map mpGrip $ associatedKeys kd | 158 | in foldr go (byGrip db) $ map mpGrip $ filter (isKey . packet) $ associatedKeys kd |
148 | Nothing -> byGrip db | 159 | Nothing -> byGrip db |
149 | } | 160 | } |
150 | 161 | ||
diff --git a/lib/Kiki.hs b/lib/Kiki.hs index 9513b0f..f89aad2 100644 --- a/lib/Kiki.hs +++ b/lib/Kiki.hs | |||
@@ -1,7 +1,8 @@ | |||
1 | {-# LANGUAGE NamedFieldPuns #-} | 1 | {-# LANGUAGE LambdaCase #-} |
2 | {-# LANGUAGE RecordWildCards #-} | 2 | {-# LANGUAGE NamedFieldPuns #-} |
3 | {-# LANGUAGE ViewPatterns #-} | ||
4 | {-# LANGUAGE OverloadedStrings #-} | 3 | {-# LANGUAGE OverloadedStrings #-} |
4 | {-# LANGUAGE RecordWildCards #-} | ||
5 | {-# LANGUAGE ViewPatterns #-} | ||
5 | module Kiki | 6 | module Kiki |
6 | ( module Kiki | 7 | ( module Kiki |
7 | , setVerifyFlag | 8 | , setVerifyFlag |
@@ -48,9 +49,11 @@ import qualified SSHKey as SSH | |||
48 | import CommandLine | 49 | import CommandLine |
49 | import DotLock | 50 | import DotLock |
50 | import GnuPGAgent (Query (..)) | 51 | import GnuPGAgent (Query (..)) |
52 | import qualified IntMapClass as I | ||
51 | import KeyRing hiding (pemFromPacket) | 53 | import KeyRing hiding (pemFromPacket) |
52 | import KeyDB | 54 | import KeyDB |
53 | import KeyRing.BuildKeyDB (gpgipv6addr, Hostnames, allNames) | 55 | import KeyRing.BuildKeyDB (gpgipv6addr, Hostnames, allNames) |
56 | import TimeUtil | ||
54 | 57 | ||
55 | withAgent :: [PassphraseSpec] -> [PassphraseSpec] | 58 | withAgent :: [PassphraseSpec] -> [PassphraseSpec] |
56 | withAgent [] = [PassphraseAgent] | 59 | withAgent [] = [PassphraseAgent] |
@@ -763,6 +766,48 @@ verifyFile isHomeless cap keyrings filename = do | |||
763 | _ -> do | 766 | _ -> do |
764 | hPutStrLn stderr "Unsupported file format." | 767 | hPutStrLn stderr "Unsupported file format." |
765 | 768 | ||
769 | signFile :: Bool -> CommonArgsParsed -> [FilePath] -> String -> FilePath -> IO () | ||
770 | signFile isHomeless cap keyrings keyid filename = do | ||
771 | let mop = minimalOp isHomeless cap | ||
772 | KikiResult r report <- runKeyRing mop | ||
773 | { opFiles = opFiles mop | ||
774 | `Map.union` Map.fromList | ||
775 | [ (ArgFile f, strm { access = Sec }) | f <- keyrings ] | ||
776 | } | ||
777 | case r of | ||
778 | KikiSuccess rt -> go rt | ||
779 | err -> hPutStrLn stderr $ errorString err | ||
780 | where | ||
781 | go :: KeyRingRuntime -> IO () | ||
782 | go rt = do | ||
783 | tm <- modificationTime <$> getFileStatus filename | ||
784 | bs <- L.readFile filename | ||
785 | let hashed = [] -- TODO: FingerprintPacket | ||
786 | unhashed = [IssuerPacket keyid] | ||
787 | lit = LiteralDataPacket | ||
788 | { format = 'b' -- b:binary, t:text, u:utf8 | ||
789 | , filename = filename | ||
790 | , timestamp = fromTime tm -- seconds since Jan 1, 1970 UTC | ||
791 | , content = bs | ||
792 | } | ||
793 | hash = SHA512 | ||
794 | matchkey fp mp = matchpr fp (packet mp) == fp | ||
795 | case smallprGrip keyid of | ||
796 | Nothing -> hPutStrLn stderr "Bad keygrip." | ||
797 | Just grip -> do | ||
798 | let keydata = lookupByGrip grip (rtKeyDB rt) | ||
799 | case keydata of | ||
800 | [] -> hPutStrLn stderr "No matching key." | ||
801 | (k,_):_ -> rtPassphrases rt (Unencrypted,S2K 100 "") k >>= \case | ||
802 | KikiSuccess un -> do | ||
803 | mb <- pgpSign (Message [un]) (DataSignature lit []) hash keyid | ||
804 | case mb of | ||
805 | Nothing -> hPutStrLn stderr "Failed to make signature." | ||
806 | Just o -> do | ||
807 | putStrLn $ "Using "++show (fingerprint un)++" to write " <> filename <> ".sig" | ||
808 | let sigs = map (\sig -> sig { unhashed_subpackets = unhashed }) (signatures_over o) | ||
809 | L.writeFile (filename <> ".sig") $ L.concat $ map encode sigs | ||
810 | err -> hPutStrLn stderr $ errorString err | ||
766 | 811 | ||
767 | parsePackets :: L.ByteString -> Either String [Packet] | 812 | parsePackets :: L.ByteString -> Either String [Packet] |
768 | parsePackets bs = case decodeOrFail bs of | 813 | parsePackets bs = case decodeOrFail bs of |
diff --git a/lib/Transforms.hs b/lib/Transforms.hs index 6250dea..118b494 100644 --- a/lib/Transforms.hs +++ b/lib/Transforms.hs | |||
@@ -340,13 +340,13 @@ accBindings bs = as | |||
340 | 340 | ||
341 | sigpackets :: | 341 | sigpackets :: |
342 | Monad m => | 342 | Monad m => |
343 | Word8 -> [SignatureSubpacket] -> [SignatureSubpacket] -> m Packet | 343 | Word8 -> KeyAlgorithm -> [SignatureSubpacket] -> [SignatureSubpacket] -> m Packet |
344 | sigpackets typ hashed unhashed = return $ | 344 | sigpackets typ alg hashed unhashed = return $ |
345 | signaturePacket | 345 | signaturePacket |
346 | 4 -- version | 346 | 4 -- version |
347 | typ -- 0x18 subkey binding sig, or 0x19 back-signature | 347 | typ -- 0x18 subkey binding sig, or 0x19 back-signature |
348 | RSA | 348 | alg |
349 | SHA1 | 349 | SHA256 |
350 | hashed | 350 | hashed |
351 | unhashed | 351 | unhashed |
352 | 0 -- Word16 -- Left 16 bits of the signed hash value | 352 | 0 -- Word16 -- Left 16 bits of the signed hash value |
@@ -409,6 +409,7 @@ makeInducerSig topk wkun uid extras | |||
409 | = CertificationSignature (secretToPublic topk) | 409 | = CertificationSignature (secretToPublic topk) |
410 | uid | 410 | uid |
411 | (sigpackets 0x13 | 411 | (sigpackets 0x13 |
412 | (key_algorithm wkun) | ||
412 | subpackets | 413 | subpackets |
413 | subpackets_unh) | 414 | subpackets_unh) |
414 | where | 415 | where |
@@ -578,6 +579,7 @@ makeSig doDecrypt top fname subkey_p tags mbsig = do | |||
578 | (SubkeySignature wk | 579 | (SubkeySignature wk |
579 | (head parsedkey) | 580 | (head parsedkey) |
580 | (sigpackets 0x19 | 581 | (sigpackets 0x19 |
582 | (key_algorithm $ head parsedkey) | ||
581 | hashed0 | 583 | hashed0 |
582 | [IssuerPacket subgrip])) | 584 | [IssuerPacket subgrip])) |
583 | SHA256 | 585 | SHA256 |
@@ -590,6 +592,7 @@ makeSig doDecrypt top fname subkey_p tags mbsig = do | |||
590 | (SubkeySignature wk | 592 | (SubkeySignature wk |
591 | (head parsedkey) | 593 | (head parsedkey) |
592 | (sigpackets 0x18 | 594 | (sigpackets 0x18 |
595 | (key_algorithm wkun) | ||
593 | hashed0 | 596 | hashed0 |
594 | unhashed0)) | 597 | unhashed0)) |
595 | SHA256 | 598 | SHA256 |
@@ -636,7 +639,7 @@ makeSig doDecrypt top fname subkey_p tags mbsig = do | |||
636 | candidateSignerKeys :: KeyDB -> Packet -> [Packet] | 639 | candidateSignerKeys :: KeyDB -> Packet -> [Packet] |
637 | candidateSignerKeys db sig = | 640 | candidateSignerKeys db sig = |
638 | case issuerGrip sig of | 641 | case issuerGrip sig of |
639 | Just g -> concatMap (map packet . associatedKeys) $ lookupByGrip g db | 642 | Just g -> concatMap (map packet . associatedKeys . snd) $ lookupByGrip g db |
640 | _ -> map keyPacket $ keyData db | 643 | _ -> map keyPacket $ keyData db |
641 | 644 | ||
642 | issuerGrip :: Packet -> Maybe KeyGrip | 645 | issuerGrip :: Packet -> Maybe KeyGrip |