summaryrefslogtreecommitdiff
path: root/kiki.hs
diff options
context:
space:
mode:
Diffstat (limited to 'kiki.hs')
-rw-r--r--kiki.hs213
1 files changed, 212 insertions, 1 deletions
diff --git a/kiki.hs b/kiki.hs
index 0ecfa1c..2433d4e 100644
--- a/kiki.hs
+++ b/kiki.hs
@@ -75,6 +75,8 @@ import DotLock
75-- import Codec.Crypto.ECC.Base -- hecc package 75-- import Codec.Crypto.ECC.Base -- hecc package
76import Text.Printf 76import Text.Printf
77import qualified CryptoCoins as CryptoCoins 77import qualified CryptoCoins as CryptoCoins
78import qualified Hosts
79import Network.Socket -- (SockAddr)
78 80
79 81
80-- instance Default S.ByteString where def = S.empty 82-- instance Default S.ByteString where def = S.empty
@@ -1188,6 +1190,7 @@ flattenTop fname ispub (KeyData key sigs uids subkeys) =
1188 ( flattenAllUids fname ispub uids 1190 ( flattenAllUids fname ispub uids
1189 ++ concatSort fname head (flattenSub fname ispub) (Map.elems subkeys)) 1191 ++ concatSort fname head (flattenSub fname ispub) (Map.elems subkeys))
1190 1192
1193flattenAllUids :: FilePath -> Bool -> Map.Map String ([SigAndTrust],OriginMap) -> [MappedPacket]
1191flattenAllUids fname ispub uids = 1194flattenAllUids fname ispub uids =
1192 concatSort fname head (flattenUid fname ispub) (Map.assocs uids) 1195 concatSort fname head (flattenUid fname ispub) (Map.assocs uids)
1193 1196
@@ -1936,6 +1939,140 @@ signature_time ov = case if null cs then ds else cs of
1936 creationTime (SignatureCreationTimePacket t) = [t] 1939 creationTime (SignatureCreationTimePacket t) = [t]
1937 creationTime _ = [] 1940 creationTime _ = []
1938 1941
1942-- We return into IO in case we want to make a signature here.
1943setHostnames :: (SockAddr -> Bool) -> Hosts.Hosts -> KeyData -> IO KeyData
1944setHostnames pred hosts kd@(KeyData topmp topsigs uids subs) =
1945 -- TODO: we are removing the origin from the UID OriginMap,
1946 -- when we should be removing origins from the locations
1947 -- field of the sig's MappedPacket records.
1948 -- Call getHostnames and compare to see if no-op.
1949 if not (pred addr) || names0 == names \\ onions
1950 then {- trace (unlines [ "setHostnames NO-OP: gpg: "++show (map Char8.unpack onions, map Char8.unpack names0)
1951 , " file: "++show (map Char8.unpack names)
1952 , " pred: "++show (pred addr)]) -}
1953 (return kd)
1954 else do
1955 -- We should be sure to remove origins so that the data is written
1956 -- (but only if something changed).
1957 -- Filter all hostnames present in uids
1958 -- Write notations into first uid
1959 {-
1960 trace (unlines [ "setHostnames ACTION: gpg: "++show (map Char8.unpack onions, map Char8.unpack names0)
1961 , " file: "++show (map Char8.unpack names) ]) $ do
1962 -}
1963 return $ KeyData topmp topsigs uids1 subs
1964 where
1965 topk = packet topmp
1966 addr = fingerdress topk
1967 names :: [Char8.ByteString]
1968 names = Hosts.namesForAddress addr hosts
1969 (_,(onions,names0)) = getHostnames kd
1970 notations = map (NotationDataPacket True "hostname@" . Char8.unpack) (names \\ onions)
1971 isName (NotationDataPacket True "hostname@" _) = True
1972 isName _ = False
1973 uids0 = fmap zapIfHasName uids
1974 fstuid = head $ do
1975 p <- map packet $ flattenAllUids "" True uids
1976 guard $ isUserID p
1977 return $ uidkey p
1978 uids1 = Map.adjust addnames fstuid uids0
1979 addnames (sigs,om) = (fmap f ss ++ ts, om ) -- XXX: removed om=Map.empty, preserve UserId origin
1980 where
1981 (ss,ts) = splitAt 1 sigs
1982 f (sig,tm) = if isSignaturePacket (packet sig) then (sig { packet = p', locations=Map.empty }, tm)
1983 else (sig, tm)
1984 where p' = (packet sig) { unhashed_subpackets=uh }
1985 uh = unhashed_subpackets (packet sig) ++ notations
1986 zapIfHasName (sigs,om) = if or bs then (sigs',om) -- XXX: removed om=Map.empty to preserve UserID origin
1987 else (sigs,om)
1988 where
1989 (bs, sigs') = unzip $ map unhash sigs
1990
1991 unhash (sig,tm) = ( not (null ns)
1992 , ( sig { packet = p', locations = Map.empty }
1993 , tm ) )
1994 where
1995 psig = packet sig
1996 p' = if isSignaturePacket psig then psig { unhashed_subpackets = ps }
1997 else psig
1998 uh = unhashed_subpackets $ psig
1999 (ns,ps) = partition isName uh
2000
2001socketFamily (SockAddrInet _ _) = AF_INET
2002socketFamily (SockAddrInet6 _ _ _ _) = AF_INET6
2003socketFamily (SockAddrUnix _) = AF_UNIX
2004
2005
2006hasFingerDress :: KeyDB -> SockAddr -> Bool
2007hasFingerDress db addr | socketFamily addr/=AF_INET6 = False
2008hasFingerDress db addr = pre=="fd" && isJust (selectPublicKey (KeyGrip g',Nothing) db)
2009 where
2010 (pre,g) = splitAt 2 $ filter (/=':') $ Hosts.inet_ntop addr
2011 g' = map toUpper g
2012
2013fingerdress :: Packet -> SockAddr
2014fingerdress topk = maybe zero id $ Hosts.inet_pton addr_str
2015 where
2016 zero = SockAddrInet 0 0
2017 addr_str = colons $ "fd" ++ (drop 10 $ map toLower $ fingerprint topk)
2018 colons (a:b:c:d:xs@(_:_)) = [a,b,c,d,':'] ++ colons xs
2019 colons xs = xs
2020
2021
2022{-
2023onionName :: KeyData -> (SockAddr,L.ByteString)
2024onionName kd = (addr,name)
2025 where
2026 (addr,(name:_,_)) = getHostnames kd
2027-}
2028
2029getHostnames :: KeyData -> (SockAddr, ([L.ByteString],[L.ByteString]))
2030getHostnames (KeyData topmp _ uids subs) = (addr,(onames,othernames))
2031 where
2032 othernames = do
2033 mp <- flattenAllUids "" True uids
2034 let p = packet mp
2035 guard $ isSignaturePacket p
2036 uh <- unhashed_subpackets p
2037 case uh of
2038 NotationDataPacket True "hostname@" v
2039 -> return $ Char8.pack v
2040 _ -> mzero
2041
2042 addr = fingerdress topk
2043 name = maybe "" id $ listToMaybe onames -- TODO: more than one tor key?
2044 topk = packet topmp
2045 torkeys = do
2046 SubKey k sigs <- Map.elems subs
2047 let subk = packet k
2048 let sigs' = do
2049 torsig <- filter (has_tag "tor") $ map (packet . fst) sigs
2050 sig <- (signatures $ Message [topk,subk,torsig])
2051 let v = verify (Message [topk]) sig
2052 -- Require parent's signature
2053 guard (not . null $ signatures_over v)
2054 let unhashed = unhashed_subpackets torsig
2055 subsigs = mapMaybe backsig unhashed
2056 -- This should consist only of 0x19 values
2057 -- subtypes = map signature_type subsigs
2058 sig' <- signatures . Message $ [topk,subk]++subsigs
2059 let v' = verify (Message [subk]) sig'
2060 -- Require subkey's signature
2061 guard . not . null $ signatures_over v'
2062 return torsig
2063 guard (not $ null sigs')
2064 return $ subk
2065 has_tag tag p = isSignaturePacket p
2066 && or [ tag `elem` mapMaybe usage (hashed_subpackets p)
2067 , tag `elem` map usageString (mapMaybe keyflags (hashed_subpackets p)) ]
2068 subkeyPacket (SubKey k _ ) = k
2069 onames :: [L.ByteString]
2070 onames = map ( (<> ".onion")
2071 . Char8.pack
2072 . take 16
2073 . torhash )
2074 torkeys
2075
1939kiki_usage = do 2076kiki_usage = do
1940 putStr . unlines $ 2077 putStr . unlines $
1941 ["kiki - a pgp key editing utility" 2078 ["kiki - a pgp key editing utility"
@@ -2047,7 +2184,10 @@ main = do
2047 , ("--show-wip",1) 2184 , ("--show-wip",1)
2048 , ("--help",0) 2185 , ("--help",0)
2049 ] 2186 ]
2050 argspec = map fst sargspec ++ ["--keyrings","--keypairs","--wallets"] 2187 argspec = map fst sargspec ++ ["--keyrings"
2188 ,"--keypairs"
2189 ,"--wallets"
2190 ,"--hosts"]
2051 -- "--bitcoin-keypairs" 2191 -- "--bitcoin-keypairs"
2052 -- Disabled. We shouldn't accept private key 2192 -- Disabled. We shouldn't accept private key
2053 -- data on the command line. 2193 -- data on the command line.
@@ -2211,8 +2351,79 @@ main = do
2211 -- return . snd $ Map.mapAccum (signTorIds stamp wkun keys) g use_db 2351 -- return . snd $ Map.mapAccum (signTorIds stamp wkun keys) g use_db
2212 Traversable.mapM (signTorIds wkun keys) use_db 2352 Traversable.mapM (signTorIds wkun keys) use_db
2213 ret_db <- return $ fmap (const use_db) ret_db 2353 ret_db <- return $ fmap (const use_db) ret_db
2354
2355 ret_db <- flip (maybe $ return ret_db) ret_db $ \db -> do
2356 let hns = maybe [] id $ Map.lookup "--hosts" margs
2357 hostdbs0 <- mapM (fmap Hosts.decode . L.readFile) hns
2358
2359 let gpgnames = map getHostnames $ Map.elems db
2360 os = do
2361 (addr,(ns,_)) <- gpgnames
2362 n <- ns
2363 return (addr,n)
2364 setOnions hosts = foldl' (flip $ uncurry Hosts.assignName) hosts os
2365 -- we ensure .onion names are set properly
2366 hostdbs = map setOnions hostdbs0
2367 outgoing_names = do
2368 (addr,(_,gns)) <- gpgnames
2369 guard . not $ null gns
2370 guard $ all (null . Hosts.namesForAddress addr) hostdbs0
2371 return addr
2372 -- putStrLn $ "hostdbs = " ++ show hostdbs
2373
2374 -- 1. let U = union all the host dbs
2375 -- preserving whitespace and comments of the first
2376 let u0 = foldl' Hosts.plus Hosts.empty hostdbs
2377 -- we filter U to be only finger-dresses
2378 u1 = Hosts.filterAddrs (hasFingerDress db) u0
2379
2380 let nf h = map Char8.unpack $ Hosts.namesForAddress (fromJust $ Hosts.inet_pton "fdf4:ed98:29c7:6226:9bde:a5b4:d564:3321") h
2381 {-
2382 putStrLn $ "_ = {\n" ++ show (head hostdbs) ++ "}"
2383 putStrLn $ "--> " ++ show (nf (head hostdbs))
2384 putStrLn $ "u0 = {\n" ++ show u0 ++ "}"
2385 putStrLn $ "--> " ++ show (nf u0)
2386 putStrLn $ "u1 = {\n" ++ show u1 ++ "}"
2387 putStrLn $ "--> " ++ show (nf u1)
2388 -}
2389
2390 -- 2. replace gpg annotations with those in U
2391 -- forM use_db
2392 db' <- Traversable.mapM (setHostnames (\a -> not $ elem a outgoing_names) u1) db
2393
2394 -- 3. add hostnames from gpg for addresses not in U
2395 let u = foldl' f u1 ans
2396 ans = reverse $ do
2397 (addr,(_,ns)) <- gpgnames
2398 guard $ addr `elem` outgoing_names -- . null $ Hosts.namesForAddress addr u0
2399 n <- ns
2400 return (addr,n)
2401 f h (addr,n) = Hosts.assignNewName addr n h
2402
2403 {-
2404 putStrLn $ "u = {\n" ++ show u ++ "}"
2405 putStrLn $ "--> " ++ show (nf u)
2406 -}
2407
2408 -- 4. for each host db H, union H with U and write it out as H'
2409 -- only if there is a non-empty diff
2410 forM_ (zip hns $ zip hostdbs0 hostdbs) $ \(fname,(h0,h1)) -> do
2411 let h = h1 `Hosts.plus` u
2412 d = Hosts.diff h0 h
2413 fnamecolon = Char8.pack fname <> ": "
2414 {-
2415 putStrLn $ "h = {\n" ++ show h ++ "}"
2416 putStrLn $ "--> " ++ show (nf h)
2417 -}
2418 Char8.hPutStrLn stderr $ Char8.unlines (map (fnamecolon <>) d)
2419 when (not $ null d) $ L.writeFile fname $ Hosts.encode h
2420 return ()
2421
2422 return (Just db')
2214 2423
2215 flip (maybe $ return ()) ret_db . const $ do 2424 flip (maybe $ return ()) ret_db . const $ do
2425
2426
2216 -- On last pass, interpret --show-* commands. 2427 -- On last pass, interpret --show-* commands.
2217 let shspec = Map.fromList [("--show-wk", const $ show_wk secfile grip) 2428 let shspec = Map.fromList [("--show-wk", const $ show_wk secfile grip)
2218 ,("--show-all",const $ show_all) 2429 ,("--show-all",const $ show_all)