diff options
author | joe <joe@jerkface.net> | 2014-04-12 17:19:46 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-04-12 17:19:46 -0400 |
commit | a8da6f5843f3a5e6f7c975a746dea27adcf3907e (patch) | |
tree | e23abc66e741c336b9c70aca08f34af9bac4309e /kiki.hs | |
parent | 23dfd840a059877af0ff2538b2d46d85a0842ed9 (diff) |
moved merge function into KeyRing module
Diffstat (limited to 'kiki.hs')
-rw-r--r-- | kiki.hs | 205 |
1 files changed, 0 insertions, 205 deletions
@@ -328,22 +328,12 @@ writePEM typ dta = pem | |||
328 | 328 | ||
329 | -- 64 byte lines | 329 | -- 64 byte lines |
330 | 330 | ||
331 | isKey (PublicKeyPacket {}) = True | ||
332 | isKey (SecretKeyPacket {}) = True | ||
333 | isKey _ = False | ||
334 | |||
335 | isUserID (UserIDPacket {}) = True | ||
336 | isUserID _ = False | ||
337 | |||
338 | isEmbeddedSignature (EmbeddedSignaturePacket {}) = True | 331 | isEmbeddedSignature (EmbeddedSignaturePacket {}) = True |
339 | isEmbeddedSignature _ = False | 332 | isEmbeddedSignature _ = False |
340 | 333 | ||
341 | isCertificationSig (CertificationSignature {}) = True | 334 | isCertificationSig (CertificationSignature {}) = True |
342 | isCertificationSig _ = True | 335 | isCertificationSig _ = True |
343 | 336 | ||
344 | isTrust (TrustPacket {}) = True | ||
345 | isTrust _ = False | ||
346 | |||
347 | issuer (IssuerPacket issuer) = Just issuer | 337 | issuer (IssuerPacket issuer) = Just issuer |
348 | issuer _ = Nothing | 338 | issuer _ = Nothing |
349 | backsig (EmbeddedSignaturePacket s) = Just s | 339 | backsig (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 | ||
1011 | scanPackets :: FilePath -> [Packet] -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] | ||
1012 | scanPackets filename [] = [] | ||
1013 | scanPackets 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 | |||
1029 | data OriginFlags = OriginFlags { | ||
1030 | originallyPublic :: Bool, | ||
1031 | originalNum :: Int | ||
1032 | } | ||
1033 | deriving Show | ||
1034 | origin :: Packet -> Int -> OriginFlags | ||
1035 | origin p n = OriginFlags ispub n | ||
1036 | where | ||
1037 | ispub = case p of | ||
1038 | SecretKeyPacket {} -> False | ||
1039 | _ -> True | ||
1040 | |||
1041 | type OriginMap = Map.Map FilePath OriginFlags | ||
1042 | data MappedPacket = MappedPacket | ||
1043 | { packet :: Packet | ||
1044 | , usage_tag :: Maybe String | ||
1045 | , locations :: OriginMap | ||
1046 | } | ||
1047 | |||
1048 | mappedPacket filename p = MappedPacket | ||
1049 | { packet = p | ||
1050 | , usage_tag = Nothing | ||
1051 | , locations = Map.singleton filename (origin p (-1)) | ||
1052 | } | ||
1053 | |||
1054 | type TrustMap = Map.Map FilePath Packet | ||
1055 | type SigAndTrust = ( MappedPacket | ||
1056 | , TrustMap ) -- trust packets | ||
1057 | |||
1058 | type KeyKey = [Char8.ByteString] | ||
1059 | data SubKey = SubKey MappedPacket [SigAndTrust] | ||
1060 | data 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 | |||
1065 | type KeyDB = Map.Map KeyKey KeyData | ||
1066 | |||
1067 | torhash key = maybe "" id $ derToBase32 <$> derRSA key | 1001 | torhash key = maybe "" id $ derToBase32 <$> derRSA key |
1068 | 1002 | ||
1069 | keykey 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 | |||
1077 | uidkey (UserIDPacket str) = str | ||
1078 | |||
1079 | -- Compare master keys, LT is prefered for merging | ||
1080 | keycomp (SecretKeyPacket {}) (PublicKeyPacket {}) = LT | ||
1081 | keycomp (PublicKeyPacket {}) (SecretKeyPacket {}) = GT | ||
1082 | keycomp a b | keykey a==keykey b = EQ | ||
1083 | keycomp 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 | ||
1091 | subcomp (SecretKeyPacket {}) (PublicKeyPacket {}) = LT | ||
1092 | subcomp (PublicKeyPacket {}) (SecretKeyPacket {}) = GT | ||
1093 | subcomp a b | keykey a==keykey b = EQ | ||
1094 | subcomp a b = error $ unlines ["Unable to merge subs:" | ||
1095 | , fingerprint a | ||
1096 | , PP.ppShow a | ||
1097 | , fingerprint b | ||
1098 | , PP.ppShow b | ||
1099 | ] | ||
1100 | subcomp_m a b = subcomp (packet a) (packet b) | ||
1101 | |||
1102 | merge :: KeyDB -> FilePath -> Message -> KeyDB | ||
1103 | merge db filename (Message ps) = merge_ db filename qs | ||
1104 | where | ||
1105 | qs = scanPackets filename ps | ||
1106 | |||
1107 | merge_ :: KeyDB -> FilePath -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] | ||
1108 | -> KeyDB | ||
1109 | merge_ 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 | |||
1208 | flattenKeys :: Bool -> KeyDB -> Message | 1003 | flattenKeys :: Bool -> KeyDB -> Message |
1209 | flattenKeys isPublic db = Message $ concatMap (map packet . flattenTop "" isPublic . snd) (prefilter . Map.assocs $ db) | 1004 | flattenKeys isPublic db = Message $ concatMap (map packet . flattenTop "" isPublic . snd) (prefilter . Map.assocs $ db) |
1210 | where | 1005 | where |