summaryrefslogtreecommitdiff
path: root/lib/KeyRing/BuildKeyDB.hs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/KeyRing/BuildKeyDB.hs')
-rw-r--r--lib/KeyRing/BuildKeyDB.hs91
1 files changed, 50 insertions, 41 deletions
diff --git a/lib/KeyRing/BuildKeyDB.hs b/lib/KeyRing/BuildKeyDB.hs
index 57647b0..c2b2703 100644
--- a/lib/KeyRing/BuildKeyDB.hs
+++ b/lib/KeyRing/BuildKeyDB.hs
@@ -79,6 +79,9 @@ import GnuPGAgent
79import ByteStringUtil 79import ByteStringUtil
80import Text.XXD 80import Text.XXD
81 81
82preferredPGPVersion :: KeyRingOperation -> Word8
83preferredPGPVersion _ = 4 -- TODO: v5
84
82newtype IPsToWriteToHostsFile = IPsToWriteToHostsFile [SockAddr] 85newtype IPsToWriteToHostsFile = IPsToWriteToHostsFile [SockAddr]
83-- | buildKeyDB 86-- | buildKeyDB
84-- 87--
@@ -122,7 +125,7 @@ buildKeyDB ctx grip0 keyring = do
122 _ -> AutoAccess 125 _ -> AutoAccess
123 acc -> acc 126 acc -> acc
124 127
125 readw wk n = fmap (n,) (readPacketsFromWallet wk n) 128 readw wk n = fmap (n,) (readPacketsFromWallet (preferredPGPVersion keyring) wk n)
126 129
127 -- KeyRings (todo: KikiCondition reporting?) 130 -- KeyRings (todo: KikiCondition reporting?)
128 (spilled,mwk,grip,accs,keyqs,unspilled) <- do 131 (spilled,mwk,grip,accs,keyqs,unspilled) <- do
@@ -232,7 +235,7 @@ buildKeyDB ctx grip0 keyring = do
232 imports <- filterM (\case (ArgFile n,_,_,_,_) -> doesFileExist n 235 imports <- filterM (\case (ArgFile n,_,_,_,_) -> doesFileExist n
233 _ -> return True) 236 _ -> return True)
234 pems 237 pems
235 db <- foldM (importSecretKey transcode) (KikiSuccess (db,[])) imports 238 db <- foldM (importSecretKey transcode (preferredPGPVersion keyring)) (KikiSuccess (db,[])) imports
236 try db $ \(db,reportPEMs) -> do 239 try db $ \(db,reportPEMs) -> do
237 240
238 -- generate keys 241 -- generate keys
@@ -240,7 +243,7 @@ buildKeyDB ctx grip0 keyring = do
240 where g (Generate _ params,v) = Just (params,v) 243 where g (Generate _ params,v) = Just (params,v)
241 g _ = Nothing 244 g _ = Nothing
242 245
243 db <- generateInternals transcode mwk db gens 246 db <- generateInternals transcode (preferredPGPVersion keyring) mwk db gens
244 try db $ \(db,reportGens) -> do 247 try db $ \(db,reportGens) -> do
245 248
246 r <- mergeHostFiles keyring db ctx 249 r <- mergeHostFiles keyring db ctx
@@ -258,7 +261,7 @@ decodePacketList :: L.ByteString -> [Packet]
258decodePacketList some = 261decodePacketList some =
259 case decodeOrFail some of 262 case decodeOrFail some of
260 Right (more,_,msg ) -> msg : decodePacketList more 263 Right (more,_,msg ) -> msg : decodePacketList more
261 Left (_,_,_) -> [] 264 Left (_,_,er) -> {- trace ("decodePacketList: " ++ er) -} []
262 265
263readPacketsFromFile :: InputFileContext -> InputFile -> IO (PacketsCodec, Message) 266readPacketsFromFile :: InputFileContext -> InputFile -> IO (PacketsCodec, Message)
264readPacketsFromFile ctx fname = do 267readPacketsFromFile ctx fname = do
@@ -274,14 +277,15 @@ readPacketsFromFile ctx fname = do
274 else tryAscii 277 else tryAscii
275 278
276readPacketsFromWallet :: 279readPacketsFromWallet ::
277 Maybe Packet 280 Word8
281 -> Maybe Packet
278 -> InputFile 282 -> InputFile
279 -> IO [(Packet,Packet,(Packet,Map.Map FilePath Packet))] 283 -> IO [(Packet,Packet,(Packet,Map.Map FilePath Packet))]
280readPacketsFromWallet wk fname = do 284readPacketsFromWallet pgpver wk fname = do
281 let ctx = InputFileContext "" "" 285 let ctx = InputFileContext "" ""
282 timestamp <- getInputFileTime ctx fname 286 timestamp <- getInputFileTime ctx fname
283 input <- readInputFileL ctx fname 287 input <- readInputFileL ctx fname
284 let (ks,_) = slurpWIPKeys timestamp input 288 let (ks,_) = slurpWIPKeys pgpver timestamp input
285 {- 289 {-
286 unless (null ks) $ do 290 unless (null ks) $ do
287 -- decrypt wk 291 -- decrypt wk
@@ -498,13 +502,15 @@ filterMatches spec ks = filter (matchSpec spec . snd) ks
498 502
499importSecretKey :: 503importSecretKey ::
500 (PacketTranscoder) 504 (PacketTranscoder)
505 -> Word8
501 -> KikiCondition 506 -> KikiCondition
502 (KeyDB, [(FilePath, KikiReportAction)]) 507 (KeyDB, [(FilePath, KikiReportAction)])
503 -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t) 508 -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t)
504 -> IO (KikiCondition (KeyDB, [(FilePath, KikiReportAction)])) 509 -> IO (KikiCondition (KeyDB, [(FilePath, KikiReportAction)]))
505importSecretKey transcode db' tup = do 510importSecretKey transcode pgpver db' tup = do
506 try db' $ \(db',report0) -> do 511 try db' $ \(db',report0) -> do
507 r <- doImport transcode 512 r <- doImport transcode
513 pgpver
508 db' 514 db'
509 tup 515 tup
510 try r $ \(db'',report) -> do 516 try r $ \(db'',report) -> do
@@ -512,18 +518,19 @@ importSecretKey transcode db' tup = do
512 518
513generateInternals :: 519generateInternals ::
514 PacketTranscoder 520 PacketTranscoder
521 -> Word8
515 -> Maybe MappedPacket 522 -> Maybe MappedPacket
516 -> KeyDB 523 -> KeyDB
517 -> [(GenerateKeyParams,StreamInfo)] 524 -> [(GenerateKeyParams,StreamInfo)]
518 -> IO (KikiCondition (KeyDB, [(FilePath, KikiReportAction)])) 525 -> IO (KikiCondition (KeyDB, [(FilePath, KikiReportAction)]))
519generateInternals transcode mwk db gens = do 526generateInternals transcode pgpver mwk db gens = do
520 case mwk of 527 case mwk of
521 Nothing -> return $ KikiSuccess (db,[]) 528 Nothing -> return $ KikiSuccess (db,[])
522 Just mpkt -> do 529 Just mpkt -> do
523 let kk = keykey (packet mpkt) 530 let kk = keykey (packet mpkt)
524 transmuteAt (go kk) kk db 531 transmuteAt (go kk) kk db
525 where 532 where
526 go kk (Just kd0) = foldM (generateSubkey transcode) (KikiSuccess (kd0,[])) gens 533 go kk (Just kd0) = foldM (generateSubkey transcode pgpver) (KikiSuccess (kd0,[])) gens
527 go kk Nothing = error "generateInternals: Key not found." 534 go kk Nothing = error "generateInternals: Key not found."
528 535
529mergeHostFiles :: KeyRingOperation -> KeyDB -> InputFileContext 536mergeHostFiles :: KeyRingOperation -> KeyDB -> InputFileContext
@@ -608,16 +615,16 @@ getInputFileTime ctx (resolveInputFile ctx -> [fname]) = do
608getInputFileTime ctx arg = error $ "getInputFileTime: Invalid argument: " ++ show arg 615getInputFileTime ctx arg = error $ "getInputFileTime: Invalid argument: " ++ show arg
609 616
610 617
611slurpWIPKeys :: Posix.EpochTime -> L.ByteString -> ( [(Word8,Packet)], [L.ByteString]) 618slurpWIPKeys :: Word8 -> Posix.EpochTime -> L.ByteString -> ( [(Word8,Packet)], [L.ByteString])
612slurpWIPKeys stamp "" = ([],[]) 619slurpWIPKeys pgpver stamp "" = ([],[])
613slurpWIPKeys stamp cs = 620slurpWIPKeys pgpver stamp cs =
614 let (b58,xs) = Char8.span (`elem` base58chars) cs 621 let (b58,xs) = Char8.span (`elem` base58chars) cs
615 mb = decode_btc_key stamp (Char8.unpack b58) 622 mb = decode_btc_key pgpver stamp (Char8.unpack b58)
616 in if L.null b58 623 in if L.null b58
617 then let (ys,xs') = Char8.break (`elem` base58chars) cs 624 then let (ys,xs') = Char8.break (`elem` base58chars) cs
618 (ks,js) = slurpWIPKeys stamp xs' 625 (ks,js) = slurpWIPKeys pgpver stamp xs'
619 in (ks,ys:js) 626 in (ks,ys:js)
620 else let (ks,js) = slurpWIPKeys stamp xs 627 else let (ks,js) = slurpWIPKeys pgpver stamp xs
621 in maybe (ks,b58:js) (\(net,Message [k])->((net,k):ks,js)) mb 628 in maybe (ks,b58:js) (\(net,Message [k])->((net,k):ks,js)) mb
622 629
623merge_ :: KeyDB -> FilePath -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))] 630merge_ :: KeyDB -> FilePath -> [(Packet,Packet,(Packet,Map.Map FilePath Packet))]
@@ -807,20 +814,21 @@ matchSpec (KeyUidMatch pat) (KeyData _ _ uids _) = not $ null us
807 814
808doImport 815doImport
809 :: PacketTranscoder 816 :: PacketTranscoder
817 -> Word8
810 -> KeyDB 818 -> KeyDB
811 -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t) 819 -> (InputFile, Maybe [Char], [KeyKey], StreamInfo, t)
812 -> IO (KikiCondition (KeyDB, [(FilePath,KikiReportAction)])) 820 -> IO (KikiCondition (KeyDB, [(FilePath,KikiReportAction)]))
813doImport transcode db (fname,subspec,ms,typ -> typ,_) = do 821doImport transcode pgpver db (fname,subspec,ms,typ -> typ,_) = do
814 flip (maybe $ return CannotImportMasterKey) 822 flip (maybe $ return CannotImportMasterKey)
815 subspec $ \tag -> do 823 subspec $ \tag -> do
816 (certs,keys) <- case typ of 824 (certs,keys) <- case typ of
817 PEMFile -> do 825 PEMFile -> do
818 ps <- readSecretPEMFile fname 826 ps <- readSecretPEMFile pgpver fname
819 let (mapMaybe spemCert -> certs,mapMaybe spemPacket-> keys) 827 let (mapMaybe spemCert -> certs,mapMaybe spemPacket-> keys)
820 = partition (isJust . spemCert) ps 828 = partition (isJust . spemCert) ps
821 return (certs,keys) 829 return (certs,keys)
822 DNSPresentation -> do 830 DNSPresentation -> do
823 p <- readSecretDNSFile fname 831 p <- readSecretDNSFile pgpver fname
824 return ([],[p]) 832 return ([],[p])
825 -- TODO Probably we need to move to a new design where signature 833 -- TODO Probably we need to move to a new design where signature
826 -- packets are merged into the database in one phase with null 834 -- packets are merged into the database in one phase with null
@@ -850,23 +858,24 @@ doImport transcode db (fname,subspec,ms,typ -> typ,_) = do
850 858
851generateSubkey :: 859generateSubkey ::
852 PacketTranscoder 860 PacketTranscoder
861 -> Word8
853 -> KikiCondition (KeyData, [(FilePath, KikiReportAction)]) -- db 862 -> KikiCondition (KeyData, [(FilePath, KikiReportAction)]) -- db
854 -> (GenerateKeyParams, StreamInfo) 863 -> (GenerateKeyParams, StreamInfo)
855 -> IO (KikiCondition (KeyData, [(FilePath, KikiReportAction)])) 864 -> IO (KikiCondition (KeyData, [(FilePath, KikiReportAction)]))
856generateSubkey transcode kd' (genparam,StreamInfo { spill = KF_Match tag }) = do 865generateSubkey transcode pgpver kd' (genparam,StreamInfo { spill = KF_Match tag }) = do
857 try kd' $ \(kd,report0) -> do 866 try kd' $ \(kd,report0) -> do
858 let subs = do 867 let subs = do
859 SubKey p sigs <- Map.elems $ keySubKeys kd 868 SubKey p sigs <- Map.elems $ keySubKeys kd
860 filter (has_tag tag) $ map (packet . fst) sigs 869 filter (has_tag tag) $ map (packet . fst) sigs
861 if null subs 870 if null subs
862 then do 871 then do
863 newkey <- generateKey genparam 872 newkey <- fmap (\k -> k { version = pgpver }) $ generateKey genparam
864 kdr <- insertSubkey transcode (keykey (keyPacket kd)) kd [mkUsage tag] (ArgFile "") newkey 873 kdr <- insertSubkey transcode (keykey (keyPacket kd)) kd [mkUsage tag] (ArgFile "") newkey
865 try kdr $ \(newkd,report) -> do 874 try kdr $ \(newkd,report) -> do
866 return $ KikiSuccess (newkd, report ++ [("", NewPacket $ showPacket newkey)]) 875 return $ KikiSuccess (newkd, report ++ [("", NewPacket $ showPacket newkey)])
867 else do 876 else do
868 return $ KikiSuccess (kd,report0) 877 return $ KikiSuccess (kd,report0)
869generateSubkey _ kd _ = return kd 878generateSubkey _ _ kd _ = return kd
870 879
871allNames :: Hostnames -> [Char8.ByteString] 880allNames :: Hostnames -> [Char8.ByteString]
872allNames (Hostnames _ ns os cs) = ns ++ os ++ (maybe [] return cs) 881allNames (Hostnames _ ns os cs) = ns ++ os ++ (maybe [] return cs)
@@ -979,8 +988,8 @@ setHostnames (IPsToWriteToHostsFile outgoing_names) hosts kd@(KeyData topmp tops
979 (ns,ps) = partition isName uh 988 (ns,ps) = partition isName uh
980 989
981decode_btc_key :: 990decode_btc_key ::
982 Enum timestamp => timestamp -> String -> Maybe (Word8, Message) 991 Enum timestamp => Word8 -> timestamp -> String -> Maybe (Word8, Message)
983decode_btc_key timestamp str = do 992decode_btc_key pgpver timestamp str = do
984 (network_id,us) <- base58_decode str 993 (network_id,us) <- base58_decode str
985 return . (network_id,) $ Message $ do 994 return . (network_id,) $ Message $ do
986 let d = foldl' (\a b->a*256+b) 0 (map fromIntegral us :: [Integer]) 995 let d = foldl' (\a b->a*256+b) 0 (map fromIntegral us :: [Integer])
@@ -1005,7 +1014,7 @@ decode_btc_key timestamp str = do
1005 ,"y' ="++show y' 1014 ,"y' ="++show y'
1006 ,"y''="++show y'']) -} 1015 ,"y''="++show y'']) -}
1007 SecretKeyPacket 1016 SecretKeyPacket
1008 { version = 4 1017 { version = pgpver
1009 , timestamp = toEnum (fromEnum timestamp) 1018 , timestamp = toEnum (fromEnum timestamp)
1010 , key_algorithm = ECDSA 1019 , key_algorithm = ECDSA
1011 , key = [ -- public fields... 1020 , key = [ -- public fields...
@@ -1159,8 +1168,8 @@ instance ASN1Object RSAPrivateKey where
1159 Left "fromASN1: RSAPrivateKey: unexpected format" 1168 Left "fromASN1: RSAPrivateKey: unexpected format"
1160 1169
1161 1170
1162readSecretPEMFile :: InputFile -> IO [SecretPEMData] 1171readSecretPEMFile :: Word8 -> InputFile -> IO [SecretPEMData]
1163readSecretPEMFile fname = do 1172readSecretPEMFile pgpver fname = do
1164 -- warn $ fname ++ ": reading ..." 1173 -- warn $ fname ++ ": reading ..."
1165 let ctx = InputFileContext "" "" 1174 let ctx = InputFileContext "" ""
1166 -- Note: The key's timestamp is included in it's fingerprint. 1175 -- Note: The key's timestamp is included in it's fingerprint.
@@ -1170,14 +1179,14 @@ readSecretPEMFile fname = do
1170 let edta = scanAndParse (fmap Left dateParser <> fmap Right (pkcs1 <> cert)) $ Char8.lines input 1179 let edta = scanAndParse (fmap Left dateParser <> fmap Right (pkcs1 <> cert)) $ Char8.lines input
1171 pkcs1 = fmap (parseRSAPrivateKey . pemBlob) 1180 pkcs1 = fmap (parseRSAPrivateKey . pemBlob)
1172 $ pemParser $ Just "RSA PRIVATE KEY" 1181 $ pemParser $ Just "RSA PRIVATE KEY"
1173 cert = fmap (fmap PEMCertificate . parseCertBlob False . pemBlob) 1182 cert = fmap (fmap PEMCertificate . parseCertBlob pgpver False . pemBlob)
1174 $ pemParser $ Just "CERTIFICATE" 1183 $ pemParser $ Just "CERTIFICATE"
1175 parseRSAPrivateKey dta = do 1184 parseRSAPrivateKey dta = do
1176 let e = decodeASN1 DER dta 1185 let e = decodeASN1 DER dta
1177 asn1 <- either (const $ mzero) return e 1186 asn1 <- either (const $ mzero) return e
1178 rsa <- either (const mzero) (return . fst) (fromASN1 asn1) 1187 rsa <- either (const mzero) (return . fst) (fromASN1 asn1)
1179 let _ = rsa :: RSAPrivateKey 1188 let _ = rsa :: RSAPrivateKey
1180 return $ PEMPacket $ rsaToPGP stamp rsa 1189 return $ PEMPacket $ rsaToPGP pgpver stamp rsa
1181 dta = catMaybes $ map snd $ scanl mergeDate (stamp,Nothing) edta 1190 dta = catMaybes $ map snd $ scanl mergeDate (stamp,Nothing) edta
1182 mergeDate (_,obj) (Left tm) = (fromTime tm,obj) 1191 mergeDate (_,obj) (Left tm) = (fromTime tm,obj)
1183 mergeDate (tm,_) (Right (Just (PEMPacket key))) = (tm,Just $ PEMPacket key') 1192 mergeDate (tm,_) (Right (Just (PEMPacket key))) = (tm,Just $ PEMPacket key')
@@ -1188,8 +1197,8 @@ readSecretPEMFile fname = do
1188 return $ dta 1197 return $ dta
1189 1198
1190 1199
1191readSecretDNSFile :: InputFile -> IO Packet 1200readSecretDNSFile :: Word8 -> InputFile -> IO Packet
1192readSecretDNSFile fname = do 1201readSecretDNSFile pgpver fname = do
1193 let ctx = InputFileContext "" "" 1202 let ctx = InputFileContext "" ""
1194 stamp <- getInputFileTime ctx fname 1203 stamp <- getInputFileTime ctx fname
1195 input <- readInputFileL ctx fname 1204 input <- readInputFileL ctx fname
@@ -1211,7 +1220,7 @@ readSecretDNSFile fname = do
1211 14 -> ECDSA -- P-384 SHA384 (RFC6605) 1220 14 -> ECDSA -- P-384 SHA384 (RFC6605)
1212 _ -> RSA 1221 _ -> RSA
1213 case alg of 1222 case alg of
1214 RSA -> return $ rsaToPGP stamp $ fromJust $ extractRSAKeyFields kvs 1223 RSA -> return $ rsaToPGP pgpver stamp $ fromJust $ extractRSAKeyFields kvs
1215 _ -> return $ error $ "readSecretDNSFile: " ++ show alg ++ " unimplemented." 1224 _ -> return $ error $ "readSecretDNSFile: " ++ show alg ++ " unimplemented."
1216 1225
1217spemPacket :: SecretPEMData -> Maybe Packet 1226spemPacket :: SecretPEMData -> Maybe Packet
@@ -1269,8 +1278,8 @@ socketFamily (SockAddrUnix _) = AF_UNIX
1269selectPublicKey :: (KeySpec,Maybe String) -> KeyDB -> Maybe Packet 1278selectPublicKey :: (KeySpec,Maybe String) -> KeyDB -> Maybe Packet
1270selectPublicKey (spec,mtag) db = selectKey0 True (spec,mtag) db 1279selectPublicKey (spec,mtag) db = selectKey0 True (spec,mtag) db
1271 1280
1272parseCertBlob :: Bool -> ByteString -> Maybe ParsedCert 1281parseCertBlob :: Word8 -> Bool -> ByteString -> Maybe ParsedCert
1273parseCertBlob comp bs = do 1282parseCertBlob pgpver comp bs = do
1274 asn1 <- either (const Nothing) Just 1283 asn1 <- either (const Nothing) Just
1275 $ decodeASN1 DER bs 1284 $ decodeASN1 DER bs
1276 let asn1' = drop 2 asn1 1285 let asn1' = drop 2 asn1
@@ -1292,7 +1301,7 @@ parseCertBlob comp bs = do
1292 then encode len <> GZip.compress (Char8.fromChunks [pre,post']) 1301 then encode len <> GZip.compress (Char8.fromChunks [pre,post'])
1293 else bs 1302 else bs
1294 return 1303 return
1295 ParsedCert { pcertKey = packetFromPublicRSAKey notBefore 1304 ParsedCert { pcertKey = packetFromPublicRSAKey pgpver notBefore
1296 (MPI $ RSA.public_n key) 1305 (MPI $ RSA.public_n key)
1297 (MPI $ RSA.public_e key) 1306 (MPI $ RSA.public_e key)
1298 , pcertTimestamp = notBefore 1307 , pcertTimestamp = notBefore
@@ -1301,9 +1310,9 @@ parseCertBlob comp bs = do
1301 } 1310 }
1302 _ -> Nothing 1311 _ -> Nothing
1303 1312
1304rsaToPGP :: TimeUtil.IsUTC a => a -> RSAPrivateKey -> Packet 1313rsaToPGP :: TimeUtil.IsUTC a => Word8 -> a -> RSAPrivateKey -> Packet
1305rsaToPGP stamp rsa = SecretKeyPacket 1314rsaToPGP pgpver stamp rsa = SecretKeyPacket
1306 { version = 4 1315 { version = pgpver
1307 , timestamp = fromTime stamp -- toEnum (fromEnum stamp) 1316 , timestamp = fromTime stamp -- toEnum (fromEnum stamp)
1308 , key_algorithm = RSA 1317 , key_algorithm = RSA
1309 , key = [ -- public fields... 1318 , key = [ -- public fields...
@@ -1364,9 +1373,9 @@ extractRSAKeyFields kvs = do
1364toStrict :: L.ByteString -> S.ByteString 1373toStrict :: L.ByteString -> S.ByteString
1365toStrict = foldr1 (<>) . L.toChunks 1374toStrict = foldr1 (<>) . L.toChunks
1366 1375
1367packetFromPublicRSAKey :: UTCTime -> MPI -> MPI -> Packet 1376packetFromPublicRSAKey :: Word8 -> UTCTime -> MPI -> MPI -> Packet
1368packetFromPublicRSAKey notBefore n e = 1377packetFromPublicRSAKey pgpver notBefore n e =
1369 PublicKeyPacket { version = 4 1378 PublicKeyPacket { version = pgpver
1370 , timestamp = round $ utcTimeToPOSIXSeconds notBefore 1379 , timestamp = round $ utcTimeToPOSIXSeconds notBefore
1371 , key_algorithm = RSA 1380 , key_algorithm = RSA
1372 , key = [('n',n),('e',e)] 1381 , key = [('n',n),('e',e)]