assistant: When generating a gpg secret key, avoid hardcoding the key algorithm and size
This aims to future-proof gpg key generation. OpenPGP is in flux with a conflict over standards ongoing. It seems not unlikely that different systems will have different gpg commands that support different algorithms. This also simplifies the code by using the --quick-gen-key interface rather than the experimental batch interface. It seems less likely that --quick-gen-key will break than an experimental interface (whose documentation I can no longer find). --quick-gen-key is supported since gpg 2.1.0 (2014). Sponsored-by: Graham Spencer on Patreon
This commit is contained in:
parent
d37dbd62b8
commit
de6a297d36
4 changed files with 21 additions and 39 deletions
|
@ -54,7 +54,7 @@ withNewSecretKey :: (KeyId -> Handler Html) -> Handler Html
|
||||||
withNewSecretKey use = do
|
withNewSecretKey use = do
|
||||||
cmd <- liftAnnex $ gpgCmd <$> Annex.getGitConfig
|
cmd <- liftAnnex $ gpgCmd <$> Annex.getGitConfig
|
||||||
userid <- liftIO $ newUserId cmd
|
userid <- liftIO $ newUserId cmd
|
||||||
liftIO $ genSecretKey cmd RSA "" userid maxRecommendedKeySize
|
liftIO $ genSecretKey cmd "" userid
|
||||||
results <- M.keys . M.filter (== userid) <$> liftIO (secretKeys cmd)
|
results <- M.keys . M.filter (== userid) <$> liftIO (secretKeys cmd)
|
||||||
case results of
|
case results of
|
||||||
[] -> giveup "Failed to generate gpg key!"
|
[] -> giveup "Failed to generate gpg key!"
|
||||||
|
|
|
@ -2,6 +2,8 @@ git-annex (10.20231228) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
* info: Added "annex sizes of repositories" table to the overall display.
|
* info: Added "annex sizes of repositories" table to the overall display.
|
||||||
* import: Sped up import from special remotes.
|
* import: Sped up import from special remotes.
|
||||||
|
* assistant: When generating a gpg secret key, avoid hardcoding the
|
||||||
|
key algorithm and size.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Fri, 29 Dec 2023 11:52:06 -0400
|
-- Joey Hess <id@joeyh.name> Fri, 29 Dec 2023 11:52:06 -0400
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,6 @@ module Utility.Gpg (
|
||||||
findPubKeys,
|
findPubKeys,
|
||||||
UserId,
|
UserId,
|
||||||
secretKeys,
|
secretKeys,
|
||||||
KeyType(..),
|
|
||||||
maxRecommendedKeySize,
|
|
||||||
genSecretKey,
|
genSecretKey,
|
||||||
genRandom,
|
genRandom,
|
||||||
testKeyId,
|
testKeyId,
|
||||||
|
@ -60,6 +58,8 @@ newtype KeyIds = KeyIds { keyIds :: [KeyId] }
|
||||||
|
|
||||||
newtype GpgCmd = GpgCmd { unGpgCmd :: String }
|
newtype GpgCmd = GpgCmd { unGpgCmd :: String }
|
||||||
|
|
||||||
|
type Passphrase = B.ByteString
|
||||||
|
|
||||||
{- Get gpg command to use, Just what's specified or, if a specific gpg
|
{- Get gpg command to use, Just what's specified or, if a specific gpg
|
||||||
- command was found at configure time, use it, or otherwise, "gpg". -}
|
- command was found at configure time, use it, or otherwise, "gpg". -}
|
||||||
mkGpgCmd :: Maybe FilePath -> GpgCmd
|
mkGpgCmd :: Maybe FilePath -> GpgCmd
|
||||||
|
@ -157,7 +157,7 @@ pipeStrict' (GpgCmd cmd) params environ input = do
|
||||||
- the passphrase.
|
- the passphrase.
|
||||||
-
|
-
|
||||||
- Note that the reader must fully consume gpg's input before returning. -}
|
- Note that the reader must fully consume gpg's input before returning. -}
|
||||||
feedRead :: (MonadIO m, MonadMask m) => GpgCmd -> [CommandParam] -> B.ByteString -> (Handle -> IO ()) -> (Handle -> m a) -> m a
|
feedRead :: (MonadIO m, MonadMask m) => GpgCmd -> [CommandParam] -> Passphrase -> (Handle -> IO ()) -> (Handle -> m a) -> m a
|
||||||
feedRead cmd params passphrase feeder reader = do
|
feedRead cmd params passphrase feeder reader = do
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
let setup = liftIO $ do
|
let setup = liftIO $ do
|
||||||
|
@ -260,49 +260,29 @@ secretKeys cmd = catchDefaultIO M.empty makemap
|
||||||
extract c k (_:rest) =
|
extract c k (_:rest) =
|
||||||
extract c k rest
|
extract c k rest
|
||||||
|
|
||||||
type Passphrase = String
|
|
||||||
type Size = Int
|
|
||||||
data KeyType = Algo Int | DSA | RSA
|
|
||||||
|
|
||||||
{- The maximum key size that gpg currently offers in its UI when
|
|
||||||
- making keys. -}
|
|
||||||
maxRecommendedKeySize :: Size
|
|
||||||
maxRecommendedKeySize = 4096
|
|
||||||
|
|
||||||
{- Generates a secret key using the experimental batch mode.
|
{- Generates a secret key using the experimental batch mode.
|
||||||
- The key is added to the secret key ring.
|
- The key is added to the secret key ring.
|
||||||
- Can take a very long time, depending on system entropy levels.
|
- Can take a very long time, depending on system entropy levels.
|
||||||
-}
|
-}
|
||||||
genSecretKey :: GpgCmd -> KeyType -> Passphrase -> UserId -> Size -> IO ()
|
genSecretKey :: GpgCmd -> Passphrase -> UserId -> IO ()
|
||||||
genSecretKey (GpgCmd cmd) keytype passphrase userid keysize =
|
genSecretKey gpgcmd passphrase userid =
|
||||||
let p = (proc cmd params)
|
feedRead gpgcmd params passphrase feeder reader
|
||||||
{ std_in = CreatePipe }
|
|
||||||
in withCreateProcess p (go p)
|
|
||||||
where
|
where
|
||||||
params = ["--batch", "--gen-key"]
|
params =
|
||||||
|
[ Param "--batch"
|
||||||
go p (Just h) _ _ pid = do
|
, Param "--quick-gen-key"
|
||||||
hPutStr h $ unlines $ catMaybes
|
, Param userid
|
||||||
[ Just $ "Key-Type: " ++
|
, Param "default" -- algo
|
||||||
case keytype of
|
, Param "default" -- usage
|
||||||
DSA -> "DSA"
|
, Param "never" -- expire
|
||||||
RSA -> "RSA"
|
]
|
||||||
Algo n -> show n
|
feeder = hClose
|
||||||
, Just $ "Key-Length: " ++ show keysize
|
reader = void . hGetContents
|
||||||
, Just $ "Name-Real: " ++ userid
|
|
||||||
, Just "Expire-Date: 0"
|
|
||||||
, if null passphrase
|
|
||||||
then Nothing
|
|
||||||
else Just $ "Passphrase: " ++ passphrase
|
|
||||||
]
|
|
||||||
hClose h
|
|
||||||
forceSuccessProcess p pid
|
|
||||||
go _ _ _ _ _ = error "internal"
|
|
||||||
|
|
||||||
{- Creates a block of high-quality random data suitable to use as a cipher.
|
{- Creates a block of high-quality random data suitable to use as a cipher.
|
||||||
- It is armored, to avoid newlines, since gpg only reads ciphers up to the
|
- It is armored, to avoid newlines, since gpg only reads ciphers up to the
|
||||||
- first newline. -}
|
- first newline. -}
|
||||||
genRandom :: GpgCmd -> Bool -> Size -> IO B.ByteString
|
genRandom :: GpgCmd -> Bool -> Int -> IO B.ByteString
|
||||||
genRandom cmd highQuality size = do
|
genRandom cmd highQuality size = do
|
||||||
s <- readStrict cmd params
|
s <- readStrict cmd params
|
||||||
checksize s
|
checksize s
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div .modal-header>
|
<div .modal-header>
|
||||||
<h3>
|
<h3>
|
||||||
<img src="@{StaticR activityicon_gif}" alt=""> #
|
<img src="@{StaticR activityicon_gif}" alt=""> #
|
||||||
Generating a #{maxRecommendedKeySize} bit GnuPg key.
|
Generating a GnuPg key.
|
||||||
<div .modal-body>
|
<div .modal-body>
|
||||||
<p>
|
<p>
|
||||||
Generating a GnuPg key can take a long time. To speed up the process, #
|
Generating a GnuPg key can take a long time. To speed up the process, #
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue