summaryrefslogtreecommitdiff
path: root/lib/KeyRing
diff options
context:
space:
mode:
Diffstat (limited to 'lib/KeyRing')
-rw-r--r--lib/KeyRing/BuildKeyDB.hs57
-rw-r--r--lib/KeyRing/Types.hs58
2 files changed, 76 insertions, 39 deletions
diff --git a/lib/KeyRing/BuildKeyDB.hs b/lib/KeyRing/BuildKeyDB.hs
index 44952de..57647b0 100644
--- a/lib/KeyRing/BuildKeyDB.hs
+++ b/lib/KeyRing/BuildKeyDB.hs
@@ -36,6 +36,7 @@ import qualified Data.Map as Map
36import Data.Maybe 36import Data.Maybe
37import Data.OpenPGP 37import Data.OpenPGP
38import Data.OpenPGP.Util (GenerateKeyParams (..), fingerprint, generateKey, pgpSign, verify) 38import Data.OpenPGP.Util (GenerateKeyParams (..), fingerprint, generateKey, pgpSign, verify)
39import GHC.Stack
39 40
40 41
41import Data.Time.Clock (UTCTime) 42import Data.Time.Clock (UTCTime)
@@ -171,7 +172,7 @@ buildKeyDB ctx grip0 keyring = do
171 trans f (info,ps) = do 172 trans f (info,ps) = do
172 let manip = combineTransforms (transforms info) 173 let manip = combineTransforms (transforms info)
173 rt1 = rt0 { rtKeyDB = merge emptyKeyDB f ps } 174 rt1 = rt0 { rtKeyDB = merge emptyKeyDB f ps }
174 acc = Just Sec /= Map.lookup f accs 175 -- acc = Just Sec /= Map.lookup f accs
175 r <- performManipulations doDecrypt rt1 mwk manip 176 r <- performManipulations doDecrypt rt1 mwk manip
176 try r $ \(rt2,report) -> do 177 try r $ \(rt2,report) -> do
177 return $ KikiSuccess (report,rtKeyDB rt2) 178 return $ KikiSuccess (report,rtKeyDB rt2)
@@ -390,6 +391,7 @@ doImportG transcode db m0 tags fname key = do
390 , rrs ) 391 , rrs )
391 -} 392 -}
392 let go (Just kd@(KeyData top topsigs uids subs)) = insertSubkey transcode kk kd tags fname key 393 let go (Just kd@(KeyData top topsigs uids subs)) = insertSubkey transcode kk kd tags fname key
394 go Nothing = pure NoWorkingKey
393 transmuteAt go kk db 395 transmuteAt go kk db
394 396
395 397
@@ -413,27 +415,27 @@ parseSpec wkgrip spec =
413 if not slashed 415 if not slashed
414 then 416 then
415 case prespec of 417 case prespec of
416 AnyMatch -> (KeyGrip "", Nothing) 418 AnyMatch -> (KeyFP 0 "", Nothing)
417 EmptyMatch -> error "Bad key spec." 419 EmptyMatch -> error "Bad key spec."
418 WorkingKeyMatch -> (KeyGrip wkgrip, Nothing) 420 WorkingKeyMatch -> (KeyFP 0 wkgrip, Nothing)
419 SubstringMatch (Just KeyTypeField) tag -> (KeyGrip wkgrip, Just tag) 421 SubstringMatch (Just KeyTypeField) tag -> (KeyFP 0 wkgrip, Just tag)
420 SubstringMatch Nothing str -> (KeyGrip wkgrip, Just str) 422 SubstringMatch Nothing str -> (KeyFP 0 wkgrip, Just str)
421 SubstringMatch (Just UserIDField) ustr -> (KeyUidMatch ustr, Nothing) 423 SubstringMatch (Just UserIDField) ustr -> (KeyUidMatch ustr, Nothing)
422 FingerprintMatch fp -> (KeyGrip fp, Nothing) 424 FingerprintMatch ver fp -> (KeyFP ver fp, Nothing)
423 else 425 else
424 case (prespec,postspec) of 426 case (prespec,postspec) of
425 (FingerprintMatch fp, SubstringMatch st t) 427 (FingerprintMatch ver fp, SubstringMatch st t)
426 | st /= Just UserIDField -> (KeyGrip fp, Just t) 428 | st /= Just UserIDField -> (KeyFP ver fp, Just t)
427 (SubstringMatch mt u, _) 429 (SubstringMatch mt u, _)
428 | postspec `elem` [AnyMatch,EmptyMatch] 430 | postspec `elem` [AnyMatch,EmptyMatch]
429 && mt /= Just KeyTypeField -> (KeyUidMatch u, Nothing) 431 && mt /= Just KeyTypeField -> (KeyUidMatch u, Nothing)
430 (SubstringMatch mt u, SubstringMatch st t) 432 (SubstringMatch mt u, SubstringMatch st t)
431 | mt /= Just KeyTypeField 433 | mt /= Just KeyTypeField
432 && st /= Just UserIDField -> (KeyUidMatch u, Just t) 434 && st /= Just UserIDField -> (KeyUidMatch u, Just t)
433 (FingerprintMatch _,FingerprintMatch _) -> error "todo: support fp:/fp: spec" 435 (FingerprintMatch _ _,FingerprintMatch _ _) -> error "todo: support fp:/fp: spec"
434 (_,FingerprintMatch fp) -> error "todo: support /fp: spec" 436 (_,FingerprintMatch _ fp) -> error "todo: support /fp: spec"
435 (FingerprintMatch fp,_) -> error "todo: support fp:/ spec" 437 (FingerprintMatch _ fp,_) -> error "todo: support fp:/ spec"
436 _ -> error "Bad key spec." 438 _ -> error "Bad key spec."
437 where 439 where
438 (preslash,slashon) = break (=='/') spec 440 (preslash,slashon) = break (=='/') spec
439 slashed = not $ null $ take 1 slashon 441 slashed = not $ null $ take 1 slashon
@@ -522,6 +524,7 @@ generateInternals transcode mwk db gens = do
522 transmuteAt (go kk) kk db 524 transmuteAt (go kk) kk db
523 where 525 where
524 go kk (Just kd0) = foldM (generateSubkey transcode) (KikiSuccess (kd0,[])) gens 526 go kk (Just kd0) = foldM (generateSubkey transcode) (KikiSuccess (kd0,[])) gens
527 go kk Nothing = error "generateInternals: Key not found."
525 528
526mergeHostFiles :: KeyRingOperation -> KeyDB -> InputFileContext 529mergeHostFiles :: KeyRingOperation -> KeyDB -> InputFileContext
527 -> IO 530 -> IO
@@ -588,7 +591,7 @@ readInputFileL ctx inp = do
588 hs <- mapM (`openFile` ReadMode) fname 591 hs <- mapM (`openFile` ReadMode) fname
589 fmap L.concat $ mapM (hGetContentsN oneMeg) hs 592 fmap L.concat $ mapM (hGetContentsN oneMeg) hs
590 593
591getInputFileTime :: InputFileContext -> InputFile -> IO CTime 594getInputFileTime :: HasCallStack => InputFileContext -> InputFile -> IO CTime
592getInputFileTime ctx (Pipe fdr fdw) = do 595getInputFileTime ctx (Pipe fdr fdw) = do
593 mt <- handleIO_ (return Nothing) $ Just <$> modificationTime <$> getFdStatus fdr 596 mt <- handleIO_ (return Nothing) $ Just <$> modificationTime <$> getFdStatus fdr
594 maybe tryw return mt 597 maybe tryw return mt
@@ -602,6 +605,8 @@ getInputFileTime ctx (FileDesc fd) = do
602getInputFileTime ctx (resolveInputFile ctx -> [fname]) = do 605getInputFileTime ctx (resolveInputFile ctx -> [fname]) = do
603 handleIO_ (error $ fname++": modificaiton time?") $ 606 handleIO_ (error $ fname++": modificaiton time?") $
604 modificationTime <$> getFileStatus fname 607 modificationTime <$> getFileStatus fname
608getInputFileTime ctx arg = error $ "getInputFileTime: Invalid argument: " ++ show arg
609
605 610
606slurpWIPKeys :: Posix.EpochTime -> L.ByteString -> ( [(Word8,Packet)], [L.ByteString]) 611slurpWIPKeys :: Posix.EpochTime -> L.ByteString -> ( [(Word8,Packet)], [L.ByteString])
607slurpWIPKeys stamp "" = ([],[]) 612slurpWIPKeys stamp "" = ([],[])
@@ -763,14 +768,15 @@ parseSingleSpec "-" = WorkingKeyMatch
763parseSingleSpec "" = EmptyMatch 768parseSingleSpec "" = EmptyMatch
764parseSingleSpec ('t':':':tag) = SubstringMatch (Just KeyTypeField) tag 769parseSingleSpec ('t':':':tag) = SubstringMatch (Just KeyTypeField) tag
765parseSingleSpec ('u':':':tag) = SubstringMatch (Just UserIDField) tag 770parseSingleSpec ('u':':':tag) = SubstringMatch (Just UserIDField) tag
766parseSingleSpec ('c':':':tag) = SubstringMatch (Just GroupIDField) tag 771-- parseSingleSpec ('c':':':tag) = SubstringMatch (Just GroupIDField) tag
767parseSingleSpec ('f':'p':':':fp) = FingerprintMatch fp 772parseSingleSpec ('f':'p':':':fp) = FingerprintMatch 0 fp
768parseSingleSpec str 773parseSingleSpec str
769 | is40digitHex str = FingerprintMatch str 774 | Just 40 <- isHexDigits str = FingerprintMatch 4 str
770 | otherwise = SubstringMatch Nothing str 775 | Just 64 <- isHexDigits str = FingerprintMatch 5 str
776 | otherwise = SubstringMatch Nothing str
771 777
772is40digitHex :: [Char] -> Bool 778isHexDigits :: [Char] -> Maybe Int
773is40digitHex xs = ys == xs && length ys==40 779isHexDigits xs = guard (ys == xs) >> Just (length ys)
774 where 780 where
775 ys = filter ishex xs 781 ys = filter ishex xs
776 ishex c | '0' <= c && c <= '9' = True 782 ishex c | '0' <= c && c <= '9' = True
@@ -779,9 +785,9 @@ is40digitHex xs = ys == xs && length ys==40
779 ishex c = False 785 ishex c = False
780 786
781matchSpec :: KeySpec -> KeyData -> Bool 787matchSpec :: KeySpec -> KeyData -> Bool
782matchSpec (KeyGrip grip) (KeyData p _ _ _) 788matchSpec (KeyFP ver grip) (KeyData p _ _ _)
783 | matchpr grip (packet p)==grip = True 789 = let mg = matchpr ver grip (packet p)
784 | otherwise = False 790 in mg == grip
785 791
786matchSpec (KeyTag key tag) (KeyData _ sigs _ _) = not . null $ filter match ps 792matchSpec (KeyTag key tag) (KeyData _ sigs _ _) = not . null $ filter match ps
787 where 793 where
@@ -791,7 +797,7 @@ matchSpec (KeyTag key tag) (KeyData _ sigs _ _) = not . null $ filter match ps
791 && has_issuer key p 797 && has_issuer key p
792 has_issuer key p = isJust $ do 798 has_issuer key p = isJust $ do
793 issuer <- signature_issuer p 799 issuer <- signature_issuer p
794 guard $ matchpr issuer key == issuer 800 guard $ matchpr 0 issuer key == issuer
795 has_tag tag p = tag `elem` mapMaybe usage (hashed_subpackets p) 801 has_tag tag p = tag `elem` mapMaybe usage (hashed_subpackets p)
796 || tag `elem` map usageString (mapMaybe keyflags (hashed_subpackets p)) 802 || tag `elem` map usageString (mapMaybe keyflags (hashed_subpackets p))
797 803
@@ -907,7 +913,7 @@ getHostnames (KeyData topmp _ uids subs) = Hostnames addr onames othernames Noth
907 913
908hasFingerDress :: KeyDB -> SockAddr -> Bool 914hasFingerDress :: KeyDB -> SockAddr -> Bool
909hasFingerDress db addr | socketFamily addr/=AF_INET6 = False 915hasFingerDress db addr | socketFamily addr/=AF_INET6 = False
910hasFingerDress db addr = pre=="fd" && isJust (selectPublicKey (KeyGrip g',Nothing) db) 916hasFingerDress db addr = pre=="fd" && isJust (selectPublicKey (KeyFP 0 g',Nothing) db)
911 where 917 where
912 (pre,g) = splitAt 2 $ filter (/=':') $ Hosts.inet_ntop addr 918 (pre,g) = splitAt 2 $ filter (/=':') $ Hosts.inet_ntop addr
913 g' = map toUpper g 919 g' = map toUpper g
@@ -1012,6 +1018,7 @@ decode_btc_key timestamp str = do
1012 ] 1018 ]
1013 , s2k_useage = 0 1019 , s2k_useage = 0
1014 , s2k = S2K 100 "" 1020 , s2k = S2K 100 ""
1021 , aead_algorithm = Nothing
1015 , symmetric_algorithm = Unencrypted 1022 , symmetric_algorithm = Unencrypted
1016 , encrypted_data = "" 1023 , encrypted_data = ""
1017 , is_subkey = True 1024 , is_subkey = True
@@ -1205,6 +1212,7 @@ readSecretDNSFile fname = do
1205 _ -> RSA 1212 _ -> RSA
1206 case alg of 1213 case alg of
1207 RSA -> return $ rsaToPGP stamp $ fromJust $ extractRSAKeyFields kvs 1214 RSA -> return $ rsaToPGP stamp $ fromJust $ extractRSAKeyFields kvs
1215 _ -> return $ error $ "readSecretDNSFile: " ++ show alg ++ " unimplemented."
1208 1216
1209spemPacket :: SecretPEMData -> Maybe Packet 1217spemPacket :: SecretPEMData -> Maybe Packet
1210spemPacket (PEMPacket p) = Just p 1218spemPacket (PEMPacket p) = Just p
@@ -1310,6 +1318,7 @@ rsaToPGP stamp rsa = SecretKeyPacket
1310 -- , ecc_curve = def 1318 -- , ecc_curve = def
1311 , s2k_useage = 0 1319 , s2k_useage = 0
1312 , s2k = S2K 100 "" 1320 , s2k = S2K 100 ""
1321 , aead_algorithm = Nothing
1313 , symmetric_algorithm = Unencrypted 1322 , symmetric_algorithm = Unencrypted
1314 , encrypted_data = "" 1323 , encrypted_data = ""
1315 , is_subkey = True 1324 , is_subkey = True
diff --git a/lib/KeyRing/Types.hs b/lib/KeyRing/Types.hs
index af213ce..dbcc22c 100644
--- a/lib/KeyRing/Types.hs
+++ b/lib/KeyRing/Types.hs
@@ -13,6 +13,7 @@ import Data.Maybe (maybeToList,isJust,fromJust,mapMaybe)
13import Data.OpenPGP 13import Data.OpenPGP
14import Data.OpenPGP.Util 14import Data.OpenPGP.Util
15import Data.Time.Clock 15import Data.Time.Clock
16import Data.Word
16import FunctorToMaybe 17import FunctorToMaybe
17import qualified Data.ByteString.Lazy as L 18import qualified Data.ByteString.Lazy as L
18import qualified System.Posix.Types as Posix 19import qualified System.Posix.Types as Posix
@@ -119,7 +120,7 @@ data PassphraseSpec = PassphraseSpec
119 { passSpecRingFile :: Maybe FilePath 120 { passSpecRingFile :: Maybe FilePath
120 -- ^ If not Nothing, the passphrase is to be used for packets 121 -- ^ If not Nothing, the passphrase is to be used for packets
121 -- from this file. 122 -- from this file.
122 , passSpecKeySpec :: Maybe String 123 , passSpecKeySpec :: Maybe KeySpec
123 -- ^ Non-Nothing value reserved for future use. 124 -- ^ Non-Nothing value reserved for future use.
124 -- (TODO: Use this to implement per-key passphrase associations). 125 -- (TODO: Use this to implement per-key passphrase associations).
125 , passSpecPassFile :: InputFile 126 , passSpecPassFile :: InputFile
@@ -132,9 +133,12 @@ data PassphraseSpec = PassphraseSpec
132instance Show PassphraseSpec where 133instance Show PassphraseSpec where
133 show (PassphraseSpec a b c) = "PassphraseSpec "++show (a,b,c) 134 show (PassphraseSpec a b c) = "PassphraseSpec "++show (a,b,c)
134 show (PassphraseMemoizer _) = "PassphraseMemoizer" 135 show (PassphraseMemoizer _) = "PassphraseMemoizer"
136 show PassphraseAgent = "PassphraseAgent"
135instance Eq PassphraseSpec where 137instance Eq PassphraseSpec where
136 PassphraseSpec a b c == PassphraseSpec d e f 138 PassphraseSpec a b c == PassphraseSpec d e f
137 = and [a==d,b==e,c==f] 139 = and [a==d,b==e,c==f]
140 PassphraseAgent == PassphraseAgent
141 = True
138 _ == _ 142 _ == _
139 = False 143 = False
140 144
@@ -152,10 +156,13 @@ instance Ord PassphraseSpec where
152 compare (PassphraseSpec a b c) (PassphraseSpec d e f) 156 compare (PassphraseSpec a b c) (PassphraseSpec d e f)
153 | fmap (const ()) a == fmap (const ()) d 157 | fmap (const ()) a == fmap (const ()) d
154 && fmap (const ()) b == fmap (const ()) e = compare (a,b,c) (d,e,f) 158 && fmap (const ()) b == fmap (const ()) e = compare (a,b,c) (d,e,f)
155 compare (PassphraseSpec (Just _) (Just _) _) _ = LT 159 compare (PassphraseSpec (Just _) (Just _) _) _ = LT
156 compare (PassphraseSpec Nothing (Just _) _) _ = LT 160 compare (PassphraseSpec Nothing (Just _) _) _ = LT
157 compare (PassphraseSpec (Just _) _ _) _ = LT 161 compare (PassphraseSpec (Just _) _ _) _ = LT
158 compare PassphraseAgent _ = GT 162 compare PassphraseAgent _ = GT
163 compare (PassphraseSpec Nothing Nothing _) (PassphraseSpec _ _ _) = GT
164 compare (PassphraseSpec Nothing Nothing _) (PassphraseMemoizer _) = GT
165 compare (PassphraseSpec Nothing Nothing _) PassphraseAgent = LT
159 166
160data Transform = 167data Transform =
161 Autosign 168 Autosign
@@ -349,17 +356,35 @@ isTrust _ = False
349-- 356--
350-- matchpr fp = Data.List.Extra.takeEnd (length fp) 357-- matchpr fp = Data.List.Extra.takeEnd (length fp)
351-- 358--
352matchpr :: String -> Packet -> String 359matchpr :: Word8 -> String -> Packet -> String
353matchpr fp k = reverse $ zipWith const (reverse (show $ fingerprint k)) fp 360matchpr ver fp k =
361 let (rev,v) = case ver of
362 4 -> (reverse, 4)
363 5 -> (id, 5)
364 _ -> case auto_fp_version k of
365 5 -> (id, 5)
366 v -> (reverse, v)
367 in rev $ zipWith const (rev (show $ fingerprintv v k)) fp
354 368
355 369
356 370
357 371
358data KeySpec = 372data KeySpec =
359 KeyGrip String -- fp: 373 KeyFP { fpVer :: Word8 -- 5 or 4 to select fingerprint style, 0 to match either.
374 , fpPartial :: String -- partial fingerprint, matches trailing for 4, or leading for 5
375 } -- fp:
360 | KeyTag Packet String -- fp:????/t: 376 | KeyTag Packet String -- fp:????/t:
361 | KeyUidMatch String -- u: 377 | KeyUidMatch String -- u:
362 deriving Show 378 deriving (Show,Eq)
379
380instance Ord KeySpec where
381 compare (KeyFP av af) (KeyFP bv bf) = compare (av,af) (bv,bf)
382 compare (KeyTag ap a) (KeyTag bp b) = compare (fingerprint ap,a) (fingerprint bp,b)
383 compare (KeyUidMatch a) (KeyUidMatch b) = compare a b
384 compare (KeyFP {}) _ = LT
385 compare (KeyTag {}) _ = LT
386 compare _ _ = GT
387
363 388
364{- 389{-
365RSAPrivateKey ::= SEQUENCE { 390RSAPrivateKey ::= SEQUENCE {
@@ -400,9 +425,9 @@ data SubkeyStatus = Unsigned | OwnerSigned | CrossSigned
400data SecretPEMData = PEMPacket Packet | PEMCertificate ParsedCert 425data SecretPEMData = PEMPacket Packet | PEMCertificate ParsedCert
401 deriving (Show,Eq) 426 deriving (Show,Eq)
402 427
403data MatchingField = KeyTypeField | UserIDField | GroupIDField deriving (Show,Eq,Ord,Enum) 428data MatchingField = KeyTypeField | UserIDField deriving (Show,Eq,Ord,Enum)
404 429
405data SingleKeySpec = FingerprintMatch String 430data SingleKeySpec = FingerprintMatch Word8 String
406 | SubstringMatch (Maybe MatchingField) String 431 | SubstringMatch (Maybe MatchingField) String
407 | EmptyMatch 432 | EmptyMatch
408 | AnyMatch 433 | AnyMatch
@@ -423,12 +448,15 @@ secretToPublic pkt@(SecretKeyPacket {}) =
423 } 448 }
424secretToPublic pkt = pkt 449secretToPublic pkt = pkt
425 450
451matchKeySpec :: KeySpec -> Packet -> Bool
452matchKeySpec spec pkt = not $ null $ snd $ seek_key spec [pkt]
453
426seek_key :: KeySpec -> [Packet] -> ([Packet],[Packet]) 454seek_key :: KeySpec -> [Packet] -> ([Packet],[Packet])
427seek_key (KeyGrip grip) sec = (pre, subs) 455seek_key (KeyFP ver grip) sec = (pre, subs)
428 where 456 where
429 (pre,subs) = break pred sec 457 (pre,subs) = break pred sec
430 pred p@(SecretKeyPacket {}) = matchpr grip p == grip 458 pred p@(SecretKeyPacket {}) = matchpr ver grip p == grip
431 pred p@(PublicKeyPacket {}) = matchpr grip p == grip 459 pred p@(PublicKeyPacket {}) = matchpr ver grip p == grip
432 pred _ = False 460 pred _ = False
433 461
434seek_key (KeyTag key tag) ps 462seek_key (KeyTag key tag) ps
@@ -441,7 +469,7 @@ seek_key (KeyTag key tag) ps
441 (as,bs) = break (\p -> isSignaturePacket p 469 (as,bs) = break (\p -> isSignaturePacket p
442 && has_tag tag p 470 && has_tag tag p
443 && isJust (signature_issuer p) 471 && isJust (signature_issuer p)
444 && matchpr (fromJust $ signature_issuer p) key == fromJust (signature_issuer p) ) 472 && matchpr (version p) (fromJust $ signature_issuer p) key == fromJust (signature_issuer p) )
445 ps 473 ps
446 (rs,qs) = break isKey (reverse as) 474 (rs,qs) = break isKey (reverse as)
447 475