From 4fcdc4a237a217262c29e9b1a1804dda410ba0a0 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sat, 20 Apr 2024 13:43:19 +0100 Subject: Removed auto-generated cert functionality It wasn't a great idea to start with (I never used it), so I decided it was best if it was removed. Generating self signed certificates is easy enough. --- CHANGES.md | 3 +- README.md | 12 ------- server/src/net/usebox/gemini/server/Server.scala | 29 ++++++--------- .../src/net/usebox/gemini/server/ServiceConf.scala | 3 +- server/src/net/usebox/gemini/server/TLSUtils.scala | 41 +--------------------- server/test/src/ServiceConfSpec.scala | 8 +++-- server/test/src/TestData.scala | 8 +++-- spacebeans.conf.example | 2 -- 8 files changed, 27 insertions(+), 79 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c9295c3..9f731f1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,9 @@ # What's new? -## Release 1.3.9 - 2024-??-?? +## Release 1.4.0 - 2024-??-?? - Updated dependencies. + - Removed auto-generated certificates functionality. ## Release 1.3.8 - 2024-01-29 diff --git a/README.md b/README.md index cd923a6..4888855 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ Some of the **SpaceBeans** features: - Virtual hosting, with SNI support - User directories support - Classic CGI scripts - - User provided certificates or auto-generated in memory (for development) - Configurable SSL engine (e.g. TLSv1.2 and/or TLSv1.3), with configurable ciphers Check [CHANGES](CHANGES.md) to see what's new in the latest release. @@ -47,17 +46,6 @@ You should evaluate your security requirements when running **SpaceBeans**. In this section *TOFU* refers to "Trust On First Use". -### Auto-generated self-signed certificate - -This is the easiest option, no need to store securely the certificate. The -downside is that you get a new certificate every time you start the service, -and that's bad for TOFU validation. - -This is recommended **only for development** and not for a service facing the -Internet. - -Comment out the `key-store` section on your virtual host and you are done. - ### Self-signed certificate You can generate a self signed certificate using Java's `keytool`: diff --git a/server/src/net/usebox/gemini/server/Server.scala b/server/src/net/usebox/gemini/server/Server.scala index bd3c66c..4dc39c1 100644 --- a/server/src/net/usebox/gemini/server/Server.scala +++ b/server/src/net/usebox/gemini/server/Server.scala @@ -65,25 +65,18 @@ case class Server(conf: ServiceConf) { def serve = { val certs = conf.virtualHosts.map { vhost => - vhost.keyStore.fold( - ( - vhost.host, - TLSUtils.genSelfSignedCert(vhost.host, conf.genCertValidFor) + val KeyStore(path, alias, password) = vhost.keyStore + TLSUtils + .loadCert(path, alias, password) + .fold( + err => { + logger + .error(err)(s"Failed to load $alias cert from keystore $path") + system.terminate() + throw err + }, + r => (vhost.host, r) ) - ) { - case KeyStore(path, alias, password) => - TLSUtils - .loadCert(path, alias, password) - .fold( - err => { - logger - .error(err)(s"Failed to load $alias cert from keystore $path") - system.terminate() - throw err - }, - r => (vhost.host, r) - ) - } }.toMap val sslContext = TLSUtils.genSSLContext(certs) diff --git a/server/src/net/usebox/gemini/server/ServiceConf.scala b/server/src/net/usebox/gemini/server/ServiceConf.scala index c6b5d9a..562cb35 100644 --- a/server/src/net/usebox/gemini/server/ServiceConf.scala +++ b/server/src/net/usebox/gemini/server/ServiceConf.scala @@ -19,7 +19,7 @@ case class Directory( case class VirtualHost( host: String, root: String, - keyStore: Option[KeyStore] = None, + keyStore: KeyStore, indexFile: String = "index.gmi", directoryListing: Boolean = true, geminiParams: Option[String] = None, @@ -81,7 +81,6 @@ case class ServiceConf( defaultMimeType: String, mimeTypes: Option[Map[String, List[String]]] = None, virtualHosts: List[VirtualHost], - genCertValidFor: FiniteDuration, enabledProtocols: List[String], enabledCipherSuites: List[String] ) diff --git a/server/src/net/usebox/gemini/server/TLSUtils.scala b/server/src/net/usebox/gemini/server/TLSUtils.scala index 012da2f..75b2645 100644 --- a/server/src/net/usebox/gemini/server/TLSUtils.scala +++ b/server/src/net/usebox/gemini/server/TLSUtils.scala @@ -1,13 +1,10 @@ package net.usebox.gemini.server import java.io.FileInputStream -import java.math.BigInteger import java.net.Socket -import java.security.{KeyPairGenerator, KeyStore, Principal, PrivateKey, SecureRandom, Security} +import java.security.{KeyStore, Principal, PrivateKey, SecureRandom, Security} import java.security.cert.X509Certificate import java.security.KeyStore.PrivateKeyEntry -import java.time.Instant -import java.util.Date import javax.net.ssl.{ ExtendedSSLSession, KeyManagerFactory, @@ -19,13 +16,10 @@ import javax.net.ssl.{ X509ExtendedKeyManager } -import scala.concurrent.duration.FiniteDuration import scala.jdk.CollectionConverters._ import scala.util.Try import org.bouncycastle.jce.provider.BouncyCastleProvider -import org.bouncycastle.jce.X509Principal -import org.bouncycastle.x509.X509V3CertificateGenerator import org.log4s._ object TLSUtils { @@ -133,38 +127,6 @@ object TLSUtils { ) }.toEither - def genSelfSignedCert( - host: String, - validFor: FiniteDuration - ): (X509Certificate, PrivateKey) = { - - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val kp = keyPairGenerator.generateKeyPair() - - val v3CertGen = new X509V3CertificateGenerator() - v3CertGen.setSerialNumber( - BigInteger.valueOf(new SecureRandom().nextInt()).abs() - ) - v3CertGen.setIssuerDN( - new X509Principal("CN=" + host + ", OU=None, O=None L=None, C=None") - ) - v3CertGen.setNotBefore( - Date.from(Instant.now().minusSeconds(60 * 60)) - ) - v3CertGen.setNotAfter( - Date.from(Instant.now().plusSeconds(validFor.toSeconds)) - ) - v3CertGen.setSubjectDN( - new X509Principal("CN=" + host + ", OU=None, O=None L=None, C=None") - ) - - v3CertGen.setPublicKey(kp.getPublic()) - v3CertGen.setSignatureAlgorithm("SHA256WithRSAEncryption") - - (v3CertGen.generateX509Certificate(kp.getPrivate()), kp.getPrivate()) - } - def genSSLContext( certs: Map[String, (X509Certificate, PrivateKey)] ): SSLContext = { @@ -199,5 +161,4 @@ object TLSUtils { ) ctx } - } diff --git a/server/test/src/ServiceConfSpec.scala b/server/test/src/ServiceConfSpec.scala index d886b4f..959f15d 100644 --- a/server/test/src/ServiceConfSpec.scala +++ b/server/test/src/ServiceConfSpec.scala @@ -124,10 +124,14 @@ class ServiceConfSpec extends AnyFlatSpec with Matchers { virtualHosts = List( VirtualHost( host = "localhost", - root = getClass.getResource("/").getPath() + root = getClass.getResource("/").getPath(), + keyStore = KeyStore( + path = "/tmp/unused.jks", + alias = "localhost", + password = "secret" + ) ) ), - genCertValidFor = 1.day, enabledProtocols = Nil, enabledCipherSuites = Nil ) diff --git a/server/test/src/TestData.scala b/server/test/src/TestData.scala index df3fbd6..64ac43b 100644 --- a/server/test/src/TestData.scala +++ b/server/test/src/TestData.scala @@ -16,10 +16,14 @@ object TestData { virtualHosts = List( VirtualHost( host = host, - root = getClass.getResource("/").getPath() + root = getClass.getResource("/").getPath(), + keyStore = KeyStore( + path = "/tmp/unused.jks", + alias = "localhost", + password = "secret" + ) ) ), - genCertValidFor = 1.day, enabledProtocols = Nil, enabledCipherSuites = Nil ) diff --git a/spacebeans.conf.example b/spacebeans.conf.example index c5b7694..e3faf8b 100644 --- a/spacebeans.conf.example +++ b/spacebeans.conf.example @@ -46,7 +46,6 @@ virtual-hosts = [ // user-directories = false // user-directory-path = "/home/{user}/public_gemini/" - // comment out to use an auto-generated self-signed certificate key-store { path = "/path/to/keystore.jks" alias = "localhost" @@ -56,7 +55,6 @@ virtual-hosts = [ ] // SSL support -gen-cert-valid-for = "365 days" enabled-protocols = [ "TLSv1.2", "TLSv1.3" ] enabled-cipher-suites = [ // TLSv 1.2 -- cgit v1.2.3