With version TLS 1.3 (RFC 8446) the TLS protocol has been significantly redesigned. iSaSiLk 6.0 supports all core and some optional
features of the TLS 1.3 protocol, however some optional features like Zero Round-Trip 0-RRT Early Data are yet not supported.
This document explains how to use and configure iSaSiLk for TLS 1.3. If you are using the default settings of iSaSiLk you should not have to do anything. TLS 1.3 is enabled by default and can be used without special configurations settings. However, you should be aware about you are using TLS 1.3 and might want to configure it according to your requirements.
The new default version interval is form TLS 1.0 to TLS 1.3.
TLS 1.3 cipher suites do not follow the TLS_<KeyExchangeAlgorithm>_WITH_<SymmetricEncryptionAlgorithm>_<HashAlgorithm> scheme anymore. They specify the symmetric AEAD and the hash algorithm to be used; authentication and key exchange mechanisms are negotiated by extensions.
iSaSiLk supports all cipher suites specified by the TLS 1.3 specification but uses a separate class (TLS13CipherSuite) to implement them:
If TLS 1.3 is used the first four suites listed above are enabled by the default (depending on their cryptographic availability), only suite TLS_AES_128_CCM_8_SHA256 does not belong to the default cipher suite set (but to the set of implemented cipher suites).
Additionally the following pre-TLS 1.3 cipher suites are also enabled by default (if supported by the underlying cryptographic capabilities):
Static RSA and CBC suites are enabled for backwards compatibility reasons.
If using the default version interval and the default cipher suite set — and the peer does support TLS 1.3 — a TLS 1.3 cipher suite will be selected for the handshake.
However, if you have enabled the default version interval and having explicitly set only some pre-TLS1.3 cipher suite(s) it is likely that you will run into a NullPointerException when SSLContext.updateCipherSuites() is called indicating that TLS 1.3 cipher suites are required for offering the TLS 1.3 protocol version. This because the new default maximum version SSLContext.VERSION_TLS13 needs at least one
enabled TLS 1.3 cipher suite. To get rid of this exception class SSLContext
offers a static method telling iSaSiLk to automatically downgrade to TLS 1.2 if TLS 1.3 is enabled but no TLS 1.3 cipher suites are set:
SSLContext.setDowngradeMaxVersionToTLS12IfNoTLS13CipherSuitesAvailable(true);
However, more appropriate you should update your configuration by either adding some TLS 1.3 cipher suite(s) or explicitly setting the maximum allowed protocol version to SSLContext.VERSION_TLS12.
Extensions are a fundamental building block of the TLS 1.3 protocol. Both, authentication
and key exchange are managed by extensions. Since TLS 1.3 would not work without extensions
iSaSiLk automatically creates and sets any missing extension that has not been enabled
by the application.
The following extensions are set by default:
On the client side additionally the PskKeyExchangeModes extension (with mode psk_dhe_ke) is included in
the extension list to be offered to the server.
Special attention has been taken to the SignatureAlgorithms extension since the meaning of the ecdsa
signature algorithms has been changed with TLS 1.3. Prior to TLS 1.3 the curve name has not been
part of the ecdsa signature algorithms. Thus ecdsa could have been used with any curve (suggested by
the SupportedEllipticCurves/SupportedGroups extension), regardless of which of the hash algorithms
sha1, sha256, sha384 or sha512 has been used. With TLS 1.3 only the legacy ecdsa_sha1 algorithm
may be used with any curve, whereas ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384 and
ecdsa_secp521r1_sha512 are bound to the NIST curves secp256r1, secp384r1 and secp521r1,
respectively; the curves/groups of the SupportedGroups extension only apply to the curve/group
used for the key exchange.
In addition to the SignatureAlgorithms extension TLS 1.3 has introduced the SignatureAlgorithmsCert
extension which applies to certificate signatures rather than to (CertificateVerify) signatures
generated during the TLS handshake. If no SignatureAlgorithmsCert extension is sent the algorithms
specified within the SignatureAlgorithms extension shall be used to check the certificate signature
algorithms, too.
Since certificates typically maybe signed by using different signature algorithm(s) than used
for signatures generated during the handshake, the SignatureAlgorithms extension may have to
cover algorithms for both types of signatures; or an SignatureAlgorithmsCert extension may be
explicitly used.
For interoperability reasons iSaSiLk by default does not check if signatures that have
been used to sign certificates comply with the SignatureAlgorithmsCert (or SignatureAlgorithms)
extension. However, it checks if the (CertificateVerify) algorithms used during the handshake comply
with the SignatureAlgorithms extension. To change this behavior you may declare
your SignatureAlgorithmsCert extension as being a critical extension and/or your
SignatureAlgorithms extension as being a not critical extension; or change the
default critical value of these extension types by calling:
ExtensionList.setDefaultCriticalValue(SignatureAlgorithmsCert.TYPE, true);
Of course, you do not need to stay with the default extensions used by iSaSiLk. You may
configure and use (some of) the extensions according to your requirements. A sample
extension configuration may look like (see the TLS13Server and TLS13Client samples):
// the extension list ExtensionList extensions = new ExtensionList(); // server_name ServerNameList serverNames = new ServerNameList(); extensions.addExtension(serverNames); // supported_groups; enable some specific groups only NamedGroup[] namedGroups = { SupportedGroups.NC_PRIME_SECP256R1, SupportedGroups.NC_X25519, SupportedGroups.FFDHE_2048 }; SupportedGroups supportedGroups = new SupportedGroups(namedGroups, true); extensions.addExtension(supportedGroups); // key_share; created from supported_groups KeyShare keyShare = KeyShare.createKeyShare(supportedGroups); extensions.addExtension(keyShare); // psk_key_exchange_modes PskKeyExchangeModes pskModes = new PskKeyExchangeModes(PskKeyExchangeModes.PSK_DHE_KE); extensions.addExtension(pskModes); // signature_algorithms SignatureScheme[] algorithms = { SignatureScheme.ecdsa_secp256r1_sha256, SignatureScheme.ed25519, SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pkcs1_sha256, }; SignatureAlgorithms signatureAlgorithms = new SignatureAlgorithms(new SignatureSchemeList(algorithms)); signatureAlgorithms.setCritical(true); extensions.addExtension(signatureAlgorithms); // signature_algorithms_cert algorithms = { SignatureScheme.ecdsa_secp256r1_sha256, SignatureScheme.ed25519, SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pkcs1_sha256, }; SignatureAlgorithms signatureAlgorithmsCert = new SignatureAlgorithmsCert(new SignatureSchemeList(algorithms)); signatureAlgorithmsCert.setCritical(true); extensions.addExtension(signatureAlgorithmsCert);
When setting the extension list for the SSLContext in use take care to set it
before updating the cipher suites, but behind setting the protocol
version interval:
// set the iSaSiLk SecurityProvider SecurityProvider.setSecurityProvider(new ECCelerateProvider()); // create the SSLContext SSLContext context = ...; // add (client or server) credentials ... // set the protocol version interval context.setAllowedProtocolVersions(SSLContext.VERSION_TLS12, SSLContext.VERSION_TLS13); // set the cipher suites context.setEnabledCipherSuiteList(new CipherSuiteList(CipherSuiteList.L_DEFAULT)); // set the extensions context.setExtensions(extensions); // update cipher suites context.updateCipherSuites();
To maintain backwards compatibility the session management remains unchanged. However, for TLS 1.3 a psk identity of the pre_shared_key extension is used as session id for identifying a pre shared key of the initial session to be used for resuming the session.
At any time after the regular handshake TLS 1.3 allows to send/exchange post handshake
messages to update/change cryptographic parameters. There are three types of post handshake
types defined:
Sending a new session ticket or requesting post client authentication may be only triggered on the server side, a key update may be done on both, client or server side.
In practice post handshaking may be used very carefully and may depend on the post handshake capabilities of the peer. For instance, it does not make sense to request post handshake authentication from a client that has not
sent a PostHandshakeAuth extension indicating that it is able to do post handshake authentication. Furthermore successful post handshaking may depend on the way the peer does handle it. For instance, a client may send its post handshake authentication messages immediately after having received the post
handshake authentication request from the server or may send some amount of application data before sending the post handshake authentication messages. iSaSiLk provides several configuration options that may be tried to handle post handshaking in a way most suitable for the intended peer. See the iSaSiLk Javadoc for more information.
We describe here how an iSaSiLk SSLv3/TLS client can use client authentication via an RSA smartcard or a similar device. Note that similar methods could be used to employ server side RSA, or (EC)DH and DSS via a smartcard but there is currently no document describing this step by step. However, note that there is another document describing the iSaSiLk provider architecture in more detail.
protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec spec, SecureRandom random) throws Exception {
if( algorithm.equals(ALG_CIPHER_RSA_SIGN) == false ) {
return super.getCipher(algorithm, mode, key, spec, random);
}
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", myHardwareProvider);
if( mode == CIPHER_ENCRYPT ) {
rsaCipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
}
return rsaCipher;
}
For more information about the iSaSiLk SecurityProvider model see the security provider site.
SecurityProvider.setSecurityProvider(new mySecurityProvider());
Two, add the respective credentials via clientContext.addClientCredentials(). The credentials consist of your certificate chain and a PrivateKey object.
This of course cannot and will not be the actual private key as that is contained in the smartcard. Instead it can be an instance of an existing class containing dummy values or it can be your own subclass of PrivateKey containing information meaning e.g. use the second key on the first smartcard. For example, you might subclass the IaikProvider implementation to use the IAIK
PCKS#11 provider for doing RSA
based cipher operations only:
package demo;
public class MySecurityProvider extends IaikProvider {
protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec param, SecureRandom random) throws Exception {
if (key instanceof IAIKPKCS11Key) {
if (algorithm.startsWith(ALG_CIPHER_RSA)) {
algorithm = ALG_CIPHER_RSA;
}
cipherEngine = Cipher.getInstance(algorithm, ((IAIKPKCS11Key) key).getTokenManager().getProvider().getName());
if (mode != CIPHER_NONE) {
int cmode = (mode == CIPHER_ENCRYPT) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
cipherEngine.init(cmode, key, param, random);
}
} else {
cipherEngine = super.getCipher(algorithm, mode, key, param, random);
}
}
}
Once you have done that you are ready to go. All that remains is standard programming for iSaSiLk and the Java™ platform, see the respective documentation for more information.
We will first explain how to get the demo working and then move on to some explanation, usage recommendations, and JDK version notes. It is recommended that you read this entire document even if some
sections may not seem to apply to you at the moment.
There are no special requirements RMI has about the socket layer that transports its calls. In other words, the core SSL library does not know or care about RMI, it is an add-on on top of it. All we do is provide a description and a demo of how we think our library should be used to secure RMI.
If you want to do something differently, just do it.
There are three players in RMI: the server, who offers services to remote programs; the client, who uses those services; and
the registry, which helps clients find servers. These player communicate using sockets and all this communication can be secured using SSL/TLS. This is what is done in the demo, where all communication between any of these players is encrypted using
strong cryptography and clients and servers are authenticated using certificates.
To run the demo follow these steps:
set CLASSPATH=%CLASSPATH%;.;lib\iaik_ssl.jar;lib\iaik_ssl_demo.jar;lib\iaik_jce_full.jar;lib\jdk11x_update.jar
Use thisrmic -d . demo.rmi.SSLHelloImpl
with the rmi compiler of your JDK. This will generate the required RMI stub and skeleton classes. If you use JDK 1.2 or later you can also select RMI compatibilityjava demo.SetupKeyStore
java demo.rmi.SSLRMIUtil
instead. It should print the success messageSSL rmiregistry started successfully...
java demo.rmi.SSLHelloImpl
It will register with the RMI registry and then printSSLHelloImpl created and bound in the registry to the name SSLHelloServer
java demo.rmi.SSLHelloClient
It will first contact the RMI registry to find out where to find theMessage from RMI Server: Hello World over SSL!
As mentioned before, the entire communication was secured via SSL/TLS.
See below for more information.
Actually using RMI over SSL is extremely simple. Done in the way explained in this document the only changes required are in the
setup code, and possibly in the use of a different RMI registry.
In short, all that is required is that at the beginning of each application that starts RMI clients, servers, or a registry the SSL policies are set via SSLContexts and a custom socket factory is activated. That’s all. As implemented in the demo this requires just three additional methods which could be used in almost exactly the same way in real world applications, only the certificates and private keys used should be parametrized there.
The assumptions the statements above are based on are:
For more information about the setup required please see the demo
source code, especially the class
SSLRMIUtil.
RMI uses sockets for all network communication. As such it is well suited to be secured using SSL. Because the designers had that in mind and do not instantiate sockets directly and use a SocketFactory instead this is also fairly easy to do. Before we get into that, let us first explain how RMI uses sockets.
This section describes who uses what type of sockets for what purpose. It assumes that no code downloading occurs, see also the note below.
As can be seen from the explanation above, there are two types of
RMI traffic:
In principle both are worth protecting, the second obviously more than
the first, after all this is what we are here to do. The communication
with the RMI registry is not as critical as might appear at first.
Assume an attacker posing as the RMI registry to redirect calls to its own server. If the RMI registry traffic is not secured it can of course easily do so, but the client would detect the
tampering in the server authentication phase of the actual RMI call as that call is secured.
That means, all that can really be achieved is a denial of service attack that prevents the client from making some or any RMI calls, but the same effect can be achieved by preventing the client from connecting to the registry in the first place. The difference is
only when that tampering is detected.
In environments where this is not a concern it is possible to leave RMI registry traffic unprotected. Although there is no immediate way in the RMI API for a SocketFactory to distinguish between sockets created for the RMI registry and sockets created for ordinary RMI calls this can be done by simply checking the port number, assuming the default port 1099 or another port number known in advance is used for the RMI registry. This is demonstrated in the SocketFactory implementation supplied with the demo, see its source.
In case you decide to leave RMI registry traffic unsecured there is actually no longer a need to use the customized registry supplied with the demo. Although the registry’s call to the server in reponse to its registration request will fail (talking plain instead of SSL/TLS) the registration is successful nevertheless. In other words, you can use the standard RMI registry or whatever other registry you want to use, which also allows you to use a common registry for secured and not secured RMI calls. However, remember that
using a secured RMI registry provides some additional security.
As shown, all of the three partners involved in RMI all except the client, which uses client sockets only, use both client and server sockets. That means, assuming strong client and server authentication is always used, they all require the respective certificates. This is reflected in the setup code the demos use.
In the demo implementation this setup is achieved using a single call to
SSLRMIRegistry.setSSLSocketFactory() which performs three things:
Again, note that strictly speaking the SSL RMI registry does not need a client certificate, as noted before. Also note that if you decide to leave RMI traffic unprotected, the server certificates for the RMI registry and the client certificate for the RMI server are not required either. In other words, in that case you only need client certificates on clients
and server certificates on servers.
Some improvements have been made to RMI 1.2. In particular, it is possible to use different SocketFactories for different remote objects. This also makes it possible to use secured and non-secured calls within a single VM.
However, the current demo does not make use of these improvements. As mentioned before this does preclude you from using them in your own applications.
iSaSiLk makes use of the JCA/JCE API for all cryptographic operations. However, it does not use the
getInstance() methods of those API classes directly, rather it uses a SecurityProvider class which centralizes all the various calls. Basically, there are two reasons for that. First, there is is no portable way to perform all required operations. For example, there is no provider indepedent way to construct a Principal object from its DER encoding. Also, some providers do not implement all required features defined in JCA/JCE. The second reason is that the SecurityProvider concept allows for more flexibility and makes it easier to use several providers at the same time.
The important class here is
iaik.security.ssl.SecurityProvider. It contains all the relevant API methods and provides a default SecurityProvider implementation that can be customized to accommodate your needs. Additionally it contains the static setting of the currently active SecurityProvider. It can be set and inspected using the methods
setSecurityProvider() and
getSecurityProvider(), respectively. Note that this is a global setting for the entire VM.
The SecurityProvider class defines a number of constant strings as well
as methods.
Constant strings are defined using the following variable names:
ALG_DIGEST_MD5
ALG_DIGEST_SHA
ALG_DIGEST_SHA256
ALG_DIGEST_SHA384
ALG_HMAC_MD5
ALG_HMAC_SHA
ALG_HMAC_SHA256
ALG_HMAC_SHA384
ALG_SIGNATURE_SHADSA
ALG_SIGNATURE_SHAECDSA
ALG_SIGNATURE_SHA224ECDSA
ALG_SIGNATURE_SHA256ECDSA
ALG_SIGNATURE_SHA384ECDSA
ALG_SIGNATURE_SHA412ECDSA
ALG_SIGNATURE_RAWDSA
ALG_SIGNATURE_MD5RSA
ALG_SIGNATURE_SHA1RSA
ALG_SIGNATURE_SHA224RSA
ALG_SIGNATURE_SHA256RSA
ALG_SIGNATURE_SHA384RSA
ALG_SIGNATURE_SHA512RSA
ALG_KEYPAIR_RSA
ALG_KEYEX_RSA
ALG_KEYEX_DSA
ALG_KEYEX_DSA_CLIENT
ALG_KEYEX_DH
ALG_KEYEX_PSK
ALG_KEYEX_DHE_PSK
ALG_KEYEX_RSA_PSK
ALG_CIPHER_AES
ALG_CIPHER_AES_GCM
ALG_CIPHER_AES_PKCS5
ALG_CIPHER_CAMELLIA
ALG_CIPHER_CAMELLIA_GCM
ALG_CIPHER_RC4
ALG_CIPHER_RC2
ALG_CIPHER_DES
ALG_CIPHER_3DES
ALG_CIPHER_IDEA
ALG_CIPHER_AES
ALG_CIPHER_RSA
ALG_CIPHER_RSA_SIGN
ALG_CIPHER_RSA_VERIFY
ALG_CIPHER_RSA_ENCRYPT
ALG_CIPHER_RSA_DECRYPT
ALG_CIPHER_RSA_ENCRYPT_SSL2
They are used with the respective
getInstance() methods. A special case are the
ALG_CIPHER_RSA_xxx strings. They are used to simplify differentiation between the various types of RSA operations, which is useful particularly for Smartcards (see also iSaSiLk and Smartcards). Usually the same RSA implementation is used in all cases though.
The SecurityProvider class has two constructors. A no-argument constructor, which will create a security provider that searches all JCA installed providers, and a constructor that takes as string argument the name of the only provider to be searched. This is usefull when you want to avoid that implementations from some other provider is used.
The security provider defines the following methods, all of which
have been implemented to work in a provider independent way using
only the JCA/JCE APIs. Note that does not necessarily mean that
they will work with any provider as some providers do not implement
the necessary KeyFactories, etc.
protected boolean isImplemented(String algorithm);
protected DHPublicKey getDHPublicKey(BigInteger y, BigInteger p, BigInteger g) throws Exception;
protected DHPrivateKey getDHPrivateKey(BigInteger x, BigInteger p, BigInteger g) throws Exception;
protected RSAPublicKey getRSAPublicKey(BigInteger modulus, BigInteger publicExponent) throws Exception;
protected X509Certificate getX509Certificate(byte[] array) throws Exception;
protected X509Certificate getX509Certificate(InputStream is) throws Exception;
protected MessageDigest getMessageDigest(String algorithm) throws Exception;
protected Mac getMac(String algorithm, Key key) throws Exception;
protected Signature getSignature(String algorithm, int mode, Key key, SecureRandom random) throws Exception;
protected byte[] calculateRawSignature(String algorithmName, byte[] dataToBeSigned, PrivateKey key, SecureRandom random) throws Exception;
protected boolean verifyRawSignature(String algorithmName, byte[] dataToBeSigned, byte[] signature, PublicKey key);
protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec spec, SecureRandom random) throws Exception;
protected KeyPairGenerator getKeyPairGenerator(String algorithm) throws Exception;
protected SecureRandom getSecureRandom();
public String decodeURL(byte[] encodedCertificateURL) throws Exception;
public byte[] encodeURL(String certificateURL) throws Exception;
public ServerName getTLSServerName(int nameType, byte[] encodedServerName);
public ServerName[] getTLSServerName(int nameType, X509Certificate serverCert);
public ServerName getTLSServerName(int nameType, String name) throws Exception;
Note that the
getCipher(),
getSignature(), and
getMac() must initialize the respective
object before returning it if requested (i.e. mode is not SIGNATURE_NONE,
CIPHER_NONE, key is not null, respectively). This structure was chosen to
allow you to convert keys if your provider can only handle its own keys objects, etc.
For example, for symmetric keys the
SecretKeySpec class is used,
which may not be supported by all providers.
The following two methods could not be implemented in a provider independent way and only
return
null when called. For this particular case the library has been
designed to work without them as well, but note that this disables the more
precise client authentication certificate selection. Therefore, it is recommended
to provide concrete implementations for your provider if possible.
protected Principal getPrincipal(byte[] array) throws Exception;
protected byte[] getEncodedPrincipal(Principal principal);
The following method could not be implemented in a provider independent way and only
return
null when called. For this particular case the library has been
designed to work without them as well, but note that this disables the more
precise server name verification. Therefore, it is recommended
to provide concrete implementations for your provider if possible.
protected String[] getTLSServerName(X509Certificate serverCert);
The following methods could not be implemented in a provider independent way.
They are required when using iSaSiLk with TLS extensions:
protected String[] getTLSServerName(X509Certificate serverCert);
public byte[] createCertStatusRequest(int statusType) throws Exception;
public byte[] createPkiPath(X509Certificate[] certificates) throws Exception;
public SecretKey deriveKey(String algorithm, char[] password, byte[] salt, int iterationCount, int keyLen, String keyName, SecureRandom random) throws Exception;
public byte[] calculateTrustedAuthorityIdentifier(int type, X509Certificate certificate) throws Exception;
Below we provide the source code for the SecurityProvider class.
It is the code from iSaSiLk slightly modified
(comments and constant strings removed, etc.).
public class SecurityProvider {
protected String providerName;
public SecurityProvider() {
this(null);
}
public SecurityProvider(String providerName) {
this.providerName = providerName;
}
protected DHPublicKey getDHPublicKey(BigInteger y, BigInteger p, BigInteger g) throws Exception {
DHPublicKeySpec spec = new DHPublicKeySpec(y, p, g);
KeyFactory factory = (providerName == null) ? KeyFactory.getInstance(“DH”) :
KeyFactory.getInstance(“DH”, providerName);
DHPublicKey key = (DHPublicKey)factory.generatePublic(spec);
return key;
}
protected DHPrivateKey getDHPrivateKey(BigInteger x, BigInteger p, BigInteger g) throws Exception {
DHPrivateKeySpec spec = new DHPrivateKeySpec(x, p, g);
KeyFactory factory = (providerName == null) ? KeyFactory.getInstance(“DH”) :
KeyFactory.getInstance(“DH”, providerName);
DHPrivateKey key = (DHPrivateKey)factory.generatePrivate(spec);
return key;
}
protected RSAPublicKey getRSAPublicKey(BigInteger modulus, BigInteger publicExponent) throws Exception {
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory factory = (providerName == null) ? KeyFactory.getInstance(“RSA”) :
KeyFactory.getInstance(“RSA”, providerName);
RSAPublicKey key = (RSAPublicKey)factory.generatePublic(spec);
return key;
}
protected X509Certificate getX509Certificate(byte[] array) throws Exception {
CertificateFactory factory = (providerName == null) ?
CertificateFactory.getInstance(“X.509”) :
CertificateFactory.getInstance(“X.509”, providerName);
InputStream in = new ByteArrayInputStream(array);
X509Certificate cert = (X509Certificate)factory.generateCertificate(in);
return cert;
}
protected Principal getPrincipal(byte[] array) throws Exception {
return null;
}
protected byte[] getEncodedPrincipal(Principal principal) {
return null;
}
protected MessageDigest getMessageDigest(String algorithm) throws Exception {
return (providerName == null) ? MessageDigest.getInstance(algorithm) :
MessageDigest.getInstance(algorithm, providerName);
}
protected Mac getMac(String algorithm, Key key) throws Exception {
Mac mac = (providerName == null) ? Mac.getInstance(algorithm) :
Mac.getInstance(algorithm, providerName);
if( key != null ) {
mac.init(key);
}
return mac;
}
protected Signature getSignature(String algorithm, int mode, Key key, SecureRandom random) throws Exception {
Signature sig = (providerName == null) ? Signature.getInstance(algorithm) :
Signature.getInstance(algorithm, providerName);
if( mode == SIGNATURE_SIGN ) {
sig.initSign((PrivateKey)key);
} else if( mode == SIGNATURE_VERIFY ) {
sig.initVerify((PublicKey)key);
} // do nothing for SIGNATURE_NONE
return sig;
}
protected byte[] calculateRawSignature(String algorithmName, byte[] dataToBeSigned, PrivateKey key, SecureRandom random) throws Exception {
Cipher cipher = getCipher(algorithmName, CIPHER_ENCRYPT, key, null, random);
byte[] signature = cipher.doFinal(dataToBeSigned);
return signature ;
}
protected boolean verifyRawSignature(String algorithmName, byte[] dataToBeSigned, byte[] signature, PublicKey key) throws Exception {
Cipher cipher = getCipher(algorithmName, CIPHER_DECRYPT, key, null, null);
byte[] received_hash = cipher.doFinal(signature);
return Utils.equalsBlock(dataToBeSigned, received_hash);
}
protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec spec, SecureRandom random) throws Exception {
if( algorithm.startsWith(ALG_CIPHER_RSA) ) {
algorithm = ALG_CIPHER_RSA;
}
Cipher cipher = (providerName == null) ? Cipher.getInstance(algorithm) :
Cipher.getInstance(algorithm, providerName);
if( mode != CIPHER_NONE ) {
int cmode = (mode == CIPHER_ENCRYPT) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
cipher.init(cmode, key, spec, random);
}
return cipher;
}
protected KeyPairGenerator getKeyPairGenerator(String algorithm) throws Exception {
return (providerName == null) ? KeyPairGenerator.getInstance(algorithm) :
KeyPairGenerator.getInstance(algorithm, providerName);
}
protected SecureRandom getSecureRandom() {
return new SecureRandom();
}
protected String[] getTLSServerName(X509Certificate serverCert) {
return null;
}
Basically there are two scenarios:
In the first case the easiest thing to do is to subclass the
IaikProvider class. For example,
package demo;
public class MySecurityProvider extends IaikProvider {
protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec param, SecureRandom random) throws Exception {
if (key instanceof IAIKPKCS11Key) {
if (algorithm.startsWith(ALG_CIPHER_RSA)) {
algorithm = ALG_CIPHER_RSA;
}
cipherEngine = Cipher.getInstance(algorithm, ((IAIKPKCS11Key) key).getTokenManager().getProvider().getName());
if (mode != CIPHER_NONE) {
int cmode = (mode == CIPHER_ENCRYPT) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
cipherEngine.init(cmode, key, param, random);
}
} else {
cipherEngine = super.getCipher(algorithm, mode, key, param, random);
}
}
}
In the second case, i.e. you want to use a different provider altogether
and not use the IAIK JCE at all (for whatever reason 😉 it will be easiest
to start with the
SecurityProvider class and override those
methods where you cannot use the default implementation. It might we
wise to have the IAIK JCE in your
CLASSPATH at first so that
you can use its implementations for those parts you have not changed
to use your provider yet.
To use your own SecurityProvider in your application you only have
to make sure you have all required classes in your
CLASSPATH
and that you activate it at the beginning of your program. This
can be done using, for example:
SecurityProvider.setSecurityProvider(new demo.MySecurityProvider());
Alternatively you may set your security provider via property file. iSaSiLk
first looks if there is a property file with name “SecurityProvider.properties”
located in package iaik.security.ssl. You may set the value of the only “class”
entry to the full name of your provider, e.g.:
class = demo.MySecurityProvider
Of course you also have to make sure your provider is initialized
in whatever way(s) it requires, e.g. add it as a JCE security provider.
This document explains how to secure HTTPS traffic with SSL/TLS using iSaSiLk. We give a quick rundown of the demo and explain how the API can be used.
Basically what the code allows you to do is to use HTTPS URLs with the java.net.URL class, open connections to perform requests and read responses, just like standard HTTP URLs are supported in the JDK.
Note: This document does not give a complete description of all features of Java™ URLs and HttpURLConnections, please refer to the iSaSiLk and JDK JavaDoc files or additional information.
HTTPS is nothing more than the HTTP protocol over SSL/TLS rather than over plain TCP. As such it would be quite easy to add HTTPS to any HTTP implementation given the necessary hooks for the transport are
provided or the source is available.
Unfortunately this is not the case for the HTTP code that comes with the JDK. As developing a stable and fairly complete implementation of HTTP/1.1 would be a serious undertaking and reinventing the wheel is something we prefer to avoid, we decided not to do yet another HTTP implementation and to use the W3C’s HTTP code that comes with their Jigsaw Web server instead (see license
notice).
Essentially what we did was to take the Jigsaw source (current version 2.2.6), remove a lot of classes which are not required for HTTP URL support, and modify a few classes to allow for HTTPS. We provide the result as the JAR file w3c_http.jar which has to be used in addition to
the iSaSiLk iaik_ssl.jar file for HTTPS support.
As a sidenote we would also like to point at that there is at least one third party HTTP implementation that can be used with iSaSiLk to provide HTTPS support. It is called HTTPClient, is free under a LGPL license and available online. Please note that this is a pointer to a possible alternate solution only and not an endorsement of this software. As a matter of fact we have
never evaluated it and of course cannot answer any support questions about it.
This section explains how to actually use HTTPS by describing the demo supplied with the iSaSiLk distribution. Its source is located in HttpsDemo.java example and it is available in
compiled form in the iaik_ssl_demo.jar file.
To try out the demo do the following (assuming you are using the IAIK JCE
as your cryptographic provider and a JDK version on a Windows platform):
set CLASSPATH=%CLASSPATH%;.;lib\iaik_ssl.jar;lib\w3c_http.jar;lib\iaik_jce_full.jar
java demo.https.HttpsDemo https://sic.tech/
Note that the HTTPS code requires w3c_http.jar in addition to
iaik_ssl.jar. The demo then will open a HTTPS connection to https://sic.tech/, display some status information and then print the downloaded HTML page. You can select a different server by passing its URL as argument to the demo.
As shown in the demo using HTTPS is very simple. Summarized, the steps to
follow are:
The HTTPS protocol has to be registered with the java.net
APIs before it can be used. There are several options:
System.getProperties().put("java.protocol.handler.pkgs", "iaik.protocol");
This property can contain a list of packages used to search for protocol handlers. For more information see the JDK documentation for the java.net.URL class. Note that this will not work if a factory is installed,java.net.URL.setURLStreamHandlerFactory(new iaik.protocol.https.HttpsURLStreamHandlerFactory());
For some reason the JDK code allows the factory to be set only once. That means if you environment already has a factory installed for some reason (as usually the case with Applets or Servlets) this code cannot be used either. In that case you can only check the installed factory if it allows other protocols to be added in some way.URL u = new URL(null, "https://...", new iaik.protocol.https.Handler());
Note that all your HTTPS URLs have to be created in this way. Also note that you need not create a new Handler object each time, you can use the same for all URLs.For cases where the above approaches cannot be used we provide a limited workaround. Because HTTPS URLs cannot even be created if no appropriate protocol handler is installed they cannot be used in this case but it is still possible to speak HTTPS via the provided implementation. To do this
create a HTTP (!) URL specifying the target host and port and pass it directly to the constructor of the class iaik.protocol.https.HttpsURLConnection. For example, use code like this:
URL u = new URL("https://sic.tech:443/");
URLConnection connection = new HttpsURLConnection(u);
InputStream in = connection.getInputStream();
Note that you must specify a destination port in this case, you cannot use the default port (80 would be used as for HTTP). Also note that this is a limited workaround only, we recommend using it only if the other options are not available. This problem is due to a limitation in the JDK software and not in ours.
HTTP defines a number of request methods. Most often used is the GET method, which is appropriate to retrieve data from the server. Another request method is POST, which is most usefull to send large amounts of data to the server. iSaSiLk supports both.
However, in difference to the original JDK HTTP implementation the POST method is not automatically chosen if you enable both input and output
for the connection. To use the POST method use code like this:
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
// setup SSL-configuration
con.setSSLContext(context);
con.setRequestMethod(“POST”);
con.setDoInput(true);
con.setDoOutput(true);
OutputStream out = con.getOutputStream();
out.write(“foobar”.getBytes());
out.flush();
InputStream in = con.getInputStream();
Important: Please note the order in which the methods are executed and also that
all data must be written before calling
getInputStream().
For connecting via a proxy the host name and port number of the proxy have to be set as System properties using “https.proxyHost” and
“https.proxyPort” as key words, e.g.:
String proxyHost = ...;
int proxyPort = ...;
System.setProperty("https.proxyHost", proxyHost);
System.setProperty("https.proxyPort", proxyPort);
...
If the proxy requires a user to authenticate him/herself by username and password, this either may be done in the common way by setting a request property on the HttpsURLConnection object or by specifying user name and password via System properties. When setting proxy user name and password via request property you have to use “Https-Proxy-Authorization” as key. The value consists of authentication scheme (“Basic”) and username/password encoding (base64) as
accustomed from normal (proxy) authentication, e.g.:
String authString = "userid:password";
String authMsg = "Basic " + base64encode(authString.getBytes());
URL url = new URL("https://...");
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
...
con.setRequestProperty("Https-Proxy-Authorization", authMsg);
Please ensure to use “Https-Proxy-Authorization” as key only when connecting through a authentication requesting HTTPS proxy! Do not use another key like “Proxy-Authorization” or “Authorization”. It would not be recognized and so may travel to the target server. You may test the behaviour of your proxy by connecting through it to an iSaSiLk server to see what is actually send to the server.
When setting HTTPS proxy user and password via System properties (may not be the recommended way except you are sure that no one else may have access to your client machine), use “https.proxyUser” and
“https.proxyPassword” as keys:
String httpsProxyUser = ...;
String httpsProxyPassword =...;
System.setProperty("https.proxyUser", httpsProxyUser);
System.setProperty("https.proxyPassword", httpsProxyPassword);
Moreover, it is possible to specify a list of hosts for which the library should
not use a proxy. This can be done using the https.nonProxyHosts property. The use is similar to the http.nonProxyHosts property. The value of this property is a ‘|’ separated list of host names. The ‘*’ as wildcard character
is allowed as first character of a name in the list. For example:
System.setProperty("https.nonProxyHosts", "*.tugraz.at|www.iaik.at");
For a host that matches any of the names in this list, the library will establish the connection directly without using the proxy.
This document describes how the TLS protocol uses certificates for authentication and the role of the iSaSiLk library and the application.
The TLS protocol uses public key cryptography for authentication. In all ciphersuites except DH_anon the server is authenticated, client authentication is optional for all ciphersuites except DH_anon. Peer authentication in this case means verification that the peer has access to the private key corresponding to the public key contained in the certificate he provided.
This is part of the TLS protocol and as such performed by the library automatically as configured. What remains for the application is to input its certificates and private keys, specify its algorithm preferences, and, very importantly, verify that the certificate provided by the remote peer is actually trusted.
Note that this document only describes the new framework and not the old model using TrustDeciders. It is still supported for compatibility though, please see the documentation from earlier releases for information about how to use it.
In TLS the types of certificates used are determined by the ciphersuite. For all standard ciphersuites X.509 certificates are used and the following types of certificates are distinguished
Note that we refer to the algorithm
DSA digital signature of an SHA-1hash as DSA while the TLS specification uses the name DSS. Both terms
describe the same algorithm and we use them interchangeably.
DH_RSA and DH_DSS certificates both contain a Diffie-Hellman public key and as such are functionally identical. The distinction based on the certificate signature algorithm is only made to allow a peer to advertise that does or does not implement the RSA or DSA algorithm. In the same way ECDH_RSA and ECDH_ECDSA are functionally identical but the algorithm used to sign the certificate is different.
The server requires certificates if a non-anonymous ciphersuite is used. In iSaSiLk you can set the server certificates using the
addServerCredentials() method of the
SSLServerContext class. You can pass either a PrivateKey object and an array of X509Certificates or a KeyAndCert object (KeyAndCert is a simple class that stores a private key and the corresponding certificate chain), or a KeyStore object (which may
contain multiple server credentials, i.e. private key entries and corresponding certificate chains).. The
addServerCredentials() method automatically determines the type of certificate used and stores it replacing existing credentials of the same type.
Below is a table of the certificate types and the ciphersuites that require its presence to function. Ciphersuites are identified via their TLS keyexchange algorithm.
Certificate type | Key exchange algorithm requiring this type of certificate |
---|---|
RSA | RSA, RSA_EXPORT, RSA_EXPORT1024, DHE_RSA, DHE_RSA_EXPORT, ECDHE_RSA |
DSS | DHE_DSS, DHE_DSS_EXPORT, DHE_DSS_EXPORT1024 |
DH_RSA | DH_RSA, DH_RSA_EXPORT |
DH_DSS | DH_DSS, DH_DSS_EXPORT |
ECDH_RSA | ECDH_RSA |
ECDH_ECDSA | ECDH_ECDSA |
ECDSA | ECDHE_ECDSA |
No certificate | DH_anon, DH_anon_EXPORT, ECDH_anon |
Unless the required certificate is available that ciphersuite cannot be used. Calling
updateCipherSuites() on the SSLServerContext object will
automatically disable all those ciphersuites that cannot be used.
In addition to certificates and a private key some ciphersuites require additional parameters. In particular, DHE ciphersuites require temporary Diffie-Hellman parameters (prime modulus and a generator), and ECDHE ciphersuites require temporary EC parameters (elliptic curve domain parameters, i.e. named_curve). Also exportable RSA ciphersuites require a temporary RSA keypair if the public key in the certificate is longer than the limit for that ciphersuite (i.e. 512 bit for EXPORT, 1024 bit for EXPORT1024).
For DHE and RSA those parameters can be set using the
addTemporaryParameter() method of SSLServerContext. If a temporary parameter is not set but a ciphersuite is chosen in the handshake that requires it defaults are used. For DHE this means pre-generated Diffie-Hellman parameters of 512 or 1024 are used, for
RSA a new 512 or 1024 bit RSA keypair is generated on the fly. For ECDHE the curve is negotiated by means of the SupportedEllipticCurves extension.
RSA keypair generator may take a few seconds, especially for 1024 bit keys. If this is a concern you should not use the defaults and set a temporary keypair manually, but note that the keypair generation will only be performed once per JVM invocation anyway. For additional information about temporary parameters please see the JavaDoc.
The client does not require certificates per se, but as noted above the server may request client authentication and choose not to accept clients with an appropriate certificate.
In TLS client authentication works as follows: during the handshake the server may request a client certificate. While doing that he also specifies which types of client certificates he wants to accept (and same four basic types described above) and optionally which certificate authorities he trusts (he lists their subject distinguished names). Both of this is done to make it easier for the client to choose the correct certificate. The server may also choose not to tell which CAs he trusts and send an empty list instead.
Note that client authentication with RSA, ECDSA and DSS certificates is available for all ciphersuites, DH_RSA and DH_DSS is only available for DH_ ciphersuites, and ECDH_RSA and ECDH_ECDSA is only available for ECDH_ ciphersuites, i.e. those where the server uses (EC)DH certificates as well. These are a special case because the EC(DH) keys cannot be used for signatures and authentication has to be performed differently. For this and other reasons we generally recommend ECDHE, DHE, ECDSA and RSA over (EC)DH.
In iSaSiLk the server can request client authentication by calling
serverContext.setRequestClientCertificate(true). The valid certificate types and trusted CAs are determined automatically. You can also restrict the types of client certificates you wish to accept, e.g. not allow DSS certificates. Use the method
serverContext.setAllowedCertificateTypes(). The trusted certificate authorities are determined using the ChainVerifier’s
getTrustedPrincipalsArray() method, see below for more information about the ChainVerifier class.
For client authentication with iSaSiLk the client only needs to add this private keys and certificates, the library will automatically select the appropriate ones. To add credentials use the
clientContext.addCredentials() method. You can add as many as you want, they will automatically be stored in a database. You can pass either a PrivateKey object and an array of X509Certificates or a KeyAndCert object (KeyAndCert is a simple class that stores a private key and the corresponding certificate chain), or a KeyStore object (which may contain multiple client credentials, i.e. private key entries and corresponding certificate chains).
During the handshake the library code calls the
clientContext.getClientCredentials() method to retrieve client certificates. If you want to implement your own storage mechanism you only need to override this method.
There are two basic parts to verifying trust: (a) specifying which certificates (and CA trees) to trust and (b) a profile to follow when verifying certificate chains.
In iSaSiLk this is handled by the ChainVerifier class. It also you to specify trusted certificates and its code implements a basic X.509v1 style profile to verify certificate chains. It can be replaced by a more advanced implementation if desired, for example it would be possible to use the IAIK Trust Manager. For information about custom ChainVerifier please see the JavaDoc API documentation.
You can specify trusted certificates by calling e.g.
context.addTrustedCertificate(), which is a shorthand for
context.getChainVerifier().addTrustedCertificate(). The library code will call the ChainVerifier during the handshake as described below.
The client verifiers that the server has an acceptable certificate. The following cases arise (assuming the default ChainVerifier implementation is used):
For more information please the the JavaDoc for the ChainVerifier class.
The client verifiers that the server has an acceptable certificate. The following cases arise (assuming the default ChainVerifier implementation is used):
For more information please the the JavaDoc for the ChainVerifier class.
Some TLS extensions may require an additional/alternative key or certificate handling. If, for instance, the client sends an OCSP certificate
status_request extension to the server, it may have to validate the OCSP status response sent back by the server. In this case the alternative
OCSPCertStatusChainVerifier maybe enabled to check the OCSP response got from the server:
SSLClientContext clientContext = new SSLClientContext();
OCSPCertStatusChainVerifier ocspChainVerifier = new OCSPCertStatusChainVerifier();
clientContext.setChainVerifier(ocspChainVerifier);
See the iSaSiLk
TLS extensions (143.81 kB)
This document gives information about interoperability with other SSL/TLS implementations and notes to SSL 2.0.
iSaSiLk supports several versions of the SSL/TLS protocol (SSL 2.0 on the client, SSL 3.0, TLS 1.0 and TLS 1.1 on both client
and server side). SSL 2.0 is disabled by default for security reasons and should only be enabled if it is actually needed.
The SSL/TLS protocol ensures that always the highest protocol version supported by both the client and the server is used.
Therefore, most applications should never need to care about version selection. However, this may not work correctly
with certain very few buggy implementations. In this case you might want to disable a protocol version. This is done using
the
setAllowedProtocolVersion() method in the
SSLContext.
Per default SSL 3.0, TLS 1.0 and TLS 1.1 are enabled for both clients and server, SSL 2.0 is not enabled, see the section on SSL 2.0
for more information
Once the handshake has been completed you can call the
getActiveProtocolVersion() method of
your SSLSocket to retrieve the selected SSL version.
iSaSiLk also supports SSL 2.0 on the client side, server side SSL 2.0 is NOT supported. It was implemented to allow communication
with a few remaining old server implementations that do not support SSLv3. Server side support for SSLv2 should never be needed
as virtually all clients long support SSLv3.
SSLv2 is a very mediocre security protocol and has several known flaws and design limitations. Therefore, it is disabled by default. It should
only be enabled if you want to communicate with a server that does not support SSLv3.
A few of the limitations of SSL 2.0 are:
In iSaSiLk SSLv2 enabled ciphersuites are not manually set. Rather they are computed automatically from the enabled v3 suites. That means that
if v2 is enabled the list of enabled v3 suites is checked and if a given enabled v3 ciphersuite has an equivalent in v2 that is automatically enabled.
These equivalents are:
SSLv3 Ciphersuite | SSLv2 Equivalent Ciphersuite |
---|---|
SSL_RSA_WITH_3DES_EDE_CBC_SHA | SSL2_RSA_WITH_DES_192_EDE3_CBC_MD5 |
SSL_RSA_WITH_IDEA_CBC_SHA | SSL2_RSA_WITH_IDEA_128_CBC_MD5 |
SSL_RSA_WITH_RC4_MD5 | SSL2_RSA_WITH_RC4_128_MD5 |
PRIVATE_RSA_WITH_RC2_CBC_MD5 | SSL2_RSA_WITH_RC2_128_CBC_MD5 |
SSL_RSA_WITH_DES_CBC_SHA | SSL2_RSA_WITH_DES_64_CBC_MD5 |
SSL_RSA_EXPORT_WITH_RC4_40_MD5 | SSL2_RSA_WITH_RC4_128_EXPORT40_MD5 |
SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 | SSL2_RSA_WITH_RC2_128_CBC_EXPORT40_MD5 |
As you can see there is an equivalent v3 ciphersuite for each v2 ciphersuite (SHA is used instead of MD5 several times) except for
SSL2_RSA_WITH_RC2_128_CBC_MD5. In this case a private ciphersuite with the v3 id 0xFF5B was defined as an equivalent. This ciphersuite
PRIVATE_RSA_WITH_RC2_CBC_MD5 can also be used in v3 mode but this is not recommended.
Fairly extensive interoperability testing has been performed between iSaSiLk and other SSL/TLS compliant implementations. Some minor problems
have been fixed and there are no known interoperability problems except for those listed below. Note that because iSaSiLk fully supports all aspects
of SSL3.0/TLS1.0/TLS1.1 iSaSiLk is interoperable with any other standard compliant implementation no matter which algorithms it supports and has enabled.
No problems were detected in tests with the following implementations:
Some notes apply to the following implementations:
Some servers do not recognize the SSL 3.0 and TLS 1.0 combined client hello format correctly (although they should).
In those cases it may be necessary to either disable TLS 1.0 or to enable
SSL 2.0 in addition (they seem to better cope with the different SSLv2 hello messages).
That means try
context.setAllowedProtocolVersions(SSLContext.VERSION_SSL30, SSLContext.VERSION_SSL30);
or possibly
context.setAllowedProtocolVersions(SSLContext.VERSION_SSL20, SSLContext.VERSION_TLS10);
Unfortunately a number of servers, seemingly including most or all versions of the Microsoft IIS server, do not correctly shutdown
the SSL/TLS layer before closing the connection on the TCP level. This will cause EOFExceptions to be thrown and also cause
iSaSiLk to invalidate the session resulting in a full handshake for each connection and consequently lower performance.
Note that this is a bug in those server implementations and not in iSaSiLk! Anyway, as a workaround we offer an SSLContext setting
that allows you to ignore this (i.e. no EOFException will be thrown and the session is cached as usually). To active this workaround
use code like
context.setCacheTerminatedSessions(true);
Note that when activated you may be vulnerable to truncation attacks. Note also
that TLS 1.0 (RFC 2246) does not allow to resume incorrectly terminated
sessions. However, since closing TLS sessions without correct shutdown
is a common practice, TLS 1.1 (RFC 4346) does no longer require to invalidate
incorrectly terminated sessions. For that reason, the default behaviour of
iSaSiLk is different for TLS 1.1 (incorrectly terminated sessions are cached)
and protocol versions prior TLS 1.1 where incorrectly terminated sessions
cause an EOF exception and are not cached by default. You may explicitly call
the
setCacheTerminatedSessions method if you want to enforce the
same behaviour for all protocol versions.
Extensions for the TLS protocol have been introduced by RFC 3546, 4366. iSaSiLk supports all standard extensions
specified by RFC 3546 (and additionally the
session_ticket extension defined in RFC 4507)
and has been successfully tested against the following extension supporting browsers :
The SessionTicket extension has been introduced by RFC 4507 (“TLS Session Resumption without Server-Side State”). However, the SessionTicket encoding has been changed from RFC 4507 to its successor draft RFC 4507bis which simply puts the ticket into the extension_data field since done so by most applications. iSaSiLk 4.1 now also uses the 4507bis format when sending a SessionTicket extension, but is able to parse both, the 4507 and 4507bis format. According to RFC 4507bis iSaSiLk now also uses SHA-256 as hash algorithm
for HMAC-protecting the ticket instead of SHA-1 as has been used by RFC 4507.
The RenegotiationInfo extension has been introduced by RFC 5746 as countermeasure against renegotiation attacks. Depending on the deploymaent of RenegotiationInfo supporting TLS applications, interoperability problems may occur during a certain transition period. See here for further information about use and configuration options
of the RenegotiationInfo extension.
The most recent versions of Mozilla Firefox and Microsoft Internet Explorer on Windows Vista both support elliptic curve cipher suites. Both browsers make use of the SupportedEllipticCurves and SupportedPointFormat extensions with named curves secp256r1, secp384r1 and secp521r1 and uncompressed point format, all supported and by default used by iSaSiLk.
This document describes how to use the iSaSiLk library to perform secure renegotiation.
In November 2009 Marsh Ray and Martin Rex independently discovered a serious vulnerability in the SSL/TLS renegotiation protocol which does not provide any cryptographic binding of the renegotiation handshake to the corresponding TLS channel. An attacker may exploit this vulnerability and establish a regular TLS connection with a server, exchange some data with it, and then splice in a connection with an innocent client who starts a new handshake with the server. The server, however, interprets this initial handshake as renegotiation and thinks that any data received so far has come from the client (and not from the attacker).
There may be variants of the attack possible where an initial handshake of the server is interpreted as renegotiation handshake by the client.
As a countermeasure against this attack (and its possible derivatives) the IETF TLS working group has developed a new TLS extension,
RenegotiationInfo (RFC 5746), to establish a cryptographic binding of the renegotiation handshake to the corresponding TLS channel. When successfully exchanging and verifying the
RenegotiationInfo extension, client and server know whether they perform an initial or renegotiating handshake and if they actually renegotiate the cryptographic parameters of the corresponding TLS connection.
For further information see http://extendedsubset.com/?p=8,
http://www.ietf.org/mail-archive/web/tls/current/msg03928.html , and RFC 5746.
RFC 5746 defines the RenegotiationInfo extension as an opaque structure that may be empty (initial handshake) or (renegotiating handshake) may carry verification data for checking the cryptographic binding to the enclosing TLS connection:
struct {
opaque renegotiated_connection<0..255>;
} RenegotiationInfo;
On the beginning of an initial handshake the client sends a ClientHello message containing a RenegotiationInfo extension with an empty renegotiated_connection field. The server, when parsing the ClientHello message, knows that the client is able to perform secure renegotiation (because the ClientHello message contains the RenegotiationInfo extension) and that the ClientHello message belongs to an initial handshake (because the renegotiated_connection field of the RenegotiationInfo extension is empty). The server now also includes an RenegotiationInfo extension with an empty
renegotiated_connection field into its ServerHello message to let the client know that it also is able to perform secure renegotiation.
Later, when client or server decide to perform a renegotiation, they exchange ClientHello and ServerHello messages containing RenegotiationInfo extensions with a non-empty renegotiated_connection field that carries verification data from the Finished messages of the immediately previous handshake. Successfully verification of this data ensures that the renegotiation corresponds to the enclosing TLS connection and the handshake can be securely continued. Otherwise, if the verification fails, the renegotiation handshake may be under attack and has to be aborted immediately by sending a fatal handshake failure alert.
A TLS handshake may be also aborted by any of the following reasons:
For interoperability with SSLv3- and TLS-Servers that do not support extensions yet, RFC 5746 provides an alternative way for the client to signal its ability to perform secure renegotiation. Instead of including an empty RenegotiationInfo extension into the
ClientHello message of an initial handshake, the client may add the special signalling cipher suite value (SCSV) “TLS_EMPTY_RENEGOTIATION_INFO_SCSV” withID {0x00, 0xFF} to the list of its cipher suites. When parsing this special cipher suite value, the server knows that the client supports the
RenegotiationInfoextension and safely can include it into its
ServerHello message to tell the client that it is also able to perform secure renegotiation. The SCSV cipher suite has no other meaning or purpose than announcing the ability to perform secure renegotiation. It can only be sent within an initial handshake and is simply ignored by (and does not break) servers that do not support TLS extension.
By default iSaSiLk uses the RenegotiationInfo extension as described above. At the beginning of a handshake an iSaSiLk client announces its ability for secure renegotiation by either sending an empty RenegotiationInfo extension or including the special SCSV cipher suite value into its cipher suite list. The RenegotiationInfo extension is only sent if the client application has
configured iSaSiLk to use any further extensions (like, for instance,
ServerName). If the client application does not want to use extensions, iSaSiLk does not send the
RenegotiationInfo extension, but includes the SCSV cipher suite value. This ensures that the server will not break if it does not support extensions. However, if the server does not respond with a RenegotiationInfo extension, the client cannot know if an attacker already has launched a renegotiation attack and therefore iSaSiLk will abort the handshake immediately by sending a fatal
handshake failure alert to the server. In the same way, an iSaSiLk server by default will immediately abort an initial handshake with a fatal handshake failure alert if the ClientHello message neither contains the RenegotiationInfo extension nor the SCSV cipher suite value. Both, iSaSiLk clients and iSaSiLk servers will not continue an (initial or renegotiating) handshake if they notice that the peer does not use the RenegotiationInfo extension correctly (for instance non-empty extension at initial handshake, empty extension at renegotiating handshake) or that the RenegotiationInfo extension of a renegotiating handshake contains an invalid or wrong
renegotiated_connection value. In all these situations the handshake will be aborted immediately by sending a fatal handshake failure alert.
All
RenegotiationInfo extension and the SCSV cipher suite value handling is done transparently to the user. iSaSiLk manages the RenegotiationInfo extension as “hidden” extension. It must not be set by the application and cannot be accessed by the application. All required secure renegotiation processing is done automatically. You only will recognize something about it if you turn on and watch
the debug output or if you get an exception because the handshake fails because of missing or incorrect use of the RenegotiationInfo extension.
A typical initial and renegotiation client-server handshake course may look like:
Client:
Starting handshake...
ssl_debug(1): Starting handshake (iSaSiLk 4.4)...
ssl_debug(1): Sending v3 client_hello message to localhost:443, requesting version 3.2...
ssl_debug(1): Received v3 server_hello handshake message.
ssl_debug(1): Server selected SSL version 3.2.
ssl_debug(1): Server created new session 4A:B7:09:06:F3:35:BA:5E...
ssl_debug(1): CipherSuite selected by server: SSL_RSA_WITH_3DES_EDE_CBC_SHA
ssl_debug(1): CompressionMethod selected by server: NULL
ssl_debug(1): TLS extensions sent by the server: renegotiation_info (65281)
ssl_debug(1): Server supports secure renegotiation.
ssl_debug(1): Received certificate handshake message with server certificate.
ssl_debug(1): Server sent a 1024 bit RSA certificate, chain has 3 elements.
ssl_debug(1): Received server_hello_done handshake message.
ssl_debug(1): Sending client_key_exchange handshake...
ssl_debug(1): Sending change_cipher_spec message...
ssl_debug(1): Sending finished message...
ssl_debug(1): Received change_cipher_spec message.
ssl_debug(1): Received finished message.
ssl_debug(1): Session added to session cache.
ssl_debug(1): Handshake completed, statistics:
ssl_debug(1): Read 2538 bytes in 3 records, wrote 254 bytes in 4 records.
ssl_debug(1): Acquiring locks for renegotiation...
ssl_debug(1): Starting renegotiation...
ssl_debug(1): Sending v3 client_hello message to localhost:443, requesting version 3.2...
ssl_debug(1): Sending extensions: renegotiation_info (65281)
ssl_debug(1): Received v3 server_hello handshake message.
ssl_debug(1): Server selected SSL version 3.2.
ssl_debug(1): Server created new session FD:15:DD:D5:11:1E:6A:B6...
ssl_debug(1): CipherSuite selected by server: SSL_RSA_WITH_3DES_EDE_CBC_SHA
ssl_debug(1): CompressionMethod selected by server: NULL
ssl_debug(1): TLS extensions sent by the server: renegotiation_info (65281)
ssl_debug(1): Received certificate handshake message with server certificate.
ssl_debug(1): Server sent a 1024 bit RSA certificate, chain has 3 elements.
ssl_debug(1): Received server_hello_done handshake message.
ssl_debug(1): Sending client_key_exchange handshake...
ssl_debug(1): Sending change_cipher_spec message...
ssl_debug(1): Sending finished message...
ssl_debug(1): Received change_cipher_spec message.
ssl_debug(1): Received finished message.
ssl_debug(1): Session added to session cache.
ssl_debug(1): Renegotiation completed, statistics:
ssl_debug(1): Read 2623 bytes in 3 records, wrote 372 bytes in 4 records.
ssl_debug(1): Shutting down SSL layer...
ssl_debug(1): Sending alert: Alert Warning: close notify
ssl_debug(1): Read 501 bytes in 1 records, 466 bytes net, 466 average.
ssl_debug(1): Wrote 53 bytes in 1 records, 18 bytes net, 18 average.
ssl_debug(1): Closing transport...
Server:
ssl_debug(1): Starting handshake (iSaSiLk 4.4)...
ssl_debug(1): Received v3 client_hello handshake message from localhost/127.0.0.1.
ssl_debug(1): Client supports secure renegotiation.
ssl_debug(1): Client requested SSL version 3.2, selecting version 3.2.
ssl_debug(1): Creating new session 4A:B7:09:06:F3:35:BA:5E...
ssl_debug(1): CipherSuites supported by the client:
ssl_debug(1): SSL_RSA_WITH_3DES_EDE_CBC_SHA
ssl_debug(1): SSL_RSA_WITH_IDEA_CBC_SHA
ssl_debug(1): SSL_RSA_WITH_RC4_128_SHA
ssl_debug(1): CompressionMethods supported by the client:
ssl_debug(1): NULL
ssl_debug(1): Sending server_hello handshake message.
ssl_debug(1): Selecting CipherSuite: SSL_RSA_WITH_3DES_EDE_CBC_SHA
ssl_debug(1): Selecting CompressionMethod: NULL
ssl_debug(1): Selecting extensions: renegotiation_info (65281)
ssl_debug(1): Sending certificate handshake message with 1024 bit RSA server certificate...
ssl_debug(1): Sending server_hello_done handshake message...
ssl_debug(1): Received client_key_exchange handshake message.
ssl_debug(1): Received change_cipher_spec message.
ssl_debug(1): Received finished message.
ssl_debug(1): Sending change_cipher_spec message...
ssl_debug(1): Sending finished message...
ssl_debug(1): Session added to session cache.
ssl_debug(1): Handshake completed, statistics:
ssl_debug(1): Read 254 bytes in 4 records, wrote 2538 bytes in 3 records.
ssl_debug(1): Acquiring locks for renegotiation...
ssl_debug(1): Starting renegotiation...
ssl_debug(1): Received v3 client_hello handshake message from localhost/127.0.0.1.
ssl_debug(1): Client requested SSL version 3.2, selecting version 3.2.
ssl_debug(1): Creating new session FD:15:DD:D5:11:1E:6A:B6...
ssl_debug(1): CipherSuites supported by the client:
ssl_debug(1): SSL_RSA_WITH_3DES_EDE_CBC_SHA
ssl_debug(1): SSL_RSA_WITH_IDEA_CBC_SHA
ssl_debug(1): SSL_RSA_WITH_RC4_128_SHA
ssl_debug(1): CompressionMethods supported by the client:
ssl_debug(1): NULL
ssl_debug(1): TLS extensions sent by the client: renegotiation_info (65281)
ssl_debug(1): Sending server_hello handshake message.
ssl_debug(1): Selecting CipherSuite: SSL_RSA_WITH_3DES_EDE_CBC_SHA
ssl_debug(1): Selecting CompressionMethod: NULL
ssl_debug(1): Selecting extensions: renegotiation_info (65281)
ssl_debug(1): Sending certificate handshake message with 1024 bit RSA server certificate...
ssl_debug(1): Sending server_hello_done handshake message...
ssl_debug(1): Received client_key_exchange handshake message.
ssl_debug(1): Received change_cipher_spec message.
ssl_debug(1): Received finished message.
ssl_debug(1): Sending change_cipher_spec message...
ssl_debug(1): Sending finished message...
ssl_debug(1): Session added to session cache.
ssl_debug(1): Renegotiation completed, statistics:
ssl_debug(1): Read 372 bytes in 4 records, wrote 2623 bytes in 3 records.
ssl_debug(1): Shutting down SSL layer...
ssl_debug(1): Sending alert: Alert Warning: close notify
ssl_debug(1): Read 53 bytes in 1 records, 18 bytes net, 18 average.
ssl_debug(1): Wrote 501 bytes in 1 records, 466 bytes net, 466 average.
ssl_debug(1): Closing transport...
As discussed above, a TLS client – for being sure to be not vulnerable to renegotiation
attacks – has to abort a handshake with a fatal handshake failure alert if a server does
not send the RenegotiationInfo extension within its initial
ServerHello message. In the same way, a TLS server has to abort an initial handshake with a fatal handshake failure alert if the ClientHello message neither contains the
RenegotiationInfo
extension nor the SCSV cipher suite value.
This means that by default no SSL/TLS communication is possible if the peer does not support secure
renegotiation. Although this is the recommended behaviour from the security point of view, it might
cause interoperability problems with servers/clients that do not support the
RenegotiationInfo extension yet. Since deployment of patched TLS implementations cannot start before the final release of RFC 5746, it will take a certain transition period until the majority of available TLS applications will be able to understand the secure renegotiation protocol. Especially
during this transmission period there may be a certain (for instance, economic) requirement for being still able to talk with unpatched TLS client or servers.
This section describes the configuration options allowing an application to control the
renegotiation handling of the iSaSiLk library. Each option can be dynamically set (or unset)
by calling a particular method of the SSLContext class, or can be statically configured by editing a SSLContext.properties file and packing it with iaik_ssl.jar file (or putting it elsewhere in the classpath). Any static configuration via SSLContext.properties file is globally valid for the entire application scope. Dynamical configuration settings are only valid for the particular SSLContext to which they have been applied. The SSLContext.properties file has to be located in the package iaik.security.ssl. A sample property and iSaSiLk jar file allowing to communicate with unpatched TLS applications is contained in the lib/legacy-renegotiation folder of your iSaSiLk distribution.
sslContext.setAllowLegacyRenegotiation(true);
Configuration via allowLegacyRenegotiation=true
Default value: sslContext.setUseNoRenegotiationWarnings(true) ;
Configuration via useNoRenegotiationWarnings=true
Default value: sslContext.setAllowIdentityChangeDuringRenegotiation(false);
Configuration via allowIdentityChangeDuringRenegotiation=false
Default value: sslContext.setDisableRenegotiation(true);
Configuration via disableRenegotiation=true
Default value:A more finely granulated configuration option is provided by the iSaSiLk SecurityProvider method continueIfPeerDoesNotSupportSecureRenegotiation. iSaSiLk calls this method during an (initial or renegotiation) handshake to check if legacy renegotiation is allowed or not when the peer does not support secure renegotiation according to RFC 5746.
By default this method will check the SSLContext configuration (as described
above) and throw an SSLException if legacy renegotiation is not allowed. This means
that — if the default configuration is used — at the client side an intial handshake
with a server that does not send the RenegotiationInfo extension will be aborted immediately with a fatal handshake failure alert. On the server side an initial handshake will also be aborted immediately if the client does not send the RenegotiationInfo extension or SCSV cipher
suite value.
You may override the SecurityProvider method continueIfPeerDoesNotSupportSecureRenegotiation if you do not want to use the default behaviour/configuration or, for instance, want to decide on case-by-case basis whether to continue or not. For instance, a client application may pop-up a warning dialag to inform the user that the server has not send the
RenegotiationInfoextension (may be only appropriate for expierenced users), or may maintain a
white list with server names for which legacy renegotiation is allowed, e.g.:
/**
* Simple demo SecurityProvider implementation for a client}
* that generally enforces secure renegotiation according
* RFC 5746 but allows legacy renegotiation with some
* specific, explcitily listed sites.
*/
public class RISecurityProvider extends IaikProvider {
/**
* Repository of sites to which legacy renegotiation
* shall be allowed.
*/
Hashtable legacyRenegotiationSites_;
/**
* Default constructor.
*/
public RISecurityProvider() {
super();
legacyRenegotiationSites_ = new Hashtable();
}
/**
* Adds a site (server) name with which legacy
* renegotiation shall be allowed.
*
* @param severName the site (server) name
*/
public void addSite(String serverName) {
if (serverName != null) {
legacyRenegotiationSites_.put(serverName, serverName);
}
}
/**
* Removes a site (server) name with which legacy
* renegotiation shall be not allowed.
*
* @param severName the site (server) name
*/
public void removeSite(String serverName) {
if (serverName != null) {
legacyRenegotiationSites_.remove(serverName);
}
}
/**
* Throws a SSLException if a server that does not support
* secure renegotiation (or tries a legacy renegotiation),
* but the server name is not contained in the list of sites
* with which legacy renegotiation is allowed.
*
*
* @param transport the SSLTransport to maybe used for getting
* information about the remote peer
* @param renegotiation whether this method is called during an
* initial or during a renegotiation handshake
*
* @exception SSLException if a server that does not support secure
* renegotiation (or tries a legacy renegotiation),
* but is not contained in the list of sites with
* which legacy renegotiation is allowed
*/
public void continueIfPeerDoesNotSupportSecureRenegotiation(SSLTransport transport,
boolean renegotiation)
throws SSLException {
String serverName = transport.getRemotePeerName();
if ((serverName != null) && (legacyRenegotiationSites_.get(serverName) != null)) {
transport.debug(“Server ” + serverName + ” did not send RenegotiationInfo extension. Continue anyway.”);
} else {
throw new SSLException(“Server did not send RenegotiationInfo extension.”);
}
}
}
For a more detailed description of the several configuraton options see the Javadoc documentation of the SSLContext class. Please note that full protection can only be achieved when not allowing any communication with clients/servers that do not support the
RenegotiationInfo extension. For that reason the default configuration of iSaSiLk does not allow to communicate with unpatched peers that are not able to perform secure renegotiation.
You want to know what SSL/TLS-capabilites you browser has? Want to find out about the SSL/TLS-features of some Web-Server? We provide two demos, that do that job for you!
The demos are included in our IAIK iSaSiLk Toolkit, one for testing the SSL/TLS capcabilities of your browser, the other for testing the capabilities of your server. Both demos can be run as servlets or as stand alone applications.
After downloading and unpacking the iSaSiLk distribution file you simply have to browse to the
demo/cmd or
demo/sh sub-directory and follow the steps described below.
Browser Test:
Waiting for HTTPS requests on port 4433…
If everything works well the SSL/TLS browser capabilities will be dumped in your browser window.
Server Test:
Waiting for HTTP requests on port 80…
A form field will be shown in your browser window where you can enter the https address of the server for which you want to know its SSL/TLS capabilities.
Class or Package | Bug / Change / New Feature | Description and Examples |
---|---|---|
NF | Implementation of the TLS 1.3 protocol according to RFC 8446 added. All core and some optional features of the protocol are implemented. Some optional features like Zero Round-Trip 0-RTT Early Data are yet not supported. |
|
CipherSuite | C | Changed state of 3DES-EDE and RC4 cipher suites from default to implemented. |
ExtensionList | NF, C | New method |
ServerNameList | C | For interoperability reasons a client-side critical ServerNameList extension does not cause the handshake to be aborted anymore. |
SignatureAlgorithms | C | Now marked as critical by default meaning that the handshake is aborted if the peer uses a signature algorithm that has not been suggested. |
SignatureAndHashAlgorithmList, SignatureSchemeList | C | Removed DSA signature algorithms from the default set. Added ED25519 in default set. Moved ED25519 to second position in all algorithms set. |
SSLServerContext | C | Default domestic DH parameters set to ffdhe2048 from RFC 7919. |
Class or Package | Bug / Change / New Feature | Description and Examples |
---|---|---|
* | NF | Implementation of the TLS 1.3 protocol according to RFC 8446 added. All core and some optional features of the protocol are implemented. Some optional features like Zero Round-Trip 0-RTT Early Data are yet not supported. |