summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2020-05-09 20:59:11 -0400
committerJoe Crayne <joe@jerkface.net>2020-05-09 20:59:11 -0400
commit71048681d402d5f692bf293a2785dc83fb32d384 (patch)
tree6f327490f18ce1475479a4b959ed68c8c6ad49ed
parent8b9d7cfbb69aacb13be754c8dc94e985f60f5aea (diff)
Added sign command to make detached signatures.
-rw-r--r--kiki.hs16
-rw-r--r--lib/KeyDB.hs27
-rw-r--r--lib/Kiki.hs51
-rw-r--r--lib/Transforms.hs13
4 files changed, 91 insertions, 16 deletions
diff --git a/kiki.hs b/kiki.hs
index 1138b7a..fe9a979 100644
--- a/kiki.hs
+++ b/kiki.hs
@@ -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
1639kiki "sign" args | "--help" `elem` args = do
1640 putStr . unlines $
1641 [ "kiki sign [--homedir HOMEDIR | --homeless] [[--keyring FILE] ...] --with-key KEYID FILE"
1642 ]
1643kiki "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
1639kiki cmd args = hPutStrLn stderr $ "I don't know how to "++cmd++"." 1654kiki cmd args = hPutStrLn stderr $ "I don't know how to "++cmd++"."
1640 1655
1641sshkeyname :: Packet -> [FilePath] 1656sshkeyname :: 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
1689main :: IO () 1705main :: 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
70newtype KeyGrip = KeyInt Int 70newtype KeyGrip = KeyInt Int
71 deriving Eq
71 72
72fingerprintGrip :: Fingerprint -> KeyGrip 73fingerprintGrip :: Fingerprint -> KeyGrip
73fingerprintGrip (Fingerprint bs) = 74fingerprintGrip (Fingerprint bs) =
@@ -109,10 +110,20 @@ kkData db = Map.toList (byKeyKey db)
109lookupKeyData :: KeyKey -> KeyDB -> Maybe KeyData 110lookupKeyData :: KeyKey -> KeyDB -> Maybe KeyData
110lookupKeyData kk db = Map.lookup kk (byKeyKey db) 111lookupKeyData kk db = Map.lookup kk (byKeyKey db)
111 112
112lookupByGrip :: KeyGrip -> KeyDB -> [KeyData] 113lookupByGrip :: KeyGrip -> KeyDB -> [(MappedPacket,KeyData)]
113lookupByGrip k db = mapMaybe (`Map.lookup` byKeyKey db) 114lookupByGrip 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
117transmute :: (Monad m, Monad kiki, Traversable kiki) => 128transmute :: (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
137alterKeyDB :: (Maybe KeyData -> Maybe KeyData) -> KeyKey -> KeyDB -> KeyDB 148alterKeyDB :: (Maybe KeyData -> Maybe KeyData) -> KeyKey -> KeyDB -> KeyDB
138alterKeyDB update kk db = db 149alterKeyDB 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 #-}
5module Kiki 6module Kiki
6 ( module Kiki 7 ( module Kiki
7 , setVerifyFlag 8 , setVerifyFlag
@@ -48,9 +49,11 @@ import qualified SSHKey as SSH
48import CommandLine 49import CommandLine
49import DotLock 50import DotLock
50import GnuPGAgent (Query (..)) 51import GnuPGAgent (Query (..))
52import qualified IntMapClass as I
51import KeyRing hiding (pemFromPacket) 53import KeyRing hiding (pemFromPacket)
52import KeyDB 54import KeyDB
53import KeyRing.BuildKeyDB (gpgipv6addr, Hostnames, allNames) 55import KeyRing.BuildKeyDB (gpgipv6addr, Hostnames, allNames)
56import TimeUtil
54 57
55withAgent :: [PassphraseSpec] -> [PassphraseSpec] 58withAgent :: [PassphraseSpec] -> [PassphraseSpec]
56withAgent [] = [PassphraseAgent] 59withAgent [] = [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
769signFile :: Bool -> CommonArgsParsed -> [FilePath] -> String -> FilePath -> IO ()
770signFile 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
767parsePackets :: L.ByteString -> Either String [Packet] 812parsePackets :: L.ByteString -> Either String [Packet]
768parsePackets bs = case decodeOrFail bs of 813parsePackets 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
341sigpackets :: 341sigpackets ::
342 Monad m => 342 Monad m =>
343 Word8 -> [SignatureSubpacket] -> [SignatureSubpacket] -> m Packet 343 Word8 -> KeyAlgorithm -> [SignatureSubpacket] -> [SignatureSubpacket] -> m Packet
344sigpackets typ hashed unhashed = return $ 344sigpackets 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
636candidateSignerKeys :: KeyDB -> Packet -> [Packet] 639candidateSignerKeys :: KeyDB -> Packet -> [Packet]
637candidateSignerKeys db sig = 640candidateSignerKeys 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
642issuerGrip :: Packet -> Maybe KeyGrip 645issuerGrip :: Packet -> Maybe KeyGrip