diff options
author | joe <joe@jerkface.net> | 2016-08-28 16:10:41 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2016-08-28 16:10:41 -0400 |
commit | 7a579e7b82a2f5707af77f4a7101ce72e57635ac (patch) | |
tree | a5ff6eac4888a5577a6ba89a76dde939af4bc038 /lib/KeyRing.hs | |
parent | 83e97b86973fc63eda92f5b38c112f0d374503c0 (diff) |
Refactored for smaller modules (faster rebuild).
Diffstat (limited to 'lib/KeyRing.hs')
-rw-r--r-- | lib/KeyRing.hs | 428 |
1 files changed, 2 insertions, 426 deletions
diff --git a/lib/KeyRing.hs b/lib/KeyRing.hs index a055dad..313258d 100644 --- a/lib/KeyRing.hs +++ b/lib/KeyRing.hs | |||
@@ -211,6 +211,8 @@ import FunctorToMaybe | |||
211 | import DotLock | 211 | import DotLock |
212 | import ProcessUtils (systemEnv, ExitCode(ExitFailure, ExitSuccess) ) | 212 | import ProcessUtils (systemEnv, ExitCode(ExitFailure, ExitSuccess) ) |
213 | import GnuPGAgent as Agent | 213 | import GnuPGAgent as Agent |
214 | import Types | ||
215 | import PacketTranscoder | ||
214 | 216 | ||
215 | -- DER-encoded elliptic curve ids | 217 | -- DER-encoded elliptic curve ids |
216 | -- nistp256_id = 0x2a8648ce3d030107 | 218 | -- nistp256_id = 0x2a8648ce3d030107 |
@@ -247,114 +249,6 @@ home = HomeDir | |||
247 | , optfile_alts = ["keys.conf","gpg.conf-2","gpg.conf"] | 249 | , optfile_alts = ["keys.conf","gpg.conf-2","gpg.conf"] |
248 | } | 250 | } |
249 | 251 | ||
250 | data InputFile = HomeSec | ||
251 | -- ^ A file named secring.gpg located in the home directory. | ||
252 | -- See 'opHome'. | ||
253 | | HomePub | ||
254 | -- ^ A file named pubring.gpg located in the home directory. | ||
255 | -- See 'opHome'. | ||
256 | | ArgFile FilePath | ||
257 | -- ^ Contents will be read or written from the specified path. | ||
258 | | FileDesc Posix.Fd | ||
259 | -- ^ Contents will be read or written from the specified file | ||
260 | -- descriptor. | ||
261 | | Pipe Posix.Fd Posix.Fd | ||
262 | -- ^ Contents will be read from the first descriptor and updated | ||
263 | -- content will be writen to the second. Note: Don't use Pipe | ||
264 | -- for 'Wallet' files. (TODO: Wallet support) | ||
265 | | Generate Int GenerateKeyParams | ||
266 | -- ^ New key packets will be generated if there is no | ||
267 | -- matching content already in the key pool. The integer is | ||
268 | -- a unique id number so that multiple generations can be | ||
269 | -- inserted into 'opFiles' | ||
270 | deriving (Eq,Ord,Show) | ||
271 | |||
272 | -- type UsageTag = String | ||
273 | data Initializer = NoCreate | Internal GenerateKeyParams | External String | ||
274 | deriving (Eq,Ord,Show) | ||
275 | |||
276 | data FileType = KeyRingFile | ||
277 | | PEMFile | ||
278 | | WalletFile | ||
279 | | DNSPresentation | ||
280 | | Hosts | ||
281 | deriving (Eq,Ord,Enum,Show) | ||
282 | |||
283 | -- | Use this type to indicate whether a file of type 'KeyRingFile' is expected | ||
284 | -- to contain secret or public PGP key packets. Note that it is not supported | ||
285 | -- to mix both in the same file and that the secret key packets include all of | ||
286 | -- the information contained in their corresponding public key packets. | ||
287 | data Access = AutoAccess -- ^ secret or public as appropriate based on existing content. | ||
288 | -- (see 'rtRingAccess') | ||
289 | | Sec -- ^ secret information | ||
290 | | Pub -- ^ public information | ||
291 | deriving (Eq,Ord,Show) | ||
292 | |||
293 | -- | Note that the documentation here is intended for when this value is | ||
294 | -- assigned to 'fill'. For other usage, see 'spill'. | ||
295 | data KeyFilter = KF_None -- ^ No keys will be imported. | ||
296 | | KF_Match String -- ^ Only the key that matches the spec will be imported. | ||
297 | | KF_Subkeys -- ^ Subkeys will be imported if their owner key is | ||
298 | -- already in the ring. TODO: Even if their signatures | ||
299 | -- are bad? | ||
300 | | KF_Authentic -- ^ Keys are imported if they belong to an authenticated | ||
301 | -- identity (signed or self-authenticating). | ||
302 | | KF_All -- ^ All keys will be imported. | ||
303 | deriving (Eq,Ord,Show) | ||
304 | |||
305 | -- | This type describes how 'runKeyRing' will treat a file. | ||
306 | data StreamInfo = StreamInfo | ||
307 | { access :: Access | ||
308 | -- ^ Indicates whether the file is allowed to contain secret information. | ||
309 | , typ :: FileType | ||
310 | -- ^ Indicates the format and content type of the file. | ||
311 | , fill :: KeyFilter | ||
312 | -- ^ This filter controls what packets will be inserted into a file. | ||
313 | , spill :: KeyFilter | ||
314 | -- | ||
315 | -- ^ Use this to indicate whether or not a file's contents should be | ||
316 | -- available for updating other files. Note that although its type is | ||
317 | -- 'KeyFilter', it is usually interpretted as a boolean flag. Details | ||
318 | -- depend on 'typ' and are as follows: | ||
319 | -- | ||
320 | -- 'KeyRingFile': | ||
321 | -- | ||
322 | -- * 'KF_None' - The file's contents will not be shared. | ||
323 | -- | ||
324 | -- * otherwise - The file's contents will be shared. | ||
325 | -- | ||
326 | -- 'PEMFile': | ||
327 | -- | ||
328 | -- * 'KF_None' - The file's contents will not be shared. | ||
329 | -- | ||
330 | -- * 'KF_Match' - The file's key will be shared with the specified owner | ||
331 | -- key and usage tag. If 'fill' is also a 'KF_Match', then it must be | ||
332 | -- equal to this value; changing the usage or owner of a key is not | ||
333 | -- supported via the fill/spill mechanism. | ||
334 | -- | ||
335 | -- * otherwise - Unspecified. Do not use. | ||
336 | -- | ||
337 | -- 'WalletFile': | ||
338 | -- | ||
339 | -- * The 'spill' setting is ignored and the file's contents are shared. | ||
340 | -- (TODO) | ||
341 | -- | ||
342 | -- 'Hosts': | ||
343 | -- | ||
344 | -- * The 'spill' setting is ignored and the file's contents are shared. | ||
345 | -- (TODO) | ||
346 | -- | ||
347 | , initializer :: Initializer | ||
348 | -- ^ If 'typ' is 'PEMFile' and an 'External' 'initializer' string is set, | ||
349 | -- then it is interpretted as a shell command that may be used to create | ||
350 | -- the key if it does not exist. | ||
351 | , transforms :: [Transform] | ||
352 | -- ^ Per-file transformations that occur before the contents of a file are | ||
353 | -- spilled into the common pool. | ||
354 | } | ||
355 | deriving (Eq,Show) | ||
356 | |||
357 | |||
358 | spillable :: StreamInfo -> Bool | 252 | spillable :: StreamInfo -> Bool |
359 | spillable (spill -> KF_None) = False | 253 | spillable (spill -> KF_None) = False |
360 | spillable _ = True | 254 | spillable _ = True |
@@ -387,10 +281,6 @@ usageFromFilter (KF_Match usage) = return usage | |||
387 | usageFromFilter _ = mzero | 281 | usageFromFilter _ = mzero |
388 | 282 | ||
389 | 283 | ||
390 | type PacketTranscoder = (SymmetricAlgorithm,S2K) -> MappedPacket -> IO (KikiCondition Packet) | ||
391 | |||
392 | type PacketDecrypter = MappedPacket -> IO (KikiCondition Packet) | ||
393 | |||
394 | data KeyRingRuntime = KeyRingRuntime | 284 | data KeyRingRuntime = KeyRingRuntime |
395 | { rtPubring :: FilePath | 285 | { rtPubring :: FilePath |
396 | -- ^ Path to the file represented by 'HomePub' | 286 | -- ^ Path to the file represented by 'HomePub' |
@@ -418,84 +308,6 @@ data KeyRingRuntime = KeyRingRuntime | |||
418 | data PacketUpdate = InducerSignature String [SignatureSubpacket] | 308 | data PacketUpdate = InducerSignature String [SignatureSubpacket] |
419 | | SubKeyDeletion KeyKey KeyKey | 309 | | SubKeyDeletion KeyKey KeyKey |
420 | 310 | ||
421 | -- | This type is used to indicate where to obtain passphrases. | ||
422 | data PassphraseSpec = PassphraseSpec | ||
423 | { passSpecRingFile :: Maybe FilePath | ||
424 | -- ^ If not Nothing, the passphrase is to be used for packets | ||
425 | -- from this file. | ||
426 | , passSpecKeySpec :: Maybe String | ||
427 | -- ^ Non-Nothing value reserved for future use. | ||
428 | -- (TODO: Use this to implement per-key passphrase associations). | ||
429 | , passSpecPassFile :: InputFile | ||
430 | -- ^ The passphrase will be read from this file or file descriptor. | ||
431 | } | ||
432 | -- | Use this to carry pasphrases from a previous run. | ||
433 | | PassphraseMemoizer PacketTranscoder | ||
434 | | PassphraseAgent | ||
435 | |||
436 | instance Show PassphraseSpec where | ||
437 | show (PassphraseSpec a b c) = "PassphraseSpec "++show (a,b,c) | ||
438 | show (PassphraseMemoizer _) = "PassphraseMemoizer" | ||
439 | instance Eq PassphraseSpec where | ||
440 | PassphraseSpec a b c == PassphraseSpec d e f | ||
441 | = and [a==d,b==e,c==f] | ||
442 | _ == _ | ||
443 | = False | ||
444 | |||
445 | |||
446 | |||
447 | data Transform = | ||
448 | Autosign | ||
449 | -- ^ This operation will make signatures for any tor-style UID | ||
450 | -- that matches a tor subkey and thus can be authenticated without | ||
451 | -- requring the judgement of a human user. | ||
452 | -- | ||
453 | -- A tor-style UID is one of the following form: | ||
454 | -- | ||
455 | -- > Anonymous <root@HOSTNAME.onion> | ||
456 | | DeleteSubkeyByFingerprint String | ||
457 | -- ^ Delete the subkey specified by the given fingerprint and any | ||
458 | -- associated signatures on that key. | ||
459 | | DeleteSubkeyByUsage String | ||
460 | -- ^ Delete the subkey specified by the given fingerprint and any | ||
461 | -- associated signatures on that key. | ||
462 | deriving (Eq,Ord,Show) | ||
463 | |||
464 | -- | This type describes an idempotent transformation (merge or import) on a | ||
465 | -- set of GnuPG keyrings and other key files. | ||
466 | data KeyRingOperation = KeyRingOperation | ||
467 | { opFiles :: Map.Map InputFile StreamInfo | ||
468 | -- ^ Indicates files to be read or updated. | ||
469 | , opPassphrases :: [PassphraseSpec] | ||
470 | -- ^ Indicates files or file descriptors where passphrases can be found. | ||
471 | , opTransforms :: [Transform] | ||
472 | -- ^ Transformations to be performed on the key pool after all files have | ||
473 | -- been read and before any have been written. | ||
474 | , opHome :: Maybe FilePath | ||
475 | -- ^ If provided, this is the directory where the 'HomeSec' and 'HomePub' | ||
476 | -- files reside. Otherwise, the evironment variable $GNUPGHOME is consulted | ||
477 | -- and if that is not set, it falls back to $HOME/.gnupg. | ||
478 | } | ||
479 | deriving (Eq,Show) | ||
480 | |||
481 | resolveInputFile :: InputFileContext -> InputFile -> [FilePath] | ||
482 | resolveInputFile ctx = resolve | ||
483 | where | ||
484 | resolve HomeSec = return (homesecPath ctx) | ||
485 | resolve HomePub = return (homepubPath ctx) | ||
486 | resolve (ArgFile f) = return f | ||
487 | resolve _ = [] | ||
488 | |||
489 | resolveForReport :: Maybe InputFileContext -> InputFile -> FilePath | ||
490 | resolveForReport mctx (Pipe fdr fdw) = resolveForReport mctx (ArgFile str) | ||
491 | where str = case (fdr,fdw) of | ||
492 | (0,1) -> "-" | ||
493 | _ -> "&pipe" ++ show (fdr,fdw) | ||
494 | resolveForReport mctx (FileDesc fd) = resolveForReport mctx (ArgFile str) | ||
495 | where str = "&" ++ show fd | ||
496 | resolveForReport mctx f = concat $ resolveInputFile ctx f | ||
497 | where ctx = fromMaybe (InputFileContext "&secret" "&public") mctx | ||
498 | |||
499 | filesToLock :: | 311 | filesToLock :: |
500 | KeyRingOperation -> InputFileContext -> [FilePath] | 312 | KeyRingOperation -> InputFileContext -> [FilePath] |
501 | filesToLock k ctx = do | 313 | filesToLock k ctx = do |
@@ -635,33 +447,6 @@ instance ASN1Object RSAPrivateKey where | |||
635 | 447 | ||
636 | 448 | ||
637 | 449 | ||
638 | -- | This type is used to indicate success or failure | ||
639 | -- and in the case of success, return the computed object. | ||
640 | -- The 'FunctorToMaybe' class is implemented to facilitate | ||
641 | -- branching on failture. | ||
642 | data KikiCondition a = KikiSuccess a | ||
643 | | FailedToLock [FilePath] | ||
644 | | BadPassphrase | ||
645 | | FailedToMakeSignature | ||
646 | | CantFindHome | ||
647 | | AmbiguousKeySpec FilePath | ||
648 | | CannotImportMasterKey | ||
649 | | NoWorkingKey | ||
650 | deriving ( Functor, Show ) | ||
651 | |||
652 | instance FunctorToMaybe KikiCondition where | ||
653 | functorToMaybe (KikiSuccess a) = Just a | ||
654 | functorToMaybe _ = Nothing | ||
655 | |||
656 | instance Applicative KikiCondition where | ||
657 | pure a = KikiSuccess a | ||
658 | f <*> a = | ||
659 | case functorToEither f of | ||
660 | Right f -> case functorToEither a of | ||
661 | Right a -> pure (f a) | ||
662 | Left err -> err | ||
663 | Left err -> err | ||
664 | |||
665 | -- | This type is used to describe events triggered by 'runKeyRing'. In | 450 | -- | This type is used to describe events triggered by 'runKeyRing'. In |
666 | -- addition to normal feedback (e.g. 'NewPacket'), it also may indicate | 451 | -- addition to normal feedback (e.g. 'NewPacket'), it also may indicate |
667 | -- non-fatal IO exceptions (e.g. 'FailedExternal'). Because a | 452 | -- non-fatal IO exceptions (e.g. 'FailedExternal'). Because a |
@@ -1349,18 +1134,6 @@ seek_key (KeyUidMatch pat) ps | |||
1349 | uidStr _ = "" | 1134 | uidStr _ = "" |
1350 | 1135 | ||
1351 | 1136 | ||
1352 | data InputFileContext = InputFileContext | ||
1353 | { homesecPath :: FilePath | ||
1354 | , homepubPath :: FilePath | ||
1355 | } | ||
1356 | |||
1357 | readInputFileS :: InputFileContext -> InputFile -> IO S.ByteString | ||
1358 | readInputFileS ctx (Pipe fd _) = fdToHandle fd >>= S.hGetContents | ||
1359 | readInputFileS ctx (FileDesc fd) = fdToHandle fd >>= S.hGetContents | ||
1360 | readInputFileS ctx inp = do | ||
1361 | let fname = resolveInputFile ctx inp | ||
1362 | fmap S.concat $ mapM S.readFile fname | ||
1363 | |||
1364 | readInputFileL :: InputFileContext -> InputFile -> IO L.ByteString | 1137 | readInputFileL :: InputFileContext -> InputFile -> IO L.ByteString |
1365 | readInputFileL ctx (Pipe fd _) = fdToHandle fd >>= L.hGetContents | 1138 | readInputFileL ctx (Pipe fd _) = fdToHandle fd >>= L.hGetContents |
1366 | readInputFileL ctx (FileDesc fd) = fdToHandle fd >>= L.hGetContents | 1139 | readInputFileL ctx (FileDesc fd) = fdToHandle fd >>= L.hGetContents |
@@ -1436,27 +1209,6 @@ doesInputFileExist ctx f = do | |||
1436 | -} | 1209 | -} |
1437 | 1210 | ||
1438 | 1211 | ||
1439 | -- | Reads contents of an 'InputFile' or returns the cached content from a prior call. | ||
1440 | -- An optional prompt is provided and will be printed on stdout only in the case that | ||
1441 | -- the provided 'InputFile' is 'FileDesc' 0 (i.e. stdin). | ||
1442 | cachedContents :: Maybe S.ByteString -> InputFileContext -> InputFile -> IO (IO S.ByteString) | ||
1443 | cachedContents maybePrompt ctx fd = do | ||
1444 | ref <- newIORef Nothing | ||
1445 | return $ get maybePrompt ref fd | ||
1446 | where | ||
1447 | trimCR bs = fst $ S.spanEnd (\x -> x==10 || x==13) bs | ||
1448 | |||
1449 | get maybePrompt ref fd = do | ||
1450 | pw <- readIORef ref | ||
1451 | flip (flip maybe return) pw $ do | ||
1452 | if fd == FileDesc 0 then case maybePrompt of | ||
1453 | Just prompt -> S.hPutStr stderr prompt | ||
1454 | Nothing -> return () | ||
1455 | else return () | ||
1456 | pw <- fmap trimCR $ readInputFileS ctx fd | ||
1457 | writeIORef ref (Just pw) | ||
1458 | return pw | ||
1459 | |||
1460 | generateSubkey :: | 1212 | generateSubkey :: |
1461 | PacketTranscoder | 1213 | PacketTranscoder |
1462 | -> KikiCondition (KeyData, [(FilePath, KikiReportAction)]) -- db | 1214 | -> KikiCondition (KeyData, [(FilePath, KikiReportAction)]) -- db |
@@ -2589,115 +2341,6 @@ writePEMKeys doDecrypt db exports = do | |||
2589 | try pun $ \pun -> do | 2341 | try pun $ \pun -> do |
2590 | return $ KikiSuccess (fname,stream,pun) | 2342 | return $ KikiSuccess (fname,stream,pun) |
2591 | 2343 | ||
2592 | makeMemoizingDecrypter :: KeyRingOperation -> InputFileContext | ||
2593 | -> Map.Map KeyKey (OriginMapped Query) | ||
2594 | -> IO PacketTranscoder | ||
2595 | makeMemoizingDecrypter operation ctx keys = do | ||
2596 | if null chains then do | ||
2597 | -- (*) Notice we do not pass ctx to resolveForReport. | ||
2598 | -- This is because the merge function does not currently use a context | ||
2599 | -- and the pws map keys must match the MappedPacket locations. | ||
2600 | -- TODO: Perhaps these should both be of type InputFile rather than | ||
2601 | -- FilePath? | ||
2602 | -- pws :: Map.Map FilePath (IO S.ByteString) | ||
2603 | {- | ||
2604 | -- This disabled code obtained password sources from StreamInfo records. | ||
2605 | pws <- | ||
2606 | Traversable.mapM (cachedContents ctx . fromJust . pwfile . typ) | ||
2607 | (Map.mapKeys (resolveForReport Nothing) -- see note (*) note above | ||
2608 | $ Map.filter (isJust . pwfile . typ) $ opFiles operation) | ||
2609 | -} | ||
2610 | let prompt = Just "Enter possibly multi-line passphrase (Press CTRL-D when finished):\n" | ||
2611 | -- List of file-specific password sources. | ||
2612 | pws2 <- | ||
2613 | Traversable.mapM (cachedContents prompt ctx) | ||
2614 | $ Map.fromList $ mapMaybe | ||
2615 | (\spec -> (,passSpecPassFile spec) `fmap` do | ||
2616 | guard $ isNothing $ passSpecKeySpec spec | ||
2617 | passSpecRingFile spec) | ||
2618 | passspecs | ||
2619 | -- List of general password sources. | ||
2620 | defpw <- do | ||
2621 | Traversable.mapM (cachedContents prompt ctx . passSpecPassFile) | ||
2622 | $ listToMaybe $ filter (\sp -> isNothing (passSpecRingFile sp) | ||
2623 | && isNothing (passSpecKeySpec sp)) | ||
2624 | $ passspecs | ||
2625 | unkeysRef <- newIORef (Map.empty :: Map.Map KeyKey Packet) | ||
2626 | return $ doDecrypt unkeysRef ({- pws `Map.union` -} pws2) defpw (not $ null agentspec) | ||
2627 | else let PassphraseMemoizer f = head chains | ||
2628 | in return f | ||
2629 | where | ||
2630 | (chains,passspecs0) = partition isChain $ opPassphrases operation | ||
2631 | where isChain (PassphraseMemoizer {}) = True | ||
2632 | isChain _ = False | ||
2633 | (agentspec,passspecs) = partition isAgent $ opPassphrases operation | ||
2634 | where isAgent PassphraseAgent = True | ||
2635 | isAgent _ = False | ||
2636 | doDecrypt :: IORef (Map.Map KeyKey Packet) | ||
2637 | -> Map.Map FilePath (IO S.ByteString) | ||
2638 | -> Maybe (IO S.ByteString) | ||
2639 | -> Bool | ||
2640 | -> (SymmetricAlgorithm,S2K) | ||
2641 | -> MappedPacket | ||
2642 | -> IO (KikiCondition Packet) | ||
2643 | doDecrypt unkeysRef pws defpw agent_requested (dest_alg,dest_s2k) mp0 = do | ||
2644 | unkeys <- readIORef unkeysRef | ||
2645 | let (mp,qry) = fromMaybe (mp0,Query (packet mp0) "anonymous2" Nothing) $ do | ||
2646 | k <- Map.lookup kk keys | ||
2647 | return (mergeKeyPacket "decrypt" mp0 (fmap queryPacket k), packet k) | ||
2648 | wk = packet mp0 | ||
2649 | kk = keykey wk | ||
2650 | fs = Map.keys $ locations mp | ||
2651 | |||
2652 | decryptIt [] = return BadPassphrase | ||
2653 | decryptIt (getpw:getpws) = tries 1 getpw (decryptIt getpws) | ||
2654 | where | ||
2655 | tries count getpw recurse = do | ||
2656 | -- TODO: This function should use mergeKeyPacket to | ||
2657 | -- combine the packet with it's unspilled version before | ||
2658 | -- attempting to decrypt it. Note: We are uninterested | ||
2659 | -- in the 'locations' field, so this would effectively | ||
2660 | -- allow you to run 'decryptIt' on an unencrypted public key | ||
2661 | -- to obtain it's secret key. | ||
2662 | (pw,wants_retry) <- getpw (if count>1 then AskAgain "Bad pasphrase." else Ask,qry) | ||
2663 | let wkun = fromMaybe wk $ do | ||
2664 | guard $ symmetric_algorithm (packet mp) /= Unencrypted | ||
2665 | decryptSecretKey pw (packet mp) | ||
2666 | |||
2667 | case symmetric_algorithm wkun of | ||
2668 | |||
2669 | Unencrypted -> do | ||
2670 | writeIORef unkeysRef (Map.insert kk wkun unkeys) | ||
2671 | ek <- if dest_alg==Unencrypted | ||
2672 | then return $ Just wkun | ||
2673 | else encryptSecretKey pw dest_s2k dest_alg wkun | ||
2674 | case ek of | ||
2675 | Nothing | wants_retry && count<3 -> tries (count+1) getpw recurse | ||
2676 | Nothing -> recurse | ||
2677 | Just wken -> return $ KikiSuccess wken | ||
2678 | |||
2679 | _ -> recurse | ||
2680 | |||
2681 | getpws = (map (const . fmap (,False)) $ mapMaybe (`Map.lookup` pws) fs ++ maybeToList defpw) ++ [ agentpw | agent_requested ] | ||
2682 | |||
2683 | agentpw (ask,qry) = do | ||
2684 | s <- session | ||
2685 | fromMaybe (return ("",False)) $ do | ||
2686 | s <- s | ||
2687 | Just $ do | ||
2688 | case ask of AskAgain _ -> clearPassphrase s (queryPacket qry) | ||
2689 | _ -> return () | ||
2690 | mbpw <- getPassphrase s ask qry | ||
2691 | quit s | ||
2692 | return ( maybe "" S8.pack mbpw, True) | ||
2693 | |||
2694 | if symmetric_algorithm wk == dest_alg | ||
2695 | && ( symmetric_algorithm wk == Unencrypted || s2k wk == dest_s2k ) | ||
2696 | then return (KikiSuccess wk) | ||
2697 | else maybe (decryptIt getpws) | ||
2698 | (return . KikiSuccess) | ||
2699 | $ Map.lookup kk unkeys | ||
2700 | |||
2701 | performManipulations :: | 2344 | performManipulations :: |
2702 | (PacketDecrypter) | 2345 | (PacketDecrypter) |
2703 | -> KeyRingRuntime | 2346 | -> KeyRingRuntime |
@@ -3162,19 +2805,6 @@ lookupEnv var = | |||
3162 | handleIO_ (return Nothing) $ fmap Just (getEnv var) | 2805 | handleIO_ (return Nothing) $ fmap Just (getEnv var) |
3163 | #endif | 2806 | #endif |
3164 | 2807 | ||
3165 | isKey :: Packet -> Bool | ||
3166 | isKey (PublicKeyPacket {}) = True | ||
3167 | isKey (SecretKeyPacket {}) = True | ||
3168 | isKey _ = False | ||
3169 | |||
3170 | isUserID :: Packet -> Bool | ||
3171 | isUserID (UserIDPacket {}) = True | ||
3172 | isUserID _ = False | ||
3173 | |||
3174 | isTrust :: Packet -> Bool | ||
3175 | isTrust (TrustPacket {}) = True | ||
3176 | isTrust _ = False | ||
3177 | |||
3178 | sigpackets :: | 2808 | sigpackets :: |
3179 | Monad m => | 2809 | Monad m => |
3180 | Word8 -> [SignatureSubpacket] -> [SignatureSubpacket] -> m Packet | 2810 | Word8 -> [SignatureSubpacket] -> [SignatureSubpacket] -> m Packet |
@@ -3497,32 +3127,10 @@ makeSig doDecrypt top fname subkey_p tags mbsig = do | |||
3497 | return $ fmap (,[]) newsig | 3127 | return $ fmap (,[]) newsig |
3498 | 3128 | ||
3499 | 3129 | ||
3500 | -- | The position and acces a packet had before the operation | ||
3501 | data OriginFlags = OriginFlags | ||
3502 | { originallyPublic :: Bool | ||
3503 | -- ^ false if SecretKeyPacket | ||
3504 | , originalNum :: Int | ||
3505 | -- ^ packets are numbered, starting from 1.. | ||
3506 | } deriving Show | ||
3507 | |||
3508 | type OriginMap = Map.Map FilePath OriginFlags | ||
3509 | |||
3510 | type MappedPacket = OriginMapped Packet | ||
3511 | data OriginMapped a = MappedPacket | ||
3512 | { packet :: a | ||
3513 | , locations :: OriginMap | ||
3514 | } deriving Show | ||
3515 | instance Functor OriginMapped where | ||
3516 | fmap f (MappedPacket x ls) = MappedPacket (f x) ls | ||
3517 | |||
3518 | type TrustMap = Map.Map FilePath Packet | 3130 | type TrustMap = Map.Map FilePath Packet |
3519 | type SigAndTrust = ( MappedPacket | 3131 | type SigAndTrust = ( MappedPacket |
3520 | , TrustMap ) -- trust packets | 3132 | , TrustMap ) -- trust packets |
3521 | 3133 | ||
3522 | -- | The 'KeyKey'-type is used to store the information of a key | ||
3523 | -- which is used for finger-printing | ||
3524 | type KeyKey = [ByteString] | ||
3525 | |||
3526 | data SubKey = SubKey MappedPacket [SigAndTrust] deriving Show | 3134 | data SubKey = SubKey MappedPacket [SigAndTrust] deriving Show |
3527 | 3135 | ||
3528 | -- | This is a GPG Identity which includes a master key and all its UIDs and | 3136 | -- | This is a GPG Identity which includes a master key and all its UIDs and |
@@ -3554,15 +3162,6 @@ mappedPacketWithHint filename p hint = MappedPacket | |||
3554 | , locations = Map.singleton filename (origin p hint) | 3162 | , locations = Map.singleton filename (origin p hint) |
3555 | } | 3163 | } |
3556 | 3164 | ||
3557 | keykey :: Packet -> KeyKey | ||
3558 | keykey key = | ||
3559 | -- Note: The key's timestamp is normally included in it's fingerprint. | ||
3560 | -- This is undesirable for kiki because it causes the same | ||
3561 | -- key to be imported multiple times and show as apparently | ||
3562 | -- distinct keys with different fingerprints. | ||
3563 | -- Thus, we will remove the timestamp. | ||
3564 | fingerprint_material (key {timestamp=0}) -- TODO: smaller key? | ||
3565 | |||
3566 | uidkey :: Packet -> String | 3165 | uidkey :: Packet -> String |
3567 | uidkey (UserIDPacket str) = str | 3166 | uidkey (UserIDPacket str) = str |
3568 | 3167 | ||
@@ -3598,29 +3197,6 @@ onionName kd = (addr,name) | |||
3598 | (addr,(name:_,_)) = getHostnames kd | 3197 | (addr,(name:_,_)) = getHostnames kd |
3599 | -} | 3198 | -} |
3600 | 3199 | ||
3601 | -- | Compare different versions if the same key pair. Public versions | ||
3602 | -- are considered greater. If the two packets do not represent the same | ||
3603 | -- key or the packets are not keys at all, an error will result that | ||
3604 | -- includes the context provided as the first argument. | ||
3605 | keyCompare :: String -> Packet -> Packet -> Ordering | ||
3606 | keyCompare what (SecretKeyPacket {}) (PublicKeyPacket {}) = LT | ||
3607 | keyCompare what (PublicKeyPacket {}) (SecretKeyPacket {}) = GT | ||
3608 | keyCompare what a b | keykey a==keykey b = EQ | ||
3609 | keyCompare what a b = error $ unlines ["Unable to merge "++what++":" | ||
3610 | , if isKey a then fingerprint a else "" | ||
3611 | , PP.ppShow a | ||
3612 | , if isKey b then fingerprint b else "" | ||
3613 | , PP.ppShow b | ||
3614 | ] | ||
3615 | |||
3616 | -- | Merge two representations of the same key, prefering secret version | ||
3617 | -- because they have more information. | ||
3618 | mergeKeyPacket :: String -> MappedPacket -> MappedPacket -> MappedPacket | ||
3619 | mergeKeyPacket what key p = | ||
3620 | key { packet = minimumBy (keyCompare what) [packet key,packet p] | ||
3621 | , locations = Map.union (locations key) (locations p) | ||
3622 | } | ||
3623 | |||
3624 | 3200 | ||
3625 | merge_ :: KeyDB -> FilePath -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] | 3201 | merge_ :: KeyDB -> FilePath -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] |
3626 | -> KeyDB | 3202 | -> KeyDB |