summaryrefslogtreecommitdiff
path: root/kiki.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2014-04-12 17:19:46 -0400
committerjoe <joe@jerkface.net>2014-04-12 17:19:46 -0400
commita8da6f5843f3a5e6f7c975a746dea27adcf3907e (patch)
treee23abc66e741c336b9c70aca08f34af9bac4309e /kiki.hs
parent23dfd840a059877af0ff2538b2d46d85a0842ed9 (diff)
moved merge function into KeyRing module
Diffstat (limited to 'kiki.hs')
-rw-r--r--kiki.hs205
1 files changed, 0 insertions, 205 deletions
diff --git a/kiki.hs b/kiki.hs
index 217f70f..47d9bdb 100644
--- a/kiki.hs
+++ b/kiki.hs
@@ -328,22 +328,12 @@ writePEM typ dta = pem
328 328
329 -- 64 byte lines 329 -- 64 byte lines
330 330
331isKey (PublicKeyPacket {}) = True
332isKey (SecretKeyPacket {}) = True
333isKey _ = False
334
335isUserID (UserIDPacket {}) = True
336isUserID _ = False
337
338isEmbeddedSignature (EmbeddedSignaturePacket {}) = True 331isEmbeddedSignature (EmbeddedSignaturePacket {}) = True
339isEmbeddedSignature _ = False 332isEmbeddedSignature _ = False
340 333
341isCertificationSig (CertificationSignature {}) = True 334isCertificationSig (CertificationSignature {}) = True
342isCertificationSig _ = True 335isCertificationSig _ = True
343 336
344isTrust (TrustPacket {}) = True
345isTrust _ = False
346
347issuer (IssuerPacket issuer) = Just issuer 337issuer (IssuerPacket issuer) = Just issuer
348issuer _ = Nothing 338issuer _ = Nothing
349backsig (EmbeddedSignaturePacket s) = Just s 339backsig (EmbeddedSignaturePacket s) = Just s
@@ -1008,203 +998,8 @@ is40digitHex xs = ys == xs && length ys==40
1008 | 'a' <= c && c <= 'f' = True 998 | 'a' <= c && c <= 'f' = True
1009 ishex c = False 999 ishex c = False
1010 1000
1011scanPackets :: FilePath -> [Packet] -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))]
1012scanPackets filename [] = []
1013scanPackets filename (p:ps) = scanl doit (doit (MarkerPacket,MarkerPacket,ret MarkerPacket) p) ps
1014 where
1015 ret p = (p,Map.empty)
1016 doit (top,sub,prev) p =
1017 case p of
1018 _ | isKey p && not (is_subkey p) -> (p,MarkerPacket,ret p)
1019 _ | isKey p && is_subkey p -> (top,p,ret p)
1020 _ | isUserID p -> (top,p,ret p)
1021 _ | isTrust p -> (top,sub,updateTrust top sub prev p)
1022 _ | otherwise -> (top,sub,ret p)
1023
1024 updateTrust top (PublicKeyPacket {}) (pre,t) p = (pre,Map.insert filename p t) -- public
1025 updateTrust (PublicKeyPacket {}) _ (pre,t) p = (pre,Map.insert filename p t) -- public
1026 updateTrust _ _ (pre,t) p = (pre,Map.insert filename p t) -- secret
1027
1028
1029data OriginFlags = OriginFlags {
1030 originallyPublic :: Bool,
1031 originalNum :: Int
1032 }
1033 deriving Show
1034origin :: Packet -> Int -> OriginFlags
1035origin p n = OriginFlags ispub n
1036 where
1037 ispub = case p of
1038 SecretKeyPacket {} -> False
1039 _ -> True
1040
1041type OriginMap = Map.Map FilePath OriginFlags
1042data MappedPacket = MappedPacket
1043 { packet :: Packet
1044 , usage_tag :: Maybe String
1045 , locations :: OriginMap
1046 }
1047
1048mappedPacket filename p = MappedPacket
1049 { packet = p
1050 , usage_tag = Nothing
1051 , locations = Map.singleton filename (origin p (-1))
1052 }
1053
1054type TrustMap = Map.Map FilePath Packet
1055type SigAndTrust = ( MappedPacket
1056 , TrustMap ) -- trust packets
1057
1058type KeyKey = [Char8.ByteString]
1059data SubKey = SubKey MappedPacket [SigAndTrust]
1060data KeyData = KeyData MappedPacket -- main key
1061 [SigAndTrust] -- sigs on main key
1062 (Map.Map String ([SigAndTrust],OriginMap)) -- uids
1063 (Map.Map KeyKey SubKey) -- subkeys
1064
1065type KeyDB = Map.Map KeyKey KeyData
1066
1067torhash key = maybe "" id $ derToBase32 <$> derRSA key 1001torhash key = maybe "" id $ derToBase32 <$> derRSA key
1068 1002
1069keykey key =
1070 -- Note: The key's timestamp is included in it's fingerprint.
1071 -- Therefore, the same key with a different timestamp is
1072 -- considered distinct using this keykey implementation.
1073 fingerprint_material (key {timestamp=0}) -- TODO: smaller key?
1074
1075
1076
1077uidkey (UserIDPacket str) = str
1078
1079-- Compare master keys, LT is prefered for merging
1080keycomp (SecretKeyPacket {}) (PublicKeyPacket {}) = LT
1081keycomp (PublicKeyPacket {}) (SecretKeyPacket {}) = GT
1082keycomp a b | keykey a==keykey b = EQ
1083keycomp a b = error $ unlines ["Unable to merge keys:"
1084 , fingerprint a
1085 , PP.ppShow a
1086 , fingerprint b
1087 , PP.ppShow b
1088 ]
1089
1090-- Compare subkeys, LT is prefered for merging
1091subcomp (SecretKeyPacket {}) (PublicKeyPacket {}) = LT
1092subcomp (PublicKeyPacket {}) (SecretKeyPacket {}) = GT
1093subcomp a b | keykey a==keykey b = EQ
1094subcomp a b = error $ unlines ["Unable to merge subs:"
1095 , fingerprint a
1096 , PP.ppShow a
1097 , fingerprint b
1098 , PP.ppShow b
1099 ]
1100subcomp_m a b = subcomp (packet a) (packet b)
1101
1102merge :: KeyDB -> FilePath -> Message -> KeyDB
1103merge db filename (Message ps) = merge_ db filename qs
1104 where
1105 qs = scanPackets filename ps
1106
1107merge_ :: KeyDB -> FilePath -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))]
1108 -> KeyDB
1109merge_ db filename qs = foldl mergeit db (zip [0..] qs)
1110 where
1111 asMapped n p = let m = mappedPacket filename p
1112 in m { locations = fmap (\x->x {originalNum=n}) (locations m) }
1113 asSigAndTrust n (p,tm) = (asMapped n p,tm)
1114 emptyUids = Map.empty
1115 -- mergeit db (_,_,TrustPacket {}) = db -- Filter TrustPackets
1116 mergeit :: KeyDB -> (Int,(Packet,Packet,(Packet,Map.Map FilePath Packet))) -> KeyDB
1117 mergeit db (n,(top,sub,ptt@(p,trustmap))) | isKey top = Map.alter update (keykey top) db
1118 where
1119 -- NOTE:
1120 -- if a keyring file has both a public key packet and a secret key packet
1121 -- for the same key, then only one of them will survive, which ever is
1122 -- later in the file.
1123 --
1124 -- This is due to the use of statements like
1125 -- (Map.insert filename (origin p n) (locations key))
1126 --
1127 update v | isKey p && not (is_subkey p)
1128 = case v of
1129 Nothing -> Just $ KeyData (asMapped n p) [] emptyUids Map.empty
1130 Just (KeyData key sigs uids subkeys) | keykey (packet key) == keykey p
1131 -> Just $ KeyData ( (asMapped n (minimumBy keycomp [packet key,p]))
1132 { locations = Map.insert filename (origin p n) (locations key) } )
1133 sigs
1134 uids
1135 subkeys
1136 _ -> error . concat $ ["Unexpected master key merge error: "
1137 ,show (fingerprint top, fingerprint p)]
1138 update (Just (KeyData key sigs uids subkeys)) | isKey p && is_subkey p
1139 = Just $ KeyData key sigs uids (Map.alter (mergeSubkey n p) (keykey p) subkeys)
1140 update (Just (KeyData key sigs uids subkeys)) | isUserID p
1141 = Just $ KeyData key sigs (Map.alter (mergeUid n ptt) (uidkey p) uids)
1142 subkeys
1143 update (Just (KeyData key sigs uids subkeys))
1144 = case sub of
1145 MarkerPacket -> Just $ KeyData key (mergeSig n ptt sigs) uids subkeys
1146 UserIDPacket {} -> Just $ KeyData key
1147 sigs
1148 (Map.alter (mergeUidSig n ptt) (uidkey sub) uids)
1149 subkeys
1150 _ | isKey sub -> Just $ KeyData key
1151 sigs
1152 uids
1153 (Map.alter (mergeSubSig n ptt) (keykey sub) subkeys)
1154 _ -> error $ "Unexpected PGP packet 1: "++(words (show p) >>= take 1)
1155 update _ = error $ "Unexpected PGP packet 2: "++(words (show p) >>= take 1)
1156
1157 mergeit _ (_,(_,_,p)) = error $ "Unexpected PGP packet 3: "++whatP p
1158
1159 mergeSubkey :: Int -> Packet -> Maybe SubKey -> Maybe SubKey
1160 mergeSubkey n p Nothing = Just $ SubKey (asMapped n p) []
1161 mergeSubkey n p (Just (SubKey key sigs)) = Just $
1162 SubKey ((asMapped n (minimumBy subcomp [packet key,p]))
1163 { locations = Map.insert filename (origin p n) (locations key) })
1164 sigs
1165
1166 mergeUid :: Int ->(Packet,a) -> Maybe ([SigAndTrust],OriginMap) -> Maybe ([SigAndTrust],OriginMap)
1167 mergeUid n (UserIDPacket s,_) Nothing = Just ([],Map.singleton filename (origin MarkerPacket n))
1168 mergeUid n (UserIDPacket s,_) (Just (sigs,m)) = Just (sigs, Map.insert filename (origin MarkerPacket n) m)
1169 mergeUid n p _ = error $ "Unable to merge into UID record: " ++whatP p
1170
1171 whatP (a,_) = concat . take 1 . words . show $ a
1172
1173
1174 mergeSig :: Int -> (Packet,TrustMap) -> [SigAndTrust] -> [SigAndTrust]
1175 mergeSig n sig sigs =
1176 let (xs,ys) = break (isSameSig sig) sigs
1177 in if null ys
1178 then sigs++[first (asMapped n) sig]
1179 else let y:ys'=ys
1180 in xs ++ (mergeSameSig n sig y : ys')
1181
1182
1183 isSameSig (a,_) (MappedPacket {packet=b},_) | isSignaturePacket a && isSignaturePacket b =
1184 a { unhashed_subpackets=[] } == b { unhashed_subpackets = [] }
1185 isSameSig (a,_) (MappedPacket {packet=b},_) = a==b
1186
1187 mergeSameSig :: Int -> (Packet,TrustMap) -> (MappedPacket,TrustMap) -> (MappedPacket, TrustMap)
1188 mergeSameSig n (a,ta) (m@(MappedPacket{packet=b,locations=locs}),tb) | isSignaturePacket a && isSignaturePacket b =
1189 ( m { packet = (b { unhashed_subpackets =
1190 foldl mergeItem (unhashed_subpackets b) (unhashed_subpackets a) })
1191 , locations = Map.insert filename (origin a n) locs }
1192 , tb `Map.union` ta )
1193
1194 where
1195 -- TODO: when merging items, we should delete invalidated origins
1196 -- from the orgin map.
1197 mergeItem ys x = if x `elem` ys then ys else ys++[x]
1198
1199 mergeSameSig n a b = trace ("discarding dup "++show a) b
1200
1201 mergeUidSig n sig (Just (sigs,m)) = Just (mergeSig n sig sigs, m)
1202 mergeUidSig n sig Nothing = Just ([asSigAndTrust n sig],Map.empty)
1203
1204 mergeSubSig n sig (Just (SubKey key sigs)) = Just $ SubKey key (mergeSig n sig sigs)
1205 mergeSubSig n sig Nothing = error $
1206 "Unable to merge subkey signature: "++(words (show sig) >>= take 1)
1207
1208flattenKeys :: Bool -> KeyDB -> Message 1003flattenKeys :: Bool -> KeyDB -> Message
1209flattenKeys isPublic db = Message $ concatMap (map packet . flattenTop "" isPublic . snd) (prefilter . Map.assocs $ db) 1004flattenKeys isPublic db = Message $ concatMap (map packet . flattenTop "" isPublic . snd) (prefilter . Map.assocs $ db)
1210 where 1005 where