diff options
author | joe <joe@jerkface.net> | 2014-05-02 14:31:17 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-05-02 14:31:17 -0400 |
commit | 970665ceb98b969b040e9f5400705846d54f77ad (patch) | |
tree | 354c328a26448f8ebcfa29298a295bdcdc26be31 /KeyRing.hs | |
parent | a1e0ac16e1ab889fd4a015a0c6914f331f034799 (diff) |
Implemented kTransforms
Diffstat (limited to 'KeyRing.hs')
-rw-r--r-- | KeyRing.hs | 153 |
1 files changed, 146 insertions, 7 deletions
@@ -55,6 +55,9 @@ module KeyRing | |||
55 | , usageString | 55 | , usageString |
56 | , walletImportFormat | 56 | , walletImportFormat |
57 | , writePEM | 57 | , writePEM |
58 | , getBindings | ||
59 | , accBindings | ||
60 | , isSubkeySignature | ||
58 | ) where | 61 | ) where |
59 | 62 | ||
60 | import System.Environment | 63 | import System.Environment |
@@ -83,16 +86,18 @@ import Data.ASN1.BitArray ( BitArray(..), toBitArray ) | |||
83 | import Data.ASN1.Encoding ( encodeASN1, encodeASN1', decodeASN1, decodeASN1' ) | 86 | import Data.ASN1.Encoding ( encodeASN1, encodeASN1', decodeASN1, decodeASN1' ) |
84 | import Data.ASN1.BinaryEncoding ( DER(..) ) | 87 | import Data.ASN1.BinaryEncoding ( DER(..) ) |
85 | import Data.Time.Clock.POSIX ( getPOSIXTime, POSIXTime ) | 88 | import Data.Time.Clock.POSIX ( getPOSIXTime, POSIXTime ) |
89 | import Data.Bits ( Bits ) | ||
90 | import Data.Text.Encoding ( encodeUtf8 ) | ||
86 | import qualified Data.Map as Map | 91 | import qualified Data.Map as Map |
87 | import qualified Data.ByteString.Lazy as L ( unpack, pack, null, readFile, writeFile | 92 | import qualified Data.ByteString.Lazy as L ( unpack, pack, null, readFile, writeFile |
88 | , ByteString, toChunks, hGetContents, hPut, concat ) | 93 | , ByteString, toChunks, hGetContents, hPut, concat, fromChunks ) |
89 | import qualified Data.ByteString as S ( ByteString, unpack, splitAt, concat, cons, spanEnd, hGetContents, readFile) | 94 | import qualified Data.ByteString as S ( ByteString, unpack, splitAt, concat, cons, spanEnd, hGetContents, readFile) |
90 | import qualified Crypto.Types.PubKey.ECC as ECC | 95 | import qualified Crypto.Types.PubKey.ECC as ECC |
91 | import qualified Codec.Binary.Base32 as Base32 | 96 | import qualified Codec.Binary.Base32 as Base32 |
92 | import qualified Codec.Binary.Base64 as Base64 | 97 | import qualified Codec.Binary.Base64 as Base64 |
93 | import qualified Crypto.Hash.SHA1 as SHA1 | 98 | import qualified Crypto.Hash.SHA1 as SHA1 |
94 | import qualified Data.Text as T ( Text, unpack, pack, | 99 | import qualified Data.Text as T ( Text, unpack, pack, |
95 | strip, reverse, drop, break, dropAround ) | 100 | strip, reverse, drop, break, dropAround, length ) |
96 | import qualified System.Posix.Types as Posix | 101 | import qualified System.Posix.Types as Posix |
97 | import System.Posix.Files ( modificationTime, getFileStatus, getFdStatus | 102 | import System.Posix.Files ( modificationTime, getFileStatus, getFdStatus |
98 | , setFileCreationMask, setFileTimes ) | 103 | , setFileCreationMask, setFileTimes ) |
@@ -199,7 +204,7 @@ data StreamInfo = StreamInfo | |||
199 | , typ :: FileType | 204 | , typ :: FileType |
200 | , fill :: KeyFilter | 205 | , fill :: KeyFilter |
201 | , spill :: KeyFilter -- ^ Currently respected for PEMFile and KeyRingFile. | 206 | , spill :: KeyFilter -- ^ Currently respected for PEMFile and KeyRingFile. |
202 | -- TODO: WalletFile and Hosts | 207 | -- (TODO: WalletFile and Hosts) |
203 | -- Note that this is currently treated as a boolean | 208 | -- Note that this is currently treated as a boolean |
204 | -- flag. KF_None means the file is not spillable | 209 | -- flag. KF_None means the file is not spillable |
205 | -- and anything else means that it is. | 210 | -- and anything else means that it is. |
@@ -262,14 +267,14 @@ data PassphraseSpec = PassphraseSpec | |||
262 | } | 267 | } |
263 | 268 | ||
264 | data Transform = Autosign | 269 | data Transform = Autosign |
270 | deriving (Eq,Ord) | ||
265 | 271 | ||
266 | data KeyRingOperation = KeyRingOperation | 272 | data KeyRingOperation = KeyRingOperation |
267 | { kFiles :: Map.Map InputFile StreamInfo | 273 | { kFiles :: Map.Map InputFile StreamInfo |
268 | , kPassphrases :: [PassphraseSpec] | 274 | , kPassphrases :: [PassphraseSpec] |
269 | , kTransform :: [Transform] | 275 | , kTransform :: [Transform] |
270 | -- ^ TODO: this is currently ignored | ||
271 | , kManip :: KeyRingRuntime -> KeyData -> [PacketUpdate]--[KeyRingAddress PacketUpdate] | 276 | , kManip :: KeyRingRuntime -> KeyData -> [PacketUpdate]--[KeyRingAddress PacketUpdate] |
272 | -- ^ TODO: this should be obsoleted by kTransform | 277 | -- ^ TODO: this is deprecated in favor of kTransform (remove it) |
273 | , homeSpec :: Maybe String | 278 | , homeSpec :: Maybe String |
274 | } | 279 | } |
275 | 280 | ||
@@ -1725,10 +1730,11 @@ performManipulations :: | |||
1725 | -> KeyRingOperation | 1730 | -> KeyRingOperation |
1726 | -> KeyRingRuntime | 1731 | -> KeyRingRuntime |
1727 | -> Maybe MappedPacket | 1732 | -> Maybe MappedPacket |
1733 | -> (KeyRingRuntime -> KeyData -> [PacketUpdate]) | ||
1728 | -> IO (KikiCondition (KeyRingRuntime,[(FilePath,KikiReportAction)])) | 1734 | -> IO (KikiCondition (KeyRingRuntime,[(FilePath,KikiReportAction)])) |
1729 | performManipulations doDecrypt operation rt wk = do | 1735 | performManipulations doDecrypt operation rt wk manip = do |
1730 | let db = rtKeyDB rt | 1736 | let db = rtKeyDB rt |
1731 | performAll kd = foldM perform (KikiSuccess kd) $ kManip operation rt kd | 1737 | performAll kd = foldM perform (KikiSuccess kd) $ manip rt kd |
1732 | r <- Traversable.mapM performAll db | 1738 | r <- Traversable.mapM performAll db |
1733 | try (sequenceA r) $ \db -> do | 1739 | try (sequenceA r) $ \db -> do |
1734 | return $ KikiSuccess (rt { rtKeyDB = db },[]) | 1740 | return $ KikiSuccess (rt { rtKeyDB = db },[]) |
@@ -1849,6 +1855,138 @@ interpretManip kd (KeyRingAddress kk sk (InducerSignature ps)) = error "todo" | |||
1849 | interpretManip kd manip = return kd | 1855 | interpretManip kd manip = return kd |
1850 | -} | 1856 | -} |
1851 | 1857 | ||
1858 | combineTransforms :: KeyRingOperation -> KeyRingRuntime -> KeyData -> [PacketUpdate] | ||
1859 | combineTransforms operation rt kd = updates | ||
1860 | where | ||
1861 | updates = kManip operation rt kd | ||
1862 | ++ concatMap (\t -> resolveTransform t rt kd) sanitized | ||
1863 | sanitized = group (sort (kTransform operation)) >>= take 1 | ||
1864 | |||
1865 | isSubkeySignature (SubkeySignature {}) = True | ||
1866 | isSubkeySignature _ = False | ||
1867 | |||
1868 | -- Returned data is simmilar to getBindings but the Word8 codes | ||
1869 | -- are ORed together. | ||
1870 | accBindings :: | ||
1871 | Bits t => | ||
1872 | [(t, (Packet, Packet), [a], [a1], [a2])] | ||
1873 | -> [(t, (Packet, Packet), [a], [a1], [a2])] | ||
1874 | accBindings bs = as | ||
1875 | where | ||
1876 | gs = groupBy samePair . sortBy (comparing bindingPair) $ bs | ||
1877 | as = map (foldl1 combine) gs | ||
1878 | bindingPair (_,p,_,_,_) = pub2 p | ||
1879 | where | ||
1880 | pub2 (a,b) = (pub a, pub b) | ||
1881 | pub a = fingerprint_material a | ||
1882 | samePair a b = bindingPair a == bindingPair b | ||
1883 | combine (ac,p,akind,ahashed,aclaimaints) | ||
1884 | (bc,_,bkind,bhashed,bclaimaints) | ||
1885 | = (ac .|. bc,p,akind++bkind,ahashed++bhashed,aclaimaints++bclaimaints) | ||
1886 | |||
1887 | |||
1888 | |||
1889 | verifyBindings keys nonkeys = (top ++ filter isSubkeySignature embedded,othersigs) | ||
1890 | where | ||
1891 | verified = do | ||
1892 | sig <- signatures (Message nonkeys) | ||
1893 | let v = verify (Message keys) sig | ||
1894 | guard (not . null $ signatures_over v) | ||
1895 | return v | ||
1896 | (top,othersigs) = partition isSubkeySignature verified | ||
1897 | embedded = do | ||
1898 | sub <- top | ||
1899 | let sigover = signatures_over sub | ||
1900 | unhashed = sigover >>= unhashed_subpackets | ||
1901 | subsigs = mapMaybe backsig unhashed | ||
1902 | -- This should consist only of 0x19 values | ||
1903 | -- subtypes = map signature_type subsigs | ||
1904 | -- trace ("subtypes = "++show subtypes) (return ()) | ||
1905 | -- trace ("issuers: "++show (map signature_issuer subsigs)) (return ()) | ||
1906 | sig <- signatures (Message ([topkey sub,subkey sub]++subsigs)) | ||
1907 | let v = verify (Message [subkey sub]) sig | ||
1908 | guard (not . null $ signatures_over v) | ||
1909 | return v | ||
1910 | |||
1911 | smallpr k = drop 24 $ fingerprint k | ||
1912 | |||
1913 | disjoint_fp ks = {- concatMap group2 $ -} transpose grouped | ||
1914 | where | ||
1915 | grouped = groupBy samepr . sortBy (comparing smallpr) $ ks | ||
1916 | samepr a b = smallpr a == smallpr b | ||
1917 | |||
1918 | {- | ||
1919 | -- useful for testing | ||
1920 | group2 :: [a] -> [[a]] | ||
1921 | group2 (x:y:ys) = [x,y]:group2 ys | ||
1922 | group2 [x] = [[x]] | ||
1923 | group2 [] = [] | ||
1924 | -} | ||
1925 | |||
1926 | |||
1927 | getBindings :: | ||
1928 | [Packet] | ||
1929 | -> | ||
1930 | ( [([Packet],[SignatureOver])] -- ^ other signatures with key sets | ||
1931 | -- that were used for the verifications | ||
1932 | , [(Word8, | ||
1933 | (Packet, Packet), -- (topkey,subkey) | ||
1934 | [String], -- usage flags | ||
1935 | [SignatureSubpacket], -- hashed data | ||
1936 | [Packet])] -- ^ binding signatures | ||
1937 | ) | ||
1938 | getBindings pkts = (sigs,bindings) | ||
1939 | where | ||
1940 | (sigs,concat->bindings) = unzip $ do | ||
1941 | let (keys,_) = partition isKey pkts | ||
1942 | keys <- disjoint_fp keys | ||
1943 | let (bs,sigs) = verifyBindings keys pkts | ||
1944 | return . ((keys,sigs),) $ do | ||
1945 | b <- bs -- trace ("sigs = "++show (map (map signature_issuer . signatures_over) sigs)) bs | ||
1946 | i <- map signature_issuer (signatures_over b) | ||
1947 | i <- maybeToList i | ||
1948 | who <- maybeToList $ find_key fingerprint (Message keys) i | ||
1949 | let (code,claimants) = | ||
1950 | case () of | ||
1951 | _ | who == topkey b -> (1,[]) | ||
1952 | _ | who == subkey b -> (2,[]) | ||
1953 | _ -> (0,[who]) | ||
1954 | let hashed = signatures_over b >>= hashed_subpackets | ||
1955 | kind = guard (code==1) >> hashed >>= maybeToList . usage | ||
1956 | return (code,(topkey b,subkey b), kind, hashed,claimants) | ||
1957 | |||
1958 | resolveTransform Autosign rt kd@(KeyData k ksigs umap submap) = ops | ||
1959 | where | ||
1960 | ops = map (\u -> InducerSignature u []) us | ||
1961 | us = filter torStyle $ Map.keys umap | ||
1962 | torStyle str = and [ uid_topdomain parsed == "onion" | ||
1963 | , uid_realname parsed `elem` ["","Anonymous"] | ||
1964 | , uid_user parsed == "root" | ||
1965 | , fmap (match . fst) (lookup (packet k) torbindings) | ||
1966 | == Just True ] | ||
1967 | where parsed = parseUID str | ||
1968 | match = (==subdom) . take (fromIntegral len) | ||
1969 | subdom0 = L.fromChunks [encodeUtf8 (uid_subdomain parsed)] | ||
1970 | subdom = Char8.unpack subdom0 | ||
1971 | len = T.length (uid_subdomain parsed) | ||
1972 | torbindings = getTorKeys (map packet $ flattenTop "" True kd) | ||
1973 | getTorKeys pub = do | ||
1974 | xs <- groupBindings pub | ||
1975 | (_,(top,sub),us,_,_) <- xs | ||
1976 | guard ("tor" `elem` us) | ||
1977 | let torhash = fromMaybe "" $ derToBase32 <$> derRSA sub | ||
1978 | return (top,(torhash,sub)) | ||
1979 | |||
1980 | groupBindings pub = gs | ||
1981 | where (_,bindings) = getBindings pub | ||
1982 | bindings' = accBindings bindings | ||
1983 | code (c,(m,s),_,_,_) = (fingerprint_material m,-c) | ||
1984 | ownerkey (_,(a,_),_,_,_) = a | ||
1985 | sameMaster (ownerkey->a) (ownerkey->b) | ||
1986 | = fingerprint_material a==fingerprint_material b | ||
1987 | gs = groupBy sameMaster (sortBy (comparing code) bindings') | ||
1988 | |||
1989 | |||
1852 | runKeyRing :: KeyRingOperation -> IO (KikiResult KeyRingRuntime) | 1990 | runKeyRing :: KeyRingOperation -> IO (KikiResult KeyRingRuntime) |
1853 | runKeyRing operation = do | 1991 | runKeyRing operation = do |
1854 | homedir <- getHomeDir (homeSpec operation) | 1992 | homedir <- getHomeDir (homeSpec operation) |
@@ -1902,6 +2040,7 @@ runKeyRing operation = do | |||
1902 | operation | 2040 | operation |
1903 | rt | 2041 | rt |
1904 | wk | 2042 | wk |
2043 | (combineTransforms operation) | ||
1905 | try' r $ \(rt,report_manips) -> do | 2044 | try' r $ \(rt,report_manips) -> do |
1906 | 2045 | ||
1907 | r <- writeWalletKeys operation (rtKeyDB rt) (fmap packet wk) | 2046 | r <- writeWalletKeys operation (rtKeyDB rt) (fmap packet wk) |