mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-10-22 09:12:17 +00:00
chain of two certificates - offline (identity) and online; switch certificates to v3 (#238)
This commit is contained in:
1 parent
96cf4d288c
commit
0c866105d2
17 files changed
+179
-57
No files matched your search
+80
-23
@@ -22,7 +22,7 @@ import Simplex.Messaging.Server.Env.STM
|
||||
import Simplex.Messaging.Server.StoreLog (StoreLog, openReadStoreLog, storeLogFilePath)
|
||||
import Simplex.Messaging.Transport (ATransport (..), TLS, Transport (..), encodeFingerprint, loadFingerprint)
|
||||
import Simplex.Messaging.Transport.WebSockets (WS)
|
||||
import System.Directory (createDirectoryIfMissing, doesFileExist, removeFile)
|
||||
import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, removeDirectoryRecursive, removeFile)
|
||||
import System.Exit (exitFailure)
|
||||
import System.FilePath (combine)
|
||||
import System.IO (IOMode (..), hFlush, stdout)
|
||||
@@ -43,6 +43,7 @@ serverConfig =
|
||||
-- below parameters are set based on ini file /etc/opt/simplex/smp-server.ini
|
||||
transports = undefined,
|
||||
storeLog = undefined,
|
||||
caCertificateFile = undefined,
|
||||
serverPrivateKeyFile = undefined,
|
||||
serverCertificateFile = undefined
|
||||
}
|
||||
@@ -56,12 +57,19 @@ cfgDir = "/etc/opt/simplex"
|
||||
logDir :: FilePath
|
||||
logDir = "/var/opt/simplex"
|
||||
|
||||
-- TODO remove file paths from ini
|
||||
defaultStoreLogFile :: FilePath
|
||||
defaultStoreLogFile = combine logDir "smp-server-store.log"
|
||||
|
||||
iniFile :: FilePath
|
||||
iniFile = combine cfgDir "smp-server.ini"
|
||||
|
||||
caPrivateKeyFile :: FilePath
|
||||
caPrivateKeyFile = combine cfgDir "ca.key"
|
||||
|
||||
defaultCACertificateFile :: FilePath
|
||||
defaultCACertificateFile = combine cfgDir "ca.crt"
|
||||
|
||||
defaultPrivateKeyFile :: FilePath
|
||||
defaultPrivateKeyFile = combine cfgDir "server.key"
|
||||
|
||||
@@ -82,12 +90,14 @@ main = do
|
||||
putStrLn "Error: server is already initialized. Start it with `smp-server start` command"
|
||||
fingerprint <- loadSavedFingerprint
|
||||
printConfig cfg fingerprint
|
||||
checkCAPrivateKeyFile
|
||||
exitFailure
|
||||
Left _ -> do
|
||||
cfg <- initializeServer opts
|
||||
putStrLn "Server was initialized. Start it with `smp-server start` command"
|
||||
fingerprint <- loadSavedFingerprint
|
||||
printConfig cfg fingerprint
|
||||
warnCAPrivateKeyFile
|
||||
ServerStart ->
|
||||
runExceptT (getConfig opts) >>= \case
|
||||
Right cfg -> runServer cfg
|
||||
@@ -111,9 +121,9 @@ getConfig opts = do
|
||||
pure $ makeConfig ini storeLog
|
||||
|
||||
makeConfig :: IniOpts -> Maybe (StoreLog 'ReadMode) -> ServerConfig
|
||||
makeConfig IniOpts {serverPort, enableWebsockets, serverPrivateKeyFile, serverCertificateFile} storeLog =
|
||||
makeConfig IniOpts {serverPort, enableWebsockets, caCertificateFile, serverPrivateKeyFile, serverCertificateFile} storeLog =
|
||||
let transports = (serverPort, transport @TLS) : [("80", transport @WS) | enableWebsockets]
|
||||
in serverConfig {transports, storeLog, serverPrivateKeyFile, serverCertificateFile}
|
||||
in serverConfig {transports, storeLog, caCertificateFile, serverPrivateKeyFile, serverCertificateFile}
|
||||
|
||||
printConfig :: ServerConfig -> String -> IO ()
|
||||
printConfig ServerConfig {storeLog} fingerprint = do
|
||||
@@ -126,8 +136,8 @@ initializeServer :: ServerOpts -> IO ServerConfig
|
||||
initializeServer opts = do
|
||||
createDirectoryIfMissing True cfgDir
|
||||
ini <- createIni opts
|
||||
createKeyAndCertificate ini opts
|
||||
saveFingerprint $ serverCertificateFile (ini :: IniOpts)
|
||||
createX509 ini opts
|
||||
saveFingerprint $ caCertificateFile (ini :: IniOpts)
|
||||
storeLog <- openStoreLog opts ini
|
||||
pure $ makeConfig ini storeLog
|
||||
|
||||
@@ -136,38 +146,59 @@ runServer cfg = do
|
||||
savedFingerprint <- loadSavedFingerprint
|
||||
checkSavedFingerprint savedFingerprint
|
||||
printConfig cfg savedFingerprint
|
||||
checkCAPrivateKeyFile
|
||||
forM_ (transports cfg) $ \(port, ATransport t) ->
|
||||
putStrLn $ "listening on port " <> port <> " (" <> transportName t <> ")"
|
||||
runSMPServer cfg
|
||||
where
|
||||
checkSavedFingerprint :: String -> IO ()
|
||||
checkSavedFingerprint savedFingerprint = do
|
||||
fingerprint <- loadFingerprint $ serverCertificateFile (cfg :: ServerConfig)
|
||||
fingerprint <- loadFingerprint $ caCertificateFile (cfg :: ServerConfig)
|
||||
if savedFingerprint == (B.unpack . encodeFingerprint) fingerprint
|
||||
then putStrLn "stored fingerprint is valid"
|
||||
else putStrLn "stored fingerprint is invalid" >> exitFailure
|
||||
|
||||
checkCAPrivateKeyFile :: IO ()
|
||||
checkCAPrivateKeyFile =
|
||||
doesFileExist caPrivateKeyFile >>= (`when` (alert >> warnCAPrivateKeyFile))
|
||||
where
|
||||
alert = putStrLn $ "WARNING: " <> caPrivateKeyFile <> " is present on the server!"
|
||||
|
||||
warnCAPrivateKeyFile :: IO ()
|
||||
warnCAPrivateKeyFile =
|
||||
putStrLn $
|
||||
"----------\n\
|
||||
\We highly recommend to remove CA private key file from the server and keep it securely in place of your choosing.\n\
|
||||
\In case server's TLS credential is compromised you will be able to regenerate it using this key,\n\
|
||||
\thus keeping server's identity and allowing clients to keep established connections. Key location:\n"
|
||||
<> caPrivateKeyFile
|
||||
<> "\n----------"
|
||||
|
||||
deleteServer :: IO ()
|
||||
deleteServer = do
|
||||
ini <- runExceptT readIni
|
||||
deleteIfExists iniFile
|
||||
case ini of
|
||||
Right IniOpts {storeLogFile, serverPrivateKeyFile, serverCertificateFile} -> do
|
||||
-- TODO delete only cfgDir and logDir once file paths are removed from ini
|
||||
Right IniOpts {storeLogFile, caCertificateFile, serverPrivateKeyFile, serverCertificateFile} -> do
|
||||
deleteDirIfExists cfgDir
|
||||
deleteIfExists storeLogFile
|
||||
deleteIfExists caCertificateFile
|
||||
deleteIfExists serverPrivateKeyFile
|
||||
deleteIfExists serverCertificateFile
|
||||
deleteIfExists fingerprintFile
|
||||
Left _ -> do
|
||||
deleteDirIfExists cfgDir
|
||||
deleteIfExists defaultStoreLogFile
|
||||
deleteIfExists defaultCACertificateFile
|
||||
deleteIfExists defaultPrivateKeyFile
|
||||
deleteIfExists defaultCertificateFile
|
||||
deleteIfExists fingerprintFile
|
||||
|
||||
data IniOpts = IniOpts
|
||||
{ enableStoreLog :: Bool,
|
||||
storeLogFile :: FilePath,
|
||||
serverPort :: ServiceName,
|
||||
enableWebsockets :: Bool,
|
||||
caCertificateFile :: FilePath,
|
||||
serverPrivateKeyFile :: FilePath,
|
||||
serverCertificateFile :: FilePath
|
||||
}
|
||||
@@ -180,9 +211,10 @@ readIni = do
|
||||
storeLogFile = opt defaultStoreLogFile "STORE_LOG" "file" ini
|
||||
serverPort = opt defaultServerPort "TRANSPORT" "port" ini
|
||||
enableWebsockets = (== Right "on") $ lookupValue "TRANSPORT" "websockets" ini
|
||||
caCertificateFile = opt defaultCACertificateFile "TRANSPORT" "ca_certificate_file" ini
|
||||
serverPrivateKeyFile = opt defaultPrivateKeyFile "TRANSPORT" "private_key_file" ini
|
||||
serverCertificateFile = opt defaultCertificateFile "TRANSPORT" "certificate_file" ini
|
||||
pure IniOpts {enableStoreLog, storeLogFile, serverPort, enableWebsockets, serverPrivateKeyFile, serverCertificateFile}
|
||||
pure IniOpts {enableStoreLog, storeLogFile, serverPort, enableWebsockets, caCertificateFile, serverPrivateKeyFile, serverCertificateFile}
|
||||
where
|
||||
opt :: String -> Text -> Text -> Ini -> String
|
||||
opt def section key ini = either (const def) T.unpack $ lookupValue section key ini
|
||||
@@ -203,6 +235,9 @@ createIni ServerOpts {enableStoreLog} = do
|
||||
<> defaultStoreLogFile
|
||||
<> "\n\n\
|
||||
\[TRANSPORT]\n\n\
|
||||
\# ca_certificate_file: "
|
||||
<> defaultCACertificateFile
|
||||
<> "\n\
|
||||
\# private_key_file: "
|
||||
<> defaultPrivateKeyFile
|
||||
<> "\n\
|
||||
@@ -219,28 +254,47 @@ createIni ServerOpts {enableStoreLog} = do
|
||||
storeLogFile = defaultStoreLogFile,
|
||||
serverPort = defaultServerPort,
|
||||
enableWebsockets = True,
|
||||
caCertificateFile = defaultCACertificateFile,
|
||||
serverPrivateKeyFile = defaultPrivateKeyFile,
|
||||
serverCertificateFile = defaultCertificateFile
|
||||
}
|
||||
|
||||
-- To generate self-signed certificate:
|
||||
-- https://blog.pinterjann.is/ed25519-certificates.html
|
||||
|
||||
createKeyAndCertificate :: IniOpts -> ServerOpts -> IO ()
|
||||
createKeyAndCertificate IniOpts {serverPrivateKeyFile, serverCertificateFile} ServerOpts {pubkeyAlgorihtm} = do
|
||||
createX509 :: IniOpts -> ServerOpts -> IO ()
|
||||
createX509 IniOpts {caCertificateFile, serverPrivateKeyFile, serverCertificateFile} ServerOpts {pubkeyAlgorihtm} = do
|
||||
createOpensslConf
|
||||
-- CA certificate (identity/offline)
|
||||
run $ "openssl genpkey -algorithm " <> pubkeyAlgorihtm <> " -out " <> caPrivateKeyFile
|
||||
run $ "openssl req -new -x509 -days 999999 -config " <> opensslConfFile <> " -extensions v3_ca -key " <> caPrivateKeyFile <> " -out " <> caCertificateFile
|
||||
-- server certificate (online)
|
||||
run $ "openssl genpkey -algorithm " <> pubkeyAlgorihtm <> " -out " <> serverPrivateKeyFile
|
||||
run $ "openssl req -new -key " <> serverPrivateKeyFile <> " -subj \"/CN=localhost\" -out " <> csrPath
|
||||
run $ "openssl x509 -req -days 999999 -in " <> csrPath <> " -signkey " <> serverPrivateKeyFile <> " -out " <> serverCertificateFile
|
||||
run $ "rm " <> csrPath
|
||||
run $ "openssl req -new -config " <> opensslConfFile <> " -reqexts v3_req -key " <> serverPrivateKeyFile <> " -out " <> serverCsrFile
|
||||
run $ "openssl x509 -req -days 999999 -copy_extensions copy -in " <> serverCsrFile <> " -CA " <> caCertificateFile <> " -CAkey " <> caPrivateKeyFile <> " -out " <> serverCertificateFile
|
||||
where
|
||||
run :: String -> IO ()
|
||||
run cmd = void $ readCreateProcess (shell cmd) ""
|
||||
csrPath :: String
|
||||
csrPath = combine cfgDir "localhost.csr"
|
||||
opensslConfFile = combine cfgDir "openssl.cnf"
|
||||
serverCsrFile = combine cfgDir "server.csr"
|
||||
createOpensslConf :: IO ()
|
||||
createOpensslConf =
|
||||
-- TODO revise https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3, https://www.rfc-editor.org/rfc/rfc3279#section-2.3.5
|
||||
writeFile
|
||||
opensslConfFile
|
||||
"[req]\n\
|
||||
\distinguished_name = req_distinguished_name\n\
|
||||
\prompt = no\n\n\
|
||||
\[req_distinguished_name]\n\
|
||||
\CN = localhost\n\n\
|
||||
\[v3_ca]\n\
|
||||
\subjectKeyIdentifier = hash\n\
|
||||
\authorityKeyIdentifier = keyid:always\n\
|
||||
\basicConstraints = critical,CA:true\n\n\
|
||||
\[v3_req]\n\
|
||||
\basicConstraints = CA:FALSE\n\
|
||||
\keyUsage = digitalSignature, nonRepudiation, keyAgreement\n\
|
||||
\extendedKeyUsage = serverAuth\n"
|
||||
|
||||
saveFingerprint :: FilePath -> IO ()
|
||||
saveFingerprint serverCertificateFile = do
|
||||
fingerprint <- loadFingerprint serverCertificateFile
|
||||
saveFingerprint caCertificateFile = do
|
||||
fingerprint <- loadFingerprint caCertificateFile
|
||||
writeFile fingerprintFile $ (B.unpack . encodeFingerprint) fingerprint <> "\n"
|
||||
|
||||
loadSavedFingerprint :: IO String
|
||||
@@ -256,6 +310,9 @@ fileExists path = do
|
||||
deleteIfExists :: FilePath -> IO ()
|
||||
deleteIfExists path = doesFileExist path >>= (`when` removeFile path)
|
||||
|
||||
deleteDirIfExists :: FilePath -> IO ()
|
||||
deleteDirIfExists path = doesDirectoryExist path >>= (`when` removeDirectoryRecursive path)
|
||||
|
||||
confirm :: String -> IO ()
|
||||
confirm msg = do
|
||||
putStr $ msg <> " (y/N): "
|
||||
|
||||
@@ -105,13 +105,13 @@ runSMPAgent t cfg = do
|
||||
-- This function uses passed TMVar to signal when the server is ready to accept TCP requests (True)
|
||||
-- and when it is disconnected from the TCP socket once the server thread is killed (False).
|
||||
runSMPAgentBlocking :: (MonadRandom m, MonadUnliftIO m) => ATransport -> TMVar Bool -> AgentConfig -> m ()
|
||||
runSMPAgentBlocking (ATransport t) started cfg@AgentConfig {tcpPort, agentCertificateFile, agentPrivateKeyFile} = do
|
||||
runSMPAgentBlocking (ATransport t) started cfg@AgentConfig {tcpPort, caCertificateFile, agentCertificateFile, agentPrivateKeyFile} = do
|
||||
runReaderT (smpAgent t) =<< newSMPAgentEnv cfg
|
||||
where
|
||||
smpAgent :: forall c m'. (Transport c, MonadUnliftIO m', MonadReader Env m') => TProxy c -> m' ()
|
||||
smpAgent _ = do
|
||||
-- tlsServerParams not in env to avoid breaking functional api w/t key and certificate generation
|
||||
tlsServerParams <- liftIO $ loadTLSServerParams agentCertificateFile agentPrivateKeyFile
|
||||
tlsServerParams <- liftIO $ loadTLSServerParams caCertificateFile agentCertificateFile agentPrivateKeyFile
|
||||
runTransportServer started tcpPort tlsServerParams $ \(h :: c) -> do
|
||||
liftIO . putLn h $ "Welcome to SMP agent v" <> currentSMPVersionStr
|
||||
c <- getAgentClient
|
||||
|
||||
@@ -32,6 +32,7 @@ data AgentConfig = AgentConfig
|
||||
smpCfg :: SMPClientConfig,
|
||||
retryInterval :: RetryInterval,
|
||||
reconnectInterval :: RetryInterval,
|
||||
caCertificateFile :: FilePath,
|
||||
agentPrivateKeyFile :: FilePath,
|
||||
agentCertificateFile :: FilePath
|
||||
}
|
||||
@@ -63,7 +64,8 @@ defaultAgentConfig =
|
||||
increaseAfter = 10_000_000,
|
||||
maxInterval = 10_000_000
|
||||
},
|
||||
-- ! we do not generate these key and certificate
|
||||
-- ! we do not generate these
|
||||
caCertificateFile = "/etc/opt/simplex-agent/ca.crt",
|
||||
agentPrivateKeyFile = "/etc/opt/simplex-agent/agent.key",
|
||||
agentCertificateFile = "/etc/opt/simplex-agent/agent.crt"
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ data ServerConfig = ServerConfig
|
||||
msgIdBytes :: Int,
|
||||
storeLog :: Maybe (StoreLog 'ReadMode),
|
||||
blockSize :: Int,
|
||||
caCertificateFile :: FilePath,
|
||||
serverPrivateKeyFile :: FilePath,
|
||||
serverCertificateFile :: FilePath
|
||||
}
|
||||
@@ -92,13 +93,13 @@ newSubscription = do
|
||||
return Sub {subThread = NoSub, delivered}
|
||||
|
||||
newEnv :: forall m. (MonadUnliftIO m, MonadRandom m) => ServerConfig -> m Env
|
||||
newEnv config = do
|
||||
newEnv config@ServerConfig {caCertificateFile, serverCertificateFile, serverPrivateKeyFile} = do
|
||||
server <- atomically $ newServer (serverTbqSize config)
|
||||
queueStore <- atomically newQueueStore
|
||||
msgStore <- atomically newMsgStore
|
||||
idsDrg <- drgNew >>= newTVarIO
|
||||
s' <- restoreQueues queueStore `mapM` storeLog (config :: ServerConfig)
|
||||
tlsServerParams <- liftIO $ loadTLSServerParams (serverCertificateFile config) (serverPrivateKeyFile config)
|
||||
tlsServerParams <- liftIO $ loadTLSServerParams caCertificateFile serverCertificateFile serverPrivateKeyFile
|
||||
return Env {config, server, queueStore, msgStore, idsDrg, storeLog = s', tlsServerParams}
|
||||
where
|
||||
restoreQueues :: QueueStore -> StoreLog 'ReadMode -> m (StoreLog 'WriteMode)
|
||||
|
||||
@@ -213,13 +213,13 @@ startTCPClient host port clientParams = withSocketsDo $ resolve >>= tryOpen err
|
||||
ctx <- connectTLS clientParams sock
|
||||
getClientConnection ctx
|
||||
|
||||
loadTLSServerParams :: FilePath -> FilePath -> IO T.ServerParams
|
||||
loadTLSServerParams certificateFile privateKeyFile =
|
||||
loadTLSServerParams :: FilePath -> FilePath -> FilePath -> IO T.ServerParams
|
||||
loadTLSServerParams caCertificateFile certificateFile privateKeyFile =
|
||||
fromCredential <$> loadServerCredential
|
||||
where
|
||||
loadServerCredential :: IO T.Credential
|
||||
loadServerCredential =
|
||||
T.credentialLoadX509 certificateFile privateKeyFile >>= \case
|
||||
T.credentialLoadX509Chain certificateFile [caCertificateFile] privateKeyFile >>= \case
|
||||
Right credential -> pure credential
|
||||
Left _ -> putStrLn "invalid credential" >> exitFailure
|
||||
fromCredential :: T.Credential -> T.ServerParams
|
||||
@@ -288,8 +288,9 @@ mkTLSClientParams host port keyHash = do
|
||||
|
||||
validateCertificateChain :: Maybe C.KeyHash -> HostName -> ByteString -> X.CertificateChain -> IO [XV.FailedReason]
|
||||
validateCertificateChain _ _ _ (X.CertificateChain []) = pure [XV.EmptyChain]
|
||||
validateCertificateChain keyHash host port cc@(X.CertificateChain sc@[cert]) =
|
||||
let fp = XV.getFingerprint cert X.HashSHA256
|
||||
validateCertificateChain _ _ _ (X.CertificateChain [_]) = pure [XV.EmptyChain]
|
||||
validateCertificateChain keyHash host port cc@(X.CertificateChain sc@[_, caCert]) =
|
||||
let fp = XV.getFingerprint caCert X.HashSHA256
|
||||
in if maybe True (sameFingerprint fp) keyHash
|
||||
then x509validate
|
||||
else pure [XV.UnknownCA]
|
||||
@@ -299,11 +300,11 @@ validateCertificateChain keyHash host port cc@(X.CertificateChain sc@[cert]) =
|
||||
x509validate = XV.validate X.HashSHA256 hooks checks certStore cache serviceID cc
|
||||
where
|
||||
hooks = XV.defaultHooks
|
||||
checks = XV.defaultChecks {XV.checkLeafV3 = False} -- TODO create v3 certificates? https://stackoverflow.com/a/18242720
|
||||
checks = XV.defaultChecks
|
||||
certStore = XS.makeCertificateStore sc
|
||||
cache = XV.exceptionValidationCache [] -- we manually check fingerprint only of the offline certificate (TODO 2 certificates)
|
||||
cache = XV.exceptionValidationCache [] -- we manually check fingerprint only of the identity certificate (ca.crt)
|
||||
serviceID = (host, port)
|
||||
validateCertificateChain _ _ _ (X.CertificateChain (_ : _)) = pure [XV.AuthorityTooDeep]
|
||||
validateCertificateChain _ _ _ _ = pure [XV.AuthorityTooDeep]
|
||||
|
||||
supportedParameters :: T.Supported
|
||||
supportedParameters =
|
||||
|
||||
+1
-1
@@ -368,7 +368,7 @@ syntaxTests t = do
|
||||
-- TODO: ERROR no connection alias in the response (it does not generate it yet if not provided)
|
||||
-- TODO: add tests with defined connection alias
|
||||
it "using same server as in invitation" $
|
||||
("311", "a", "JOIN https://simpex.chat/invitation#/?smp=smp%3A%2F%2F" <> (U.encode . decodeLenient) "f80NoyPgNXR5n/fRVfmRTtkRps6/xDrQLmiuz9qFUJU=" <> "%40localhost%3A5001%2F3456-w%3D%3D%23&e2e=" <> urlEncode True samplePublicKey <> " 14\nbob's connInfo")
|
||||
("311", "a", "JOIN https://simpex.chat/invitation#/?smp=smp%3A%2F%2F" <> (U.encode . decodeLenient) "9VjLsOY5ZvB4hoglNdBzJFAUi/vP4GkZnJFahQOXV20=" <> "%40localhost%3A5001%2F3456-w%3D%3D%23&e2e=" <> urlEncode True samplePublicKey <> " 14\nbob's connInfo")
|
||||
>#> ("311", "a", "ERR SMP AUTH")
|
||||
describe "invalid" $ do
|
||||
-- TODO: JOIN is not merged yet - to be added
|
||||
|
||||
@@ -156,7 +156,7 @@ cfg :: AgentConfig
|
||||
cfg =
|
||||
defaultAgentConfig
|
||||
{ tcpPort = agentTestPort,
|
||||
smpServers = L.fromList ["localhost:5001#f80NoyPgNXR5n/fRVfmRTtkRps6/xDrQLmiuz9qFUJU="],
|
||||
smpServers = L.fromList ["localhost:5001#9VjLsOY5ZvB4hoglNdBzJFAUi/vP4GkZnJFahQOXV20="],
|
||||
tbqSize = 1,
|
||||
dbFile = testDB,
|
||||
smpCfg =
|
||||
@@ -166,8 +166,9 @@ cfg =
|
||||
tcpTimeout = 500_000
|
||||
},
|
||||
retryInterval = (retryInterval defaultAgentConfig) {initialInterval = 50_000},
|
||||
agentPrivateKeyFile = "tests/fixtures/example.key",
|
||||
agentCertificateFile = "tests/fixtures/example.crt"
|
||||
caCertificateFile = "tests/fixtures/ca.crt",
|
||||
agentPrivateKeyFile = "tests/fixtures/server.key",
|
||||
agentCertificateFile = "tests/fixtures/server.crt"
|
||||
}
|
||||
|
||||
withSmpAgentThreadOn_ :: (MonadUnliftIO m, MonadRandom m) => ATransport -> (ServiceName, ServiceName, String) -> m () -> (ThreadId -> m a) -> m a
|
||||
|
||||
+5
-4
@@ -38,13 +38,13 @@ testPort2 :: ServiceName
|
||||
testPort2 = "5002"
|
||||
|
||||
testKeyHashStr :: ByteString
|
||||
testKeyHashStr = "f80NoyPgNXR5n/fRVfmRTtkRps6/xDrQLmiuz9qFUJU="
|
||||
testKeyHashStr = "9VjLsOY5ZvB4hoglNdBzJFAUi/vP4GkZnJFahQOXV20="
|
||||
|
||||
testBlockSize :: Int
|
||||
testBlockSize = 16 * 1024 -- TODO move to Protocol
|
||||
|
||||
testKeyHash :: Maybe C.KeyHash
|
||||
testKeyHash = Just "f80NoyPgNXR5n/fRVfmRTtkRps6/xDrQLmiuz9qFUJU="
|
||||
testKeyHash = Just "9VjLsOY5ZvB4hoglNdBzJFAUi/vP4GkZnJFahQOXV20="
|
||||
|
||||
testStoreLogFile :: FilePath
|
||||
testStoreLogFile = "tests/tmp/smp-server-store.log"
|
||||
@@ -67,8 +67,9 @@ cfg =
|
||||
msgIdBytes = 24,
|
||||
storeLog = Nothing,
|
||||
blockSize = testBlockSize,
|
||||
serverPrivateKeyFile = "tests/fixtures/example.key",
|
||||
serverCertificateFile = "tests/fixtures/example.crt"
|
||||
caCertificateFile = "tests/fixtures/ca.crt",
|
||||
serverPrivateKeyFile = "tests/fixtures/server.key",
|
||||
serverCertificateFile = "tests/fixtures/server.crt"
|
||||
}
|
||||
|
||||
withSmpServerStoreLogOn :: (MonadUnliftIO m, MonadRandom m) => ATransport -> ServiceName -> (ThreadId -> m a) -> m a
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
server.csr
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
To generate fixtures:
|
||||
|
||||
(keep these instructions and *openssl.cnf* consistent with certificate generation on server)
|
||||
|
||||
```sh
|
||||
# CA certificate (identity/offline)
|
||||
openssl genpkey -algorithm ED448 -out ca.key
|
||||
openssl req -new -x509 -days 999999 -config openssl.cnf -extensions v3_ca -key ca.key -out ca.crt
|
||||
# server certificate (online)
|
||||
openssl genpkey -algorithm ED448 -out server.key
|
||||
openssl req -new -config openssl.cnf -reqexts v3_req -key server.key -out server.csr
|
||||
openssl x509 -req -days 999999 -copy_extensions copy -in server.csr -CA ca.crt -CAkey ca.key -out server.crt
|
||||
# to pretty-print
|
||||
openssl x509 -in ca.crt -text -noout
|
||||
openssl req -in server.csr -text -noout
|
||||
openssl x509 -in server.crt -text -noout
|
||||
```
|
||||
|
||||
To compute fingerprint for tests:
|
||||
|
||||
```sh
|
||||
stack ghci --ghci-options src/Simplex/Messaging/Transport.hs
|
||||
> fingerprint <- loadFingerprint "tests/fixtures/ca.crt"
|
||||
> encodeFingerprint fingerprint
|
||||
```
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBijCCAQqgAwIBAgIUf/txCk9PXE4nY2gQ/B/HG2sNzmswBQYDK2VxMBQxEjAQ
|
||||
BgNVBAMMCWxvY2FsaG9zdDAgFw0yMTEyMjMxNzEzMjNaGA80NzU5MTExOTE3MTMy
|
||||
M1owFDESMBAGA1UEAwwJbG9jYWxob3N0MEMwBQYDK2VxAzoAXlJkn15EFUS21zLI
|
||||
I+HSKlhvt88LSXK70KkN4JRRLrXPaTYfpSchFZWmSuLmx5m6rmSg5Ywj9d2Ao1Mw
|
||||
UTAdBgNVHQ4EFgQUxJBTkCx02jIpcUKU4fJYcnce59QwHwYDVR0jBBgwFoAUxJBT
|
||||
kCx02jIpcUKU4fJYcnce59QwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXEDcwDlxmpY
|
||||
U7j3CIVnMKAGA1rqML5lvKrDTS6DidTiq90dkMTyoXv8AE4omdiGobMnB3HZPl+B
|
||||
CpdDUYCfQfkNdi8Hqj3V9viqcgahbn5mGnjUAK1+Ix6r7KLm2zeKcfGEG008ykGW
|
||||
TMUFDvkQqRIlFDdOPAA=
|
||||
-----END CERTIFICATE-----
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MEcCAQAwBQYDK2VxBDsEOZvjURTKSor4A7+45hnY721WD06L3E4UMKh9zntEY83C
|
||||
CCv1Jju2fffDmtIFl6EXytF/nyEPGQfS5A==
|
||||
-----END PRIVATE KEY-----
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBLzCBsAIUDS2s4hUHeT9gYpGcf7SJNnyReDUwBQYDK2VxMBQxEjAQBgNVBAMM
|
||||
CWxvY2FsaG9zdDAgFw0yMTEyMTQxMDM3NTFaGA80NzU5MTExMDEwMzc1MVowFDES
|
||||
MBAGA1UEAwwJbG9jYWxob3N0MEMwBQYDK2VxAzoAMb/HUcgN/sU2rm1YHoTMFVTu
|
||||
ptY7hKjDm8mRxUWXzvHS0S6vqZRfJuCBQms4MSlTv+z1LjzDevUAMAUGAytlcQNz
|
||||
AA2eyrpA0O2TzNCeVEs0Dp/uXTzQPWJHD8fN0DCwSJf7xIY01jNmcvx/IFYnGCd+
|
||||
uQ/7vm6kcUFNgKhVWY9e7xLjYqeBirHTQiTRrh+9mKDOwmsSOhnz3acYPgrJ2QUO
|
||||
zDtZa16ppKRA5ucLJ4AXaacOAA==
|
||||
-----END CERTIFICATE-----
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MEcCAQAwBQYDK2VxBDsEOcj0BvnNHWg2dsOnww++p/PHxnl+KGWFXre57wXEredA
|
||||
j0xo78ZgadAeY0Y5mO4nfb8lk3CBz+ojGA==
|
||||
-----END PRIVATE KEY-----
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
|
||||
[req_distinguished_name]
|
||||
CN = localhost
|
||||
|
||||
[v3_ca]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always
|
||||
basicConstraints = critical,CA:true
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = digitalSignature, nonRepudiation, keyAgreement
|
||||
extendedKeyUsage = serverAuth
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBpjCCASagAwIBAgIUaZBiYKJjueUsvwoaeK9mh+F2mn0wBQYDK2VxMBQxEjAQ
|
||||
BgNVBAMMCWxvY2FsaG9zdDAgFw0yMTEyMjMxNzEzMzNaGA80NzU5MTExOTE3MTMz
|
||||
M1owFDESMBAGA1UEAwwJbG9jYWxob3N0MEMwBQYDK2VxAzoA/q7ngl2MOKDeHVgC
|
||||
4aNgO4+pOQ7cfHJhgVTKz0W6CCK9Ce39B0N+cRy6/dPzGCSSOYNKyGE0rnWAo28w
|
||||
bTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDyDATBgNVHSUEDDAKBggrBgEFBQcDATAd
|
||||
BgNVHQ4EFgQUQP8dENbwDxWZNX2QwauT1Ple6aswHwYDVR0jBBgwFoAUxJBTkCx0
|
||||
2jIpcUKU4fJYcnce59QwBQYDK2VxA3MATscvAiT11CqXODKwx/0uLan3mKRLfJrP
|
||||
gqshoOmIG4HUXoSPZwjgARaCKTwFwMlLmMJt6wd7c8iAnKdfghvDvE+fgSKDe1d4
|
||||
tVKQt+RWUzMb5w4WyqivxmKQyIBHNHzkj3Qh54P6JLpfMz29j84/pxIA
|
||||
-----END CERTIFICATE-----
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MEcCAQAwBQYDK2VxBDsEOQANqfrmSygKW1iiDCgf/G/y2AH1lp5NurM3Q73fp9Aw
|
||||
nznRFYq6BvM03cMOkqtFpQd15A+DZr248A==
|
||||
-----END PRIVATE KEY-----
|
||||
Reference in new issue
Block a user