Deprecation and documentation for the AESCounterBuiltinRNG issue
* reproducer test of AESCounterBuiltinRNG issue * update documentation of random-number-generator * deprecate AES128CounterSecureRNG AES256CounterSecureRNG * incorporate feedback from Johannes
This commit is contained in:
parent
56498e7e58
commit
b75bb8fc46
15 changed files with 282 additions and 66 deletions
|
|
@ -379,8 +379,6 @@ akka.remote.artery {
|
|||
protocol = "TLSv1.2"
|
||||
|
||||
enabled-algorithms = [TLS_DHE_RSA_WITH_AES_128_GCM_SHA256]
|
||||
|
||||
random-number-generator = "AES128CounterSecureRNG"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -469,8 +469,6 @@ akka {
|
|||
protocol = "TLSv1.2"
|
||||
|
||||
enabled-algorithms = [TLS_DHE_RSA_WITH_AES_128_GCM_SHA256]
|
||||
|
||||
random-number-generator = "AES128CounterSecureRNG"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
93
akka-docs/src/main/paradox/security/2018-08-29-aes-rng.md
Normal file
93
akka-docs/src/main/paradox/security/2018-08-29-aes-rng.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Broken random number generators AES128CounterSecureRNG / AES256CounterSecureRNG, Fixed in Akka 2.5.16
|
||||
|
||||
### Date
|
||||
|
||||
29 August 2018
|
||||
|
||||
### Description of Vulnerability
|
||||
|
||||
A random number generator is used in Akka Remoting for TLS (both classic and Artery
|
||||
Remoting). Akka allows to configure custom random number generators. For historical reasons,
|
||||
Akka included the `AES128CounterSecureRNG` and `AES256CounterSecureRNG` random number
|
||||
generators. The implementations had a bug that caused the generated numbers to be repeated
|
||||
after only a few bytes.
|
||||
|
||||
The custom RNG implementations were not configured by default but examples in the
|
||||
documentation showed (and therefore implicitly recommended) using the custom ones.
|
||||
|
||||
This can be used by an attacker to compromise the communication if these random number generators
|
||||
are enabled in configuration. It would be possible to eavesdrop, replay or modify the messages sent with
|
||||
Akka Remoting/Cluster.
|
||||
|
||||
To protect against such attacks the system should be updated to Akka *2.5.16* or later, or the default
|
||||
configuration of the TLS random number generator should be used:
|
||||
|
||||
```
|
||||
# Set `SecureRandom` RNG explicitly (but it is also the default)
|
||||
akka.remote.netty.ssl.random-number-generator = "SecureRandom"
|
||||
akka.remote.artery.ssl.config-ssl-engine.random-number-generator = "SecureRandom"
|
||||
```
|
||||
|
||||
Please subscribe to the [akka-security](https://groups.google.com/forum/#!forum/akka-security) mailing list to be notified promptly about future security issues.
|
||||
|
||||
### Severity
|
||||
|
||||
The [CVSS](https://en.wikipedia.org/wiki/CVSS) score of this vulnerability is 5.9 (Medium), based on vector [AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N/E:U/RL:O/RC:C](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N/E:U/RL:O/RC:C).
|
||||
|
||||
Rationale for the score:
|
||||
|
||||
* AV:A - Best practice is that Akka remoting nodes should only be accessible from the adjacent network, so in
|
||||
good setups, this will be adjacent.
|
||||
* AC:H - Any one in the adjacent network can launch the attack with non-special access privileges,
|
||||
but man-in-the-middle attacks are not trivial.
|
||||
* C:H, I:H - Confidentiality and Integrity are only partially affected because only the networking component
|
||||
is affected and not the whole Akka cluster. Assessed to be High anyway because access to actor system data would
|
||||
probably be possible by injecting messages into the remoting communication.
|
||||
|
||||
### Affected Versions
|
||||
|
||||
* Akka *2.5.0 - 2.5.15* with any of the following configuration properties defined:
|
||||
|
||||
```
|
||||
akka.remote.netty.ssl.random-number-generator = "AES128CounterSecureRNG"
|
||||
akka.remote.netty.ssl.random-number-generator = "AES256CounterSecureRNG"
|
||||
akka.remote.artery.ssl.config-ssl-engine.random-number-generator = "AES128CounterSecureRNG"
|
||||
akka.remote.artery.ssl.config-ssl-engine.random-number-generator = "AES256CounterSecureRNG"
|
||||
```
|
||||
|
||||
Akka *2.4.x* versions are not affected by this particular bug. It has reached
|
||||
end-of-life since start of 2018. If you still run on Akka 2.4, we still
|
||||
recommend to use the default `SecureRandom` implementation for the reasons
|
||||
given below. Please check your configuration files not to configure the
|
||||
custom RNGs.
|
||||
|
||||
### Fixed Versions
|
||||
|
||||
We have prepared patches for the affected versions, and have released the following version which resolve the issue:
|
||||
|
||||
* Akka *2.5.16* (Scala 2.11, 2.12)
|
||||
|
||||
Binary and source compatibility has been maintained for the patched releases so the upgrade procedure is as simple
|
||||
as changing the library dependency.
|
||||
|
||||
The exact historical reasons to include custom RNG implementations could not be reconstructed
|
||||
but it was likely because RNGs provided by previous versions of the JDK were deemed too slow.
|
||||
|
||||
Including custom cryptographic components in your library (or application) should not be done
|
||||
lightly. We acknowledge that we cannot prove that the custom RNGs that Akka provides or has
|
||||
been providing are generally correct or just correct enough for the purposes in Akka.
|
||||
|
||||
The reporter of this vulnerability, Rafał Sumisławski, kindly provided us with fixes for the
|
||||
custom RNGs in Akka. However, as we cannot thoroughly verify the correctness of the algorithm
|
||||
we decided to remove custom RNGs from Akka.
|
||||
|
||||
If the "AES128CounterSecureRNG" and "AES256CounterSecureRNG" configuration values are still used with Akka 2.5.16
|
||||
they will be ignored and the default `SecureRandom` is used and a warning is logged. This is to avoid accidental
|
||||
use of these unverified and possibly insecure implementations. The deprecated implementations are not recommended,
|
||||
but they can be enabled by using configuration values "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG"
|
||||
during the transition period until they have been removed.
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
We would like to thank Rafał Sumisławski at NetworkedAssets for bringing this issue to our attention and providing
|
||||
a patch.
|
||||
|
|
@ -30,5 +30,6 @@ to ensure that a fix can be provided without delay.
|
|||
|
||||
* [2017-02-10-java-serialization](2017-02-10-java-serialization.md)
|
||||
* [2017-08-09-camel](2017-08-09-camel.md)
|
||||
* [2018-08-29-aes-rng](2018-08-29-aes-rng.md)
|
||||
|
||||
@@@
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
# AES random number generator issue, security was selected over compatibility
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AESCounterBuiltinRNG$AESKey")
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AESCounterBuiltinRNG")
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AESCounterBuiltinRNG$")
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AkkaProvider$")
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AES256CounterSecureRNG")
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AES128CounterSecureRNG")
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AkkaProvider")
|
||||
|
|
@ -666,13 +666,15 @@ akka {
|
|||
# http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunJCEProvider
|
||||
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA"]
|
||||
|
||||
# There are three options, in increasing order of security:
|
||||
# "" or SecureRandom => (default)
|
||||
# There are two options, and the default SecureRandom is recommended:
|
||||
# "" or "SecureRandom" => (default)
|
||||
# "SHA1PRNG" => Can be slow because of blocking issues on Linux
|
||||
# "AES128CounterSecureRNG" => fastest startup and based on AES encryption
|
||||
# algorithm
|
||||
# "AES256CounterSecureRNG" (Install JCE Unlimited Strength Jurisdiction
|
||||
# Policy Files first)
|
||||
#
|
||||
# "AES128CounterSecureRNG" and "AES256CounterSecureRNG" were deprecated in Akka
|
||||
# 2.5.16 and if these configuration values are used it will use the default
|
||||
# SecureRandom anyway and log a warning. The deprecated implementations are
|
||||
# not recommended, but they can be enabled by using configuration values
|
||||
# "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG"
|
||||
#
|
||||
# Setting a value here may require you to supply the appropriate cipher
|
||||
# suite (see enabled-algorithms section above)
|
||||
|
|
@ -1158,13 +1160,15 @@ akka {
|
|||
# http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunJCEProvider
|
||||
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA"]
|
||||
|
||||
# There are three options, in increasing order of security:
|
||||
# "" or SecureRandom => (default)
|
||||
# There are two options, and the default SecureRandom is recommended:
|
||||
# "" or "SecureRandom" => (default)
|
||||
# "SHA1PRNG" => Can be slow because of blocking issues on Linux
|
||||
# "AES128CounterSecureRNG" => fastest startup and based on AES encryption
|
||||
# algorithm
|
||||
# "AES256CounterSecureRNG" (Install JCE Unlimited Strength Jurisdiction
|
||||
# Policy Files first)
|
||||
#
|
||||
# "AES128CounterSecureRNG" and "AES256CounterSecureRNG" were deprecated in Akka
|
||||
# 2.5.16 and if these configuration values are used it will use the default
|
||||
# SecureRandom anyway and log a warning. The deprecated implementations are
|
||||
# not recommended, but they can be enabled by using configuration values
|
||||
# "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG"
|
||||
#
|
||||
# Setting a value here may require you to supply the appropriate cipher
|
||||
# suite (see enabled-algorithms section above)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import akka.event.LogMarker
|
|||
import akka.event.Logging
|
||||
import akka.event.MarkerLoggingAdapter
|
||||
import akka.japi.Util.immutableSeq
|
||||
import akka.remote.security.provider.AkkaProvider
|
||||
import akka.remote.security.provider.DeprecatedAkkaProvider
|
||||
import akka.stream.IgnoreComplete
|
||||
import akka.stream.TLSClosing
|
||||
import akka.stream.TLSRole
|
||||
|
|
@ -223,21 +223,28 @@ object SSLEngineProviderSetup {
|
|||
@InternalApi private[akka] object SecureRandomFactory {
|
||||
def createSecureRandom(randomNumberGenerator: String, log: MarkerLoggingAdapter): SecureRandom = {
|
||||
val rng = randomNumberGenerator match {
|
||||
case r @ ("AES128CounterSecureRNG" | "AES256CounterSecureRNG") ⇒
|
||||
log.debug("SSL random number generator set to: {}", r)
|
||||
SecureRandom.getInstance(r, AkkaProvider)
|
||||
case s @ ("SHA1PRNG" | "NativePRNG") ⇒
|
||||
log.debug("SSL random number generator set to: {}", s)
|
||||
// SHA1PRNG needs /dev/urandom to be the source on Linux to prevent problems with /dev/random blocking
|
||||
// However, this also makes the seed source insecure as the seed is reused to avoid blocking (not a problem on FreeBSD).
|
||||
SecureRandom.getInstance(s)
|
||||
|
||||
case "" ⇒
|
||||
log.debug("SSLRandomNumberGenerator not specified, falling back to SecureRandom")
|
||||
case "" | "SecureRandom" ⇒
|
||||
log.debug("SSL random number generator set to [SecureRandom]")
|
||||
new SecureRandom
|
||||
|
||||
case r @ ("AES128CounterSecureRNG" | "AES256CounterSecureRNG") ⇒
|
||||
log.warning("SSL random number generator set to deprecated [{}], using [SecureRandom] instead. " +
|
||||
"The [{}] implementation can be enabled with configuration value [Deprecated{r}], " +
|
||||
"but that is not recommended.", r, r, r)
|
||||
new SecureRandom
|
||||
|
||||
case r @ ("DeprecatedAES128CounterSecureRNG" | "DeprecatedAES256CounterSecureRNG") ⇒
|
||||
log.warning("SSL random number generator set to deprecated [{}]. Use [SecureRandom] instead.", r)
|
||||
SecureRandom.getInstance(r, DeprecatedAkkaProvider)
|
||||
|
||||
case unknown ⇒
|
||||
log.warning(LogMarker.Security, "Unknown SSLRandomNumberGenerator [{}] falling back to SecureRandom", unknown)
|
||||
log.warning(LogMarker.Security, "Unknown SSL random number generator [{}] falling back to SecureRandom", unknown)
|
||||
new SecureRandom
|
||||
}
|
||||
rng.nextInt() // prevent stall on first access
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.remote.security.provider
|
||||
|
||||
import java.security.{ PrivilegedAction, AccessController, Provider }
|
||||
|
||||
/**
|
||||
* A provider that for AES128CounterRNGFast, a cryptographically secure random number generator through SecureRandom
|
||||
*/
|
||||
object AkkaProvider extends Provider("Akka", 1.0, "Akka provider 1.0 that implements a secure AES random number generator") {
|
||||
AccessController.doPrivileged(new PrivilegedAction[this.type] {
|
||||
def run = {
|
||||
//SecureRandom
|
||||
put("SecureRandom.AES128CounterSecureRNG", classOf[AES128CounterSecureRNG].getName)
|
||||
put("SecureRandom.AES256CounterSecureRNG", classOf[AES256CounterSecureRNG].getName)
|
||||
|
||||
//Implementation type: software or hardware
|
||||
put("SecureRandom.AES128CounterSecureRNG ImplementedIn", "Software")
|
||||
put("SecureRandom.AES256CounterSecureRNG ImplementedIn", "Software")
|
||||
null //Magic null is magic
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -14,13 +14,15 @@ import scala.concurrent.ExecutionContext
|
|||
/**
|
||||
* This class is a wrapper around the 128-bit AESCounterBuiltinRNG AES/CTR PRNG algorithm
|
||||
* The only method used by netty ssl is engineNextBytes(bytes)
|
||||
*
|
||||
*/
|
||||
class AES128CounterSecureRNG extends java.security.SecureRandomSpi {
|
||||
@deprecated("Use SecureRandom instead. We cannot prove that this code is correct, see https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html", "2.5.16")
|
||||
class DeprecatedAES128CounterSecureRNG extends java.security.SecureRandomSpi {
|
||||
private val singleThreadPool = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor(new AESCounterBuiltinRNGReSeeder))
|
||||
private val entropySource = new SecureRandom
|
||||
private val seed = entropySource.generateSeed(Seed128)
|
||||
|
||||
private val rng = new AESCounterBuiltinRNG(seed, singleThreadPool)
|
||||
private val rng = new DeprecatedAESCounterBuiltinRNG(seed, singleThreadPool)
|
||||
|
||||
/**
|
||||
* This is managed internally by AESCounterBuiltinRNG
|
||||
|
|
@ -15,12 +15,13 @@ import scala.concurrent.ExecutionContext
|
|||
* This class is a wrapper around the 256-bit AESCounterBuiltinRNG AES/CTR PRNG algorithm
|
||||
* The only method used by netty ssl is engineNextBytes(bytes)
|
||||
*/
|
||||
class AES256CounterSecureRNG extends java.security.SecureRandomSpi {
|
||||
@deprecated("Use SecureRandom instead. We cannot prove that this code is correct, see https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html", "2.5.16")
|
||||
class DeprecatedAES256CounterSecureRNG extends java.security.SecureRandomSpi {
|
||||
private val singleThreadPool = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor(new AESCounterBuiltinRNGReSeeder))
|
||||
private val entropySource = new SecureRandom
|
||||
private val seed = entropySource.generateSeed(Seed256)
|
||||
|
||||
private val rng = new AESCounterBuiltinRNG(seed, singleThreadPool)
|
||||
private val rng = new DeprecatedAESCounterBuiltinRNG(seed, singleThreadPool)
|
||||
|
||||
/**
|
||||
* This is managed internally by AESCounterBuiltinRNG
|
||||
|
|
@ -17,6 +17,11 @@ import scala.concurrent.{ Await, ExecutionContext, Future, duration }
|
|||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* We cannot prove that this code is correct and it will therefore be removed
|
||||
* with AES128CounterSecureRNG and AES256CounterSecureRNG. See security
|
||||
* vulnerability https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html
|
||||
*
|
||||
* This class is a Scala implementation of AESCounterRNG algorithm
|
||||
* patterned after org.uncommons.maths.random by Daniel Dyer (Apache License 2.0)
|
||||
*
|
||||
|
|
@ -32,10 +37,10 @@ import scala.concurrent.{ Await, ExecutionContext, Future, duration }
|
|||
* NOTE: this class is not serializable
|
||||
*/
|
||||
@InternalApi
|
||||
private[akka] class AESCounterBuiltinRNG(val seed: Array[Byte], implicit val executionContext: ExecutionContext,
|
||||
val reseedingThreshold: Long = CounterRNGConstants.ReseedingThreshold,
|
||||
val reseedingDeadline: Long = CounterRNGConstants.ReseedingDeadline,
|
||||
val reseedingTimeout: Duration = CounterRNGConstants.ReseedingTimeout) extends Random {
|
||||
private[akka] class DeprecatedAESCounterBuiltinRNG(val seed: Array[Byte], implicit val executionContext: ExecutionContext,
|
||||
val reseedingThreshold: Long = CounterRNGConstants.ReseedingThreshold,
|
||||
val reseedingDeadline: Long = CounterRNGConstants.ReseedingDeadline,
|
||||
val reseedingTimeout: Duration = CounterRNGConstants.ReseedingTimeout) extends Random {
|
||||
import CounterRNGConstants._
|
||||
|
||||
private val entropySource = new SecureRandom
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.remote.security.provider
|
||||
|
||||
import java.security.{ PrivilegedAction, AccessController, Provider }
|
||||
|
||||
/**
|
||||
* A provider that for AES128CounterRNGFast, a cryptographically secure random number generator through SecureRandom
|
||||
*
|
||||
*/
|
||||
@deprecated("Use SecureRandom instead. We cannot prove that this code is correct, see https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html", "2.5.16")
|
||||
object DeprecatedAkkaProvider extends Provider("Akka", 1.0, "Akka provider 1.0 that implements a secure AES random number generator") {
|
||||
AccessController.doPrivileged(new PrivilegedAction[this.type] {
|
||||
def run = {
|
||||
//SecureRandom
|
||||
put("SecureRandom.DeprecatedAES128CounterSecureRNG", classOf[DeprecatedAES128CounterSecureRNG].getName)
|
||||
put("SecureRandom.DeprecatedAES256CounterSecureRNG", classOf[DeprecatedAES256CounterSecureRNG].getName)
|
||||
|
||||
//Implementation type: software or hardware
|
||||
put("SecureRandom.DeprecatedAES128CounterSecureRNG ImplementedIn", "Software")
|
||||
put("SecureRandom.DeprecatedAES256CounterSecureRNG ImplementedIn", "Software")
|
||||
null //Magic null is magic
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -7,7 +7,7 @@ package akka.remote.transport.netty
|
|||
import java.security._
|
||||
|
||||
import akka.japi.Util._
|
||||
import akka.remote.security.provider.AkkaProvider
|
||||
import akka.remote.security.provider.DeprecatedAkkaProvider
|
||||
import com.typesafe.config.Config
|
||||
import org.jboss.netty.handler.ssl.SslHandler
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ private[akka] class SSLSettings(config: Config) {
|
|||
private[akka] object NettySSLSupport {
|
||||
|
||||
// TODO is this needed in Artery TLS?
|
||||
Security addProvider AkkaProvider
|
||||
Security addProvider DeprecatedAkkaProvider
|
||||
|
||||
/**
|
||||
* Construct a SSLHandler which can be inserted into a Netty server/client pipeline
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
package akka.remote
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
import akka.actor._
|
||||
import akka.event.NoMarkerLogging
|
||||
|
|
@ -54,7 +56,8 @@ object Configuration {
|
|||
}
|
||||
"""
|
||||
|
||||
final case class CipherConfig(runTest: Boolean, config: Config, cipher: String, localPort: Int, remotePort: Int)
|
||||
final case class CipherConfig(runTest: Boolean, config: Config, cipher: String, localPort: Int, remotePort: Int,
|
||||
provider: Option[ConfigSSLEngineProvider])
|
||||
|
||||
def getCipherConfig(cipher: String, enabled: String*): CipherConfig = {
|
||||
val localPort, remotePort = { val s = new java.net.ServerSocket(0); try s.getLocalPort finally s.close() }
|
||||
|
|
@ -69,7 +72,10 @@ object Configuration {
|
|||
val rng = sslEngineProvider.createSecureRandom()
|
||||
|
||||
rng.nextInt() // Has to work
|
||||
val sRng = settings.SSLRandomNumberGenerator
|
||||
val sRng = settings.SSLRandomNumberGenerator match {
|
||||
case "AES128CounterSecureRNG" | "AES256CounterSecureRNG" ⇒ ""
|
||||
case other ⇒ other
|
||||
}
|
||||
if (rng.getAlgorithm != sRng && sRng != "")
|
||||
throw new NoSuchAlgorithmException(sRng)
|
||||
|
||||
|
|
@ -81,9 +87,10 @@ object Configuration {
|
|||
engine.getSupportedProtocols.contains(settings.SSLProtocol) ||
|
||||
(throw new IllegalArgumentException("Protocol not supported: " + settings.SSLProtocol))
|
||||
|
||||
CipherConfig(true, config, cipher, localPort, remotePort)
|
||||
CipherConfig(true, config, cipher, localPort, remotePort, Some(sslEngineProvider))
|
||||
} catch {
|
||||
case (_: IllegalArgumentException) | (_: NoSuchAlgorithmException) ⇒ CipherConfig(false, AkkaSpec.testConf, cipher, localPort, remotePort) // Cannot match against the message since the message might be localized :S
|
||||
case _: IllegalArgumentException | _: NoSuchAlgorithmException ⇒
|
||||
CipherConfig(false, AkkaSpec.testConf, cipher, localPort, remotePort, None) // Cannot match against the message since the message might be localized :S
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,13 +99,17 @@ class Ticket1978SHA1PRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig
|
|||
|
||||
class Ticket1978AES128CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("AES128CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
|
||||
|
||||
class Ticket1978DeprecatedAES128CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("DeprecatedAES128CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
|
||||
|
||||
class Ticket1978AES256CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("AES256CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
|
||||
|
||||
class Ticket1978DeprecatedAES256CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("DeprecatedAES256CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
|
||||
|
||||
class Ticket1978DefaultRNGSecureSpec extends Ticket1978CommunicationSpec(getCipherConfig("", "TLS_RSA_WITH_AES_128_CBC_SHA"))
|
||||
|
||||
class Ticket1978CrappyRSAWithMD5OnlyHereToMakeSureThingsWorkSpec extends Ticket1978CommunicationSpec(getCipherConfig("", "SSL_RSA_WITH_NULL_MD5"))
|
||||
|
||||
class Ticket1978NonExistingRNGSecureSpec extends Ticket1978CommunicationSpec(CipherConfig(false, AkkaSpec.testConf, "NonExistingRNG", 12345, 12346))
|
||||
class Ticket1978NonExistingRNGSecureSpec extends Ticket1978CommunicationSpec(CipherConfig(false, AkkaSpec.testConf, "NonExistingRNG", 12345, 12346, None))
|
||||
|
||||
abstract class Ticket1978CommunicationSpec(val cipherConfig: CipherConfig) extends AkkaSpec(cipherConfig.config) with ImplicitSender {
|
||||
|
||||
|
|
@ -121,6 +132,38 @@ abstract class Ticket1978CommunicationSpec(val cipherConfig: CipherConfig) exten
|
|||
val ignoreMe = other.actorOf(Props(new Actor { def receive = { case ("ping", x) ⇒ sender() ! ((("pong", x), sender())) } }), "echo")
|
||||
val otherAddress = other.asInstanceOf[ExtendedActorSystem].provider.asInstanceOf[RemoteActorRefProvider].transport.defaultAddress
|
||||
|
||||
"generate random" in {
|
||||
val rng = cipherConfig.provider.get.createSecureRandom()
|
||||
val bytes = Array.ofDim[Byte](16)
|
||||
// awaitAssert just in case we are very unlucky to get same sequence more than once
|
||||
awaitAssert {
|
||||
val randomBytes = (1 to 10).map { n ⇒
|
||||
rng.nextBytes(bytes)
|
||||
bytes.toVector
|
||||
}.toSet
|
||||
randomBytes.size should ===(10)
|
||||
}
|
||||
}
|
||||
|
||||
"have random numbers that are not compressable, because then they are not random" in {
|
||||
val provider = new ConfigSSLEngineProvider(system)
|
||||
val rng = provider.createSecureRandom()
|
||||
|
||||
val randomData = new Array[Byte](1024 * 1024)
|
||||
rng.nextBytes(randomData)
|
||||
|
||||
val baos = new ByteArrayOutputStream()
|
||||
val gzipped = new GZIPOutputStream(baos)
|
||||
try gzipped.write(randomData)
|
||||
finally gzipped.close()
|
||||
|
||||
val compressed = baos.toByteArray
|
||||
// random data should not be compressible
|
||||
// Another reproducer of https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html
|
||||
// with the broken implementation the compressed size was <5k
|
||||
compressed.size should be > randomData.length
|
||||
}
|
||||
|
||||
"support tell" in within(timeout.duration) {
|
||||
val here = {
|
||||
system.actorSelection(otherAddress.toString + "/user/echo") ! Identify(None)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
package akka.remote.artery
|
||||
package tcp
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
|
|
@ -39,6 +41,13 @@ class TlsTcpWithAES128CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.pars
|
|||
}
|
||||
"""))
|
||||
|
||||
class TlsTcpWithDeprecatedAES128CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
|
||||
akka.remote.artery.ssl.config-ssl-engine {
|
||||
random-number-generator = "DeprecatedAES128CounterSecureRNG"
|
||||
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
|
||||
}
|
||||
"""))
|
||||
|
||||
class TlsTcpWithAES256CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
|
||||
akka.remote.artery.ssl.config-ssl-engine {
|
||||
random-number-generator = "AES256CounterSecureRNG"
|
||||
|
|
@ -46,6 +55,13 @@ class TlsTcpWithAES256CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.pars
|
|||
}
|
||||
"""))
|
||||
|
||||
class TlsTcpWithDeprecatedAES256CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
|
||||
akka.remote.artery.ssl.config-ssl-engine {
|
||||
random-number-generator = "DeprecatedAES256CounterSecureRNG"
|
||||
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
|
||||
}
|
||||
"""))
|
||||
|
||||
class TlsTcpWithDefaultRNGSecureSpec extends TlsTcpSpec(ConfigFactory.parseString("""
|
||||
akka.remote.artery.ssl.config-ssl-engine {
|
||||
random-number-generator = ""
|
||||
|
|
@ -86,7 +102,10 @@ abstract class TlsTcpSpec(config: Config)
|
|||
|
||||
val rng = provider.createSecureRandom()
|
||||
rng.nextInt() // Has to work
|
||||
val sRng = provider.SSLRandomNumberGenerator
|
||||
val sRng = provider.SSLRandomNumberGenerator match {
|
||||
case "AES128CounterSecureRNG" | "AES256CounterSecureRNG" ⇒ ""
|
||||
case other ⇒ other
|
||||
}
|
||||
if (rng.getAlgorithm != sRng && sRng != "")
|
||||
throw new NoSuchAlgorithmException(sRng)
|
||||
|
||||
|
|
@ -102,7 +121,7 @@ abstract class TlsTcpSpec(config: Config)
|
|||
engine.getSupportedProtocols.contains(provider.SSLProtocol) ||
|
||||
(throw new IllegalArgumentException("Protocol not supported: " + provider.SSLProtocol))
|
||||
} catch {
|
||||
case e @ ((_: IllegalArgumentException) | (_: NoSuchAlgorithmException)) ⇒
|
||||
case e @ (_: IllegalArgumentException | _: NoSuchAlgorithmException) ⇒
|
||||
info(e.toString)
|
||||
false
|
||||
}
|
||||
|
|
@ -128,6 +147,41 @@ abstract class TlsTcpSpec(config: Config)
|
|||
|
||||
if (isSupported) {
|
||||
|
||||
"generate random" in {
|
||||
val provider = new ConfigSSLEngineProvider(system)
|
||||
val rng = provider.createSecureRandom()
|
||||
val bytes = Array.ofDim[Byte](16)
|
||||
// Reproducer of the specific issue described at
|
||||
// https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html
|
||||
// awaitAssert just in case we are very unlucky to get same sequence more than once
|
||||
awaitAssert {
|
||||
val randomBytes = (1 to 10).map { n ⇒
|
||||
rng.nextBytes(bytes)
|
||||
bytes.toVector
|
||||
}.toSet
|
||||
randomBytes.size should ===(10)
|
||||
}
|
||||
}
|
||||
|
||||
"have random numbers that are not compressable, because then they are not random" in {
|
||||
val provider = new ConfigSSLEngineProvider(system)
|
||||
val rng = provider.createSecureRandom()
|
||||
|
||||
val randomData = new Array[Byte](1024 * 1024)
|
||||
rng.nextBytes(randomData)
|
||||
|
||||
val baos = new ByteArrayOutputStream()
|
||||
val gzipped = new GZIPOutputStream(baos)
|
||||
try gzipped.write(randomData)
|
||||
finally gzipped.close()
|
||||
|
||||
val compressed = baos.toByteArray
|
||||
// random data should not be compressible
|
||||
// Another reproducer of https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html
|
||||
// with the broken implementation the compressed size was <5k
|
||||
compressed.size should be > randomData.length
|
||||
}
|
||||
|
||||
"deliver messages" in {
|
||||
systemB.actorOf(TestActors.echoActorProps, "echo")
|
||||
val echoRef = identify(rootB / "user" / "echo")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue