diff options
Diffstat (limited to 'lib/KeyRing/BuildKeyDB.hs')
-rw-r--r-- | lib/KeyRing/BuildKeyDB.hs | 101 |
1 files changed, 59 insertions, 42 deletions
diff --git a/lib/KeyRing/BuildKeyDB.hs b/lib/KeyRing/BuildKeyDB.hs index a3df62d..c5754f1 100644 --- a/lib/KeyRing/BuildKeyDB.hs +++ b/lib/KeyRing/BuildKeyDB.hs | |||
@@ -36,6 +36,7 @@ import qualified Data.ByteString.Lazy as L (ByteString, concat, empty, | |||
36 | null, toChunks, | 36 | null, toChunks, |
37 | toStrict, head) | 37 | toStrict, head) |
38 | import Data.Char | 38 | import Data.Char |
39 | import Data.Functor | ||
39 | import Data.List | 40 | import Data.List |
40 | import qualified Data.Map as Map | 41 | import qualified Data.Map as Map |
41 | import Data.Maybe | 42 | import Data.Maybe |
@@ -191,7 +192,7 @@ buildKeyDB ctx grip0 keyring = do | |||
191 | , rtGrip = grip | 192 | , rtGrip = grip |
192 | , rtWorkingKey = wk | 193 | , rtWorkingKey = wk |
193 | , rtRingAccess = accs | 194 | , rtRingAccess = accs |
194 | , rtKeyDB = Map.empty | 195 | , rtKeyDB = emptyKeyDB |
195 | , rtPassphrases = transcode | 196 | , rtPassphrases = transcode |
196 | } | 197 | } |
197 | -- autosigns and deletes | 198 | -- autosigns and deletes |
@@ -199,7 +200,7 @@ buildKeyDB ctx grip0 keyring = do | |||
199 | let trans :: InputFile -> (StreamInfo,Message) -> IO (KikiCondition (KikiReport,KeyDB)) | 200 | let trans :: InputFile -> (StreamInfo,Message) -> IO (KikiCondition (KikiReport,KeyDB)) |
200 | trans f (info,ps) = do | 201 | trans f (info,ps) = do |
201 | let manip = combineTransforms (transforms info) | 202 | let manip = combineTransforms (transforms info) |
202 | rt1 = rt0 { rtKeyDB = merge Map.empty f ps } | 203 | rt1 = rt0 { rtKeyDB = merge emptyKeyDB f ps } |
203 | acc = Just Sec /= Map.lookup f accs | 204 | acc = Just Sec /= Map.lookup f accs |
204 | r <- performManipulations doDecrypt rt1 mwk manip | 205 | r <- performManipulations doDecrypt rt1 mwk manip |
205 | try r $ \(rt2,report) -> do | 206 | try r $ \(rt2,report) -> do |
@@ -214,10 +215,11 @@ buildKeyDB ctx grip0 keyring = do | |||
214 | #endif | 215 | #endif |
215 | try transformed0 $ \transformed -> do | 216 | try transformed0 $ \transformed -> do |
216 | let -- | db_rings - all keyrings combined into one | 217 | let -- | db_rings - all keyrings combined into one |
217 | db_rings :: Map.Map KeyKey KeyData | 218 | db_rings = Map.foldlWithKey' mergeIt emptyKeyDB transformed |
218 | db_rings = Map.foldlWithKey' mergeIt Map.empty transformed | ||
219 | where | 219 | where |
220 | mergeIt db f (_,dbtrans) = Map.unionWith mergeKeyData db dbtrans | 220 | mergeIt db f (_,dbtrans) |
221 | = KeyDB { byKeyKey = Map.unionWith mergeKeyData (byKeyKey db) (byKeyKey dbtrans) | ||
222 | } | ||
221 | -- | reportTrans | 223 | -- | reportTrans |
222 | -- events, indexed by file | 224 | -- events, indexed by file |
223 | reportTrans :: [(FilePath, KikiReportAction)] | 225 | reportTrans :: [(FilePath, KikiReportAction)] |
@@ -257,7 +259,7 @@ buildKeyDB ctx grip0 keyring = do | |||
257 | -- TODO: KikiCondition reporting for spill/fill usage mismatch? | 259 | -- TODO: KikiCondition reporting for spill/fill usage mismatch? |
258 | -- TODO: parseSpec3 | 260 | -- TODO: parseSpec3 |
259 | let (topspec,subspec) = parseSpec grip usage | 261 | let (topspec,subspec) = parseSpec grip usage |
260 | ms = map fst $ filterMatches topspec (Map.toList db) | 262 | ms = map fst $ filterMatches topspec (Map.toList $ byKeyKey db) |
261 | cmd = initializer stream | 263 | cmd = initializer stream |
262 | return (n,subspec,ms,stream, cmd) | 264 | return (n,subspec,ms,stream, cmd) |
263 | 265 | ||
@@ -356,25 +358,35 @@ merge :: KeyDB -> InputFile -> Message -> KeyDB | |||
356 | merge db inputfile (Message ps) = merge_ db filename qs | 358 | merge db inputfile (Message ps) = merge_ db filename qs |
357 | where | 359 | where |
358 | filename = resolveForReport Nothing inputfile | 360 | filename = resolveForReport Nothing inputfile |
359 | |||
360 | qs = scanPackets filename ps | 361 | qs = scanPackets filename ps |
361 | 362 | ||
362 | scanPackets :: FilePath -> [Packet] -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] | 363 | -- Aggregate packets into a list of triples: |
363 | scanPackets filename [] = [] | 364 | -- |
364 | scanPackets filename (p:ps) = scanl doit (doit (MarkerPacket,MarkerPacket,ret MarkerPacket) p) ps | 365 | -- A top (master) key |
365 | where | 366 | -- |
366 | ret p = (p,Map.empty) | 367 | -- A subkey, or if this entry corresponds to the master-key, this field is a |
367 | doit (top,sub,prev) p = | 368 | -- MarkerPacket placeholder. |
368 | case p of | 369 | -- |
369 | _ | isKey p && not (is_subkey p) -> (p,MarkerPacket,ret p) | 370 | -- An optional trust packet in the form of a singleton or empty Map whose key |
370 | _ | isKey p && is_subkey p -> (top,p,ret p) | 371 | -- is the filename. |
371 | _ | isUserID p -> (top,p,ret p) | 372 | scanPackets :: FilePath -> [Packet] -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] |
372 | _ | isTrust p -> (top,sub,updateTrust top sub prev p) | 373 | scanPackets filename [] = [] |
373 | _ -> (top,sub,ret p) | 374 | scanPackets filename (p:ps) = scanl doit (doit (MarkerPacket,MarkerPacket,ret MarkerPacket) p) ps |
374 | 375 | where | |
375 | updateTrust top (PublicKeyPacket {}) (pre,t) p = (pre,Map.insert filename p t) -- public | 376 | ret p = (p,Map.empty) |
376 | updateTrust (PublicKeyPacket {}) _ (pre,t) p = (pre,Map.insert filename p t) -- public | 377 | doit (top,sub,prev) p = |
377 | updateTrust _ _ (pre,t) p = (pre,Map.insert filename p t) -- secret | 378 | case p of |
379 | _ | isKey p && not (is_subkey p) -> (p,MarkerPacket,ret p) | ||
380 | _ | isKey p && is_subkey p -> (top,p,ret p) | ||
381 | _ | isUserID p -> (top,p,ret p) | ||
382 | _ | isTrust p -> (top,sub,updateTrust top sub prev p) | ||
383 | _ -> (top,sub,ret p) | ||
384 | |||
385 | -- Most arguments are ignored and we simply create the singleton trust-map when appropriate. | ||
386 | -- XXX: Simplify this? | ||
387 | updateTrust top (PublicKeyPacket {}) (pre,t) p = (pre,Map.insert filename p t) -- public | ||
388 | updateTrust (PublicKeyPacket {}) _ (pre,t) p = (pre,Map.insert filename p t) -- public | ||
389 | updateTrust _ _ (pre,t) p = (pre,Map.insert filename p t) -- secret | ||
378 | 390 | ||
379 | 391 | ||
380 | mergeKeyData :: KeyData -> KeyData -> KeyData | 392 | mergeKeyData :: KeyData -> KeyData -> KeyData |
@@ -405,17 +417,18 @@ mergeKeyData (KeyData atop asigs auids asubs) | |||
405 | 417 | ||
406 | doImportG | 418 | doImportG |
407 | :: PacketTranscoder | 419 | :: PacketTranscoder |
408 | -> Map.Map KeyKey KeyData | 420 | -> KeyDB |
409 | -> [KeyKey] -- m0, only head is used | 421 | -> [KeyKey] -- m0, only head is used |
410 | -> [SignatureSubpacket] -- tags | 422 | -> [SignatureSubpacket] -- tags |
411 | -> InputFile | 423 | -> InputFile |
412 | -> Packet | 424 | -> Packet |
413 | -> IO (KikiCondition (Map.Map KeyKey KeyData, [(FilePath,KikiReportAction)])) | 425 | -> IO (KikiCondition (KeyDB, [(FilePath,KikiReportAction)])) |
414 | doImportG transcode db m0 tags fname key = do | 426 | doImportG transcode db m0 tags fname key = do |
415 | let kk = head m0 | 427 | let kk = head m0 |
416 | Just kd@(KeyData top topsigs uids subs) = Map.lookup kk db | 428 | Just kd@(KeyData top topsigs uids subs) = Map.lookup kk (byKeyKey db) |
417 | kdr <- insertSubkey transcode kk kd tags fname key | 429 | kdr <- insertSubkey transcode kk kd tags fname key |
418 | try kdr $ \(kd',rrs) -> return $ KikiSuccess (Map.insert kk kd' db, rrs) | 430 | try kdr $ \(kd',rrs) -> return $ KikiSuccess ( db { byKeyKey = Map.insert kk kd' (byKeyKey db) } |
431 | , rrs) | ||
419 | 432 | ||
420 | 433 | ||
421 | iswallet :: FileType -> Bool | 434 | iswallet :: FileType -> Bool |
@@ -514,7 +527,7 @@ outgoing_names db hostdbs0 = IPsToWriteToHostsFile $ do | |||
514 | guard $ all (null . Hosts.namesForAddress addr) hostdbs0 | 527 | guard $ all (null . Hosts.namesForAddress addr) hostdbs0 |
515 | return addr | 528 | return addr |
516 | where | 529 | where |
517 | gpgnames = map getHostnames $ Map.elems db | 530 | gpgnames = map getHostnames $ Map.elems $ byKeyKey db |
518 | 531 | ||
519 | filterMatches :: KeySpec -> [(KeyKey,KeyData)] -> [(KeyKey,KeyData)] | 532 | filterMatches :: KeySpec -> [(KeyKey,KeyData)] -> [(KeyKey,KeyData)] |
520 | filterMatches spec ks = filter (matchSpec spec . snd) ks | 533 | filterMatches spec ks = filter (matchSpec spec . snd) ks |
@@ -522,9 +535,9 @@ filterMatches spec ks = filter (matchSpec spec . snd) ks | |||
522 | importSecretKey :: | 535 | importSecretKey :: |
523 | (PacketTranscoder) | 536 | (PacketTranscoder) |
524 | -> KikiCondition | 537 | -> KikiCondition |
525 | (Map.Map KeyKey KeyData, [(FilePath, KikiReportAction)]) | 538 | (KeyDB, [(FilePath, KikiReportAction)]) |
526 | -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t) | 539 | -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t) |
527 | -> IO (KikiCondition (Map.Map KeyKey KeyData, [(FilePath, KikiReportAction)])) | 540 | -> IO (KikiCondition (KeyDB, [(FilePath, KikiReportAction)])) |
528 | importSecretKey transcode db' tup = do | 541 | importSecretKey transcode db' tup = do |
529 | try db' $ \(db',report0) -> do | 542 | try db' $ \(db',report0) -> do |
530 | r <- doImport transcode | 543 | r <- doImport transcode |
@@ -536,16 +549,17 @@ importSecretKey transcode db' tup = do | |||
536 | generateInternals :: | 549 | generateInternals :: |
537 | PacketTranscoder | 550 | PacketTranscoder |
538 | -> Maybe MappedPacket | 551 | -> Maybe MappedPacket |
539 | -> Map.Map KeyKey KeyData | 552 | -> KeyDB |
540 | -> [(GenerateKeyParams,StreamInfo)] | 553 | -> [(GenerateKeyParams,StreamInfo)] |
541 | -> IO (KikiCondition (Map.Map KeyKey KeyData, [(FilePath, KikiReportAction)])) | 554 | -> IO (KikiCondition (KeyDB, [(FilePath, KikiReportAction)])) |
542 | generateInternals transcode mwk db gens = do | 555 | generateInternals transcode mwk db gens = do |
543 | case fmap packet mwk >>= \wk -> Map.lookup (keykey wk) db of | 556 | case fmap packet mwk >>= \wk -> Map.lookup (keykey wk) (byKeyKey db) of |
544 | Just kd0 -> do | 557 | Just kd0 -> do |
545 | kd <- foldM (generateSubkey transcode) (KikiSuccess (kd0,[])) gens | 558 | kd <- foldM (generateSubkey transcode) (KikiSuccess (kd0,[])) gens |
546 | try kd $ \(kd,reportGens) -> do | 559 | try kd $ \(kd,reportGens) -> do |
547 | let kk = keykey $ packet $ fromJust mwk | 560 | let kk = keykey $ packet $ fromJust mwk |
548 | return $ KikiSuccess (Map.insert kk kd db,reportGens) | 561 | return $ KikiSuccess ( KeyDB { byKeyKey = Map.insert kk kd (byKeyKey db) } |
562 | , reportGens ) | ||
549 | Nothing -> return $ KikiSuccess (db,[]) | 563 | Nothing -> return $ KikiSuccess (db,[]) |
550 | 564 | ||
551 | mergeHostFiles :: KeyRingOperation -> KeyDB -> InputFileContext | 565 | mergeHostFiles :: KeyRingOperation -> KeyDB -> InputFileContext |
@@ -575,7 +589,7 @@ mergeHostFiles krd db ctx = do | |||
575 | 589 | ||
576 | hostdbs0 <- mapM (fmap Hosts.decode . readInputFileL' ctx) hns | 590 | hostdbs0 <- mapM (fmap Hosts.decode . readInputFileL' ctx) hns |
577 | 591 | ||
578 | let gpgnames = map getHostnames $ Map.elems db | 592 | let gpgnames = map getHostnames $ Map.elems (byKeyKey db) |
579 | os = do | 593 | os = do |
580 | Hostnames addr ns _ _ <- gpgnames | 594 | Hostnames addr ns _ _ <- gpgnames |
581 | n <- ns | 595 | n <- ns |
@@ -604,7 +618,8 @@ mergeHostFiles krd db ctx = do | |||
604 | 618 | ||
605 | -- 2. replace gpg annotations with those in U | 619 | -- 2. replace gpg annotations with those in U |
606 | -- forM use_db | 620 | -- forM use_db |
607 | db' <- Traversable.mapM (setHostnames addrs u1) db | 621 | db' <- Traversable.mapM (setHostnames addrs u1) (byKeyKey db) |
622 | <&> \m -> db { byKeyKey = m } | ||
608 | 623 | ||
609 | return $ KikiSuccess ((db',(hostdbs0,hostdbs,u1,gpgnames,addrs)),[]) | 624 | return $ KikiSuccess ((db',(hostdbs0,hostdbs,u1,gpgnames,addrs)),[]) |
610 | 625 | ||
@@ -649,7 +664,8 @@ merge_ db filename qs = foldl mergeit db (zip [0..] qs) | |||
649 | where | 664 | where |
650 | -- mergeit db (_,_,TrustPacket {}) = db -- Filter TrustPackets | 665 | -- mergeit db (_,_,TrustPacket {}) = db -- Filter TrustPackets |
651 | mergeit :: KeyDB -> (Int,(Packet,Packet,(Packet,Map.Map FilePath Packet))) -> KeyDB | 666 | mergeit :: KeyDB -> (Int,(Packet,Packet,(Packet,Map.Map FilePath Packet))) -> KeyDB |
652 | mergeit db adding@(n,(top,sub,ptt@(p,trustmap))) | isKey top = Map.alter update (keykey top) db | 667 | mergeit db adding@(n,(top,sub,ptt@(p,trustmap))) |
668 | | isKey top = db { byKeyKey = Map.alter update (keykey top) (byKeyKey db) } | ||
653 | where | 669 | where |
654 | update Nothing = Just $ KeyData (mappedPacketWithHint filename p n) [] Map.empty Map.empty | 670 | update Nothing = Just $ KeyData (mappedPacketWithHint filename p n) [] Map.empty Map.empty |
655 | update (Just kd) = dbInsertPacket kd filename adding | 671 | update (Just kd) = dbInsertPacket kd filename adding |
@@ -828,9 +844,9 @@ matchSpec (KeyUidMatch pat) (KeyData _ _ uids _) = not $ null us | |||
828 | 844 | ||
829 | doImport | 845 | doImport |
830 | :: PacketTranscoder | 846 | :: PacketTranscoder |
831 | -> Map.Map KeyKey KeyData | 847 | -> KeyDB |
832 | -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t) | 848 | -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t) |
833 | -> IO (KikiCondition (Map.Map KeyKey KeyData, [(FilePath,KikiReportAction)])) | 849 | -> IO (KikiCondition (KeyDB, [(FilePath,KikiReportAction)])) |
834 | doImport transcode db (fname,subspec,ms,typ -> typ,_) = do | 850 | doImport transcode db (fname,subspec,ms,typ -> typ,_) = do |
835 | flip (maybe $ return CannotImportMasterKey) | 851 | flip (maybe $ return CannotImportMasterKey) |
836 | subspec $ \tag -> do | 852 | subspec $ \tag -> do |
@@ -1389,7 +1405,7 @@ extractRSAKeyFields kvs = do | |||
1389 | 1405 | ||
1390 | selectKey0 :: Bool -> (KeySpec,Maybe String) -> KeyDB -> Maybe Packet | 1406 | selectKey0 :: Bool -> (KeySpec,Maybe String) -> KeyDB -> Maybe Packet |
1391 | selectKey0 wantPublic (spec,mtag) db = do | 1407 | selectKey0 wantPublic (spec,mtag) db = do |
1392 | let Message ps = flattenKeys wantPublic db | 1408 | let Message ps = flattenKeys wantPublic $ byKeyKey db |
1393 | ys = snd $ seek_key spec ps | 1409 | ys = snd $ seek_key spec ps |
1394 | flip (maybe (listToMaybe ys)) mtag $ \tag -> do | 1410 | flip (maybe (listToMaybe ys)) mtag $ \tag -> do |
1395 | case ys of | 1411 | case ys of |
@@ -1410,8 +1426,9 @@ packetFromPublicRSAKey notBefore n e = | |||
1410 | , v3_days_of_validity = Nothing | 1426 | , v3_days_of_validity = Nothing |
1411 | } | 1427 | } |
1412 | 1428 | ||
1413 | flattenKeys :: Bool -> KeyDB -> Message | 1429 | flattenKeys :: Bool -> Map.Map KeyKey KeyData -> Message |
1414 | flattenKeys isPublic db = Message $ concatMap (map packet . flattenTop "" isPublic . snd) (prefilter . Map.assocs $ db) | 1430 | flattenKeys isPublic db = Message $ concatMap (map packet . flattenTop "" isPublic . snd) |
1431 | (prefilter . Map.assocs $ db) | ||
1415 | where | 1432 | where |
1416 | prefilter = if isPublic then id else filter isSecret | 1433 | prefilter = if isPublic then id else filter isSecret |
1417 | where | 1434 | where |