blob: 84f851ecd73c47e06c2a90466cefc8b95baeecb5 [file] [log] [blame] [view]
## Security providers setup
While the code supports _BouncyCastle_ and _EdDSA_ security providers out-of-the-box,
it also provides a way to [add security providers](https://issues.apache.org/jira/browse/SSHD-713) via the `SecurityProviderRegistrar`
interface implementation. In order to add support for a new security provider one needs to implement the registrar interface and make
the code aware of it.
### Default/built-in security provider registrars
The code contains built-in security provider registrars for _BouncyCastle_ and _EdDSA_ (a.k.a. `ed25519`). It automatically detects
the existence of the required artifacts (since they are optional dependencies) and executes the respective security provider registration.
This behavior is controlled by the `org.apache.sshd.security.registrars` system property. This property contains a comma-separated list
of **fully-qualified** class names implementing the `SecurityProviderRegistrar` interface and assumed to contain a default **public**
no-arguments constructor. The code automatically parses the list and attempts to instantiate and invoke the registrar.
**Note:**
- The registration code automatically parses the configured registrars list and instantiates them. In this context, one can use the
special `none` value to indicate that the code should not attempt to automatically register the default providers.
- A registrar instance might be created but eventually discarded and not invoked if it is disabled, unsupported or already registered
programmatically via `SecurityUtils#registerSecurityProvider`.
- The registration attempt is a **one-shot** deal - i.e., once the registrars list is parsed and successfully resolved, any modifications
to the registered security providers must be done **programatically**. One can call `SecurityUtils#isRegistrationCompleted()` to find out
if the registration phase has already been executed.
- The registrars are consulted in the same **order** as they were initially registered - either programmatically or via the system property
configuration. Therefore, if two or more registrars support the same algorithm, then the earlier registered one will be used.
- If no matching registrar was found, then the default security provider is used. If none set, the JCE defaults are invoked. The default
security provider can be configured either via the `org.apache.sshd.security.defaultProvider` system property or by programmatically
invoking `SecurityUtils#setDefaultProviderChoice`. **Note:** if the system property option is used, then it is assumed to contain a security
provider's **name** (rather than its `Provider` class name...).
- If programmatic selection of the default security provider choice is required, then the code flow must ensure that
`SecurityUtils#setDefaultProviderChoice` is called before **any** security entity (e.g., ciphers, keys, etc...) are
required. Theoretically, one could change the choice after ciphers have been been requested but before keys were generated
(e.g....), but it is dangerous and may yield unpredictable behavior.
### Implementing a new security provider registrar
See `AbstractSecurityProviderRegistrar` helper class for a default implementation of most of the required functionality, as
well as the existing implementations for _BouncyCastle_ and _EdDSA_ for examples of how to implement it. The most important
issues to consider when adding such an implementation are:
* Try using reflection API to detect the existence of the registered provider class and/or instantiate it. The main reason
for this recommendation is that it isolates the code from a direct dependency on the provider's classes and makes class loading
issue less likely.
* Decide whether to use the provider's name or instance when creating security related entities such as ciphers, keys, etc...
**Note:** the default preference is to use the provider name, thus registering via `Security.addProvider` call. In order to
change that, either register the instance yourself or override the `isNamedProviderUsed` method. In this context, **cache**
the generated `Provider` instance if the instance rather than the name is used. **Note:** using only the provider instance
instead of the name is a rather new feature and has not been fully tested. It is possible though to decide and use it anyway
as long as it can be configurably disabled.
* The default implementation provides fine-grained control over the declared supported security entities - ciphers, signatures,
key generators, etc... By default, it is done via consulting a system property composed of `org.apache.sshd.security.provider`,
followed by the security provider name and the relevant security entity - e.g., `org.apache.sshd.security.provider.BC.KeyFactory`
is assumed to contain a comma-separated list of supported `KeyFactory` algorithms.
**Note:**
* The same naming convention can be used to enable/disable the registrar - even if supported - e.g.,
`org.apache.sshd.security.provider.BC.enabled=false` disables the _BouncyCastle_ registrar.
* One can use `all` or `*` to specify that all entities of the specified type are supported - e.g.,
`org.apache.sshd.security.provider.BC.MessageDigest=all`. In this context, one can override the
`getDefaultSecurityEntitySupportValue` method if no fine-grained configuration is required per-entity type,
* The result of an `isXxxSupported` call is/should be **cached** (see `AbstractSecurityProviderRegistrar`).
* For ease of implementation, all support query calls are routed to the `isSecurityEntitySupported` method
so that one can concentrate all the configuration in a single method. This is done for **convenience**
reasons - the code will invoke the correct support query as per the type of entity it needs. E.g., if it
needs a cipher, it will invoke `isCipherSupported` - which by default will invoke `isSecurityEntitySupported`
with the `Cipher` class as its argument.
* Specifically for **ciphers** the argument to the support query contains a **transformation** (e.g., `AES/CBC/NoPadding`)
so one should take that into account when parsing the input argument to decide which cipher is referenced - see
`SecurityProviderRegistrar.getEffectiveSecurityEntityName(Class<?>, String)` helper method
## Diff-Hellman group exchange configuration
The [RFC 4419 - Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol](https://tools.ietf.org/html/rfc4419)
specifies in section 3:
>> Servers and clients SHOULD support groups with a modulus length of k bits, where 1024 <= k <= 8192.
>> The recommended values for min and max are 1024 and 8192, respectively.
This was subsequently amended in [RFC 8270 - Increase the Secure Shell Minimum Recommended Diffie-Hellman Modulus Size to 2048 Bits](https://tools.ietf.org/html/rfc8270).
In any case, the values are auto-detected by the code but the user can intervene in 2 ways:
1. Programmatically - by invoking `SecurityUtils#setMin/MaxDHGroupExchangeKeySize` respectively
2. Via system property - by setting `org.apache.sshd.min/maxDHGexKeySize` system property respectively
**Note(s)**
* The value should be a multiple of 1024 (not enforced)
* The value should be between 2048 and 8192 (not enforced - allows users to make an **explicit** decision to use shorter keys - especially the minimum).
* The minimum must be less or equal to the maximum (enforced - if reversed then group exchange is **disabled**)
* If a **negative** value is set in either one then group exchange is **disabled**
* Setting a value of zero indicates a **lazy** auto-detection of the supported range the next time these values are needed.
Furthermore, if all possible primes have been exhausted the code no longer falls back to DH group exchange using SHA-1 unless the `ALLOW_DHG1_KEX_FALLBACK` core module property is set.
## FIPS Mode
Apache MINA sshd supports running in environments restricted by FIPS 140 through a special "FIPS mode".
In FIPS mode, crypto-algorithms not approved by FIPS-140 are disabled.
FIPS mode can be switched on in two ways:
* via System property `org.apache.sshd.security.fipsEnabled=true`, or
* if the system property is not set to `true` also programmatically via a call to `SecurityUtils.setFipsMode()` before any other call to the library.
In FIPS mode, the following algorithms are disabled completely:
* key exchange methods sntrup761x25519-sha512, sntrup761x25519-sha512<!-- -->@openssh.com, curve25519-sha256, curve25519-sha256<!-- -->@libssh.org, and curve448-sha512.
* the chacha20-poly1305 cipher.
* the bcrypt KDF used in encrypted private key files in [OpenSSH format](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key).
* all ed25519 keys and signatures.
The `BouncyCastleSecurityProviderRegistrar` only considers the "BCFIPS" provider from `bc-fips`
and disregards the "BC" provider from normal Bouncy Castle. The registrar for _EdDSA_ is disabled.
For random numbers, `SecureRandom.getInstanceStrong()` is used.
This FIPS mode does not automatically make an application using Apache MINA sshd FIPS-140-compliant.
It only ensures that the Apache MINA sshd library does not provide or use algorithms that should not
be used in FIPS-140-compliant applications running in approved mode.
It is usually necessary to configure the JVM for full FIPS 140 compliance, for instance, by defining
appropriate security providers statically. Any such configuration is beyond the scope of the Apache MINA
sshd library.