SSL and SocketChannel - java

Ideally, I only need a simple SSLSocketChannel.
I already have a component that reads and writes message over ordinary SocketChannel, but for some of these connections, I have to use SSL over the wire; the operations over these connections, however, are the same.
Does anyone knows a free SSLSocketChannel implementation (with the appropriate selector) or something similar? I've found this, but the selector doesn't accept it since its vendor isn't SUN.
I'm decoupling the reading_from/writing_to net logic from the insertion and retrieval of network data via a simple object, in order to use a SSLEngine without getting mad, but it's really tricky to implement that correctly, given the fact that I don't know the internals of SSL protocol...

Jetty has an NIO SSL implementation for their server: SslSelectorChannelConnector. You might want to peek at it for details on what its doing.
There is also an old (but decent) article from O'Reilly that explains the details about NIO + SSL along with example code.

TLS Channel is a simple library that does exactly that: wrapping a SSLContext (or SSLEngine) and exposing a ByteChannel interface, doing the heavy lifting internally.
(Disclaimer: I am the library's main author).

Check out Restlet's implementation it may do what you need, and it's all about NIO.
Restlet Engine Javadoc
Specifically the HttpClientCall. SetProtocol(HTTPS) - getResponseEntityChannel returns a ReadableByteChannel (getEntityChannel returns a WriteableByteChannel)

Not sure if this is what you're looking for, but may help... To create SSL/TLS enabled server sockets, I'm currently using code like the following (keystore.jks contains a self signed private/public key pair used for securing confirmation) - clients have a similar trust store which contains the signed certificate with the public key of that pair.
A bit of googling around getting that configured should get you underway.
String keyStorePath = "keystore.jks";
String keyStorePassword = "password";
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = new KeyStore();
keyStore.load(new FileInputStream(keyStorePath), keyStorePassword);
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
SSLContext sslContext = getServerSSLContext(namespace.getUuid());
SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory();
// Create sockets as necessary

Related

Does Java Check cRLSign KeyUsage bit for CRL Issuing Certificates?

I'm using Java implementation for revocation checking using CRL which is like the following code (I tailored the code to be short and clear)
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
rc.setOptions(EnumSet.of(
PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.ONLY_END_ENTITY,
PKIXRevocationChecker.Option.NO_FALLBACK,
PKIXRevocationChecker.Option.SOFT_FAIL));
PKIXBuilderParameters pkixParams =
new PKIXBuilderParameters(getTrustStore(), new X509CertSelector());
pkixParams.setRevocationEnabled(false);
pkixParams.addCertPathChecker(rc);
tmf.init(new CertPathTrustManagerParameters(pkixParams));
SSLContext contect = SSLContext.getInstance("TLSv1.2");
context.init(null, getTrustManagers(), null);
defaultFactory = context.getSocketFactory();
The above code is in the constructor of a custom SSLSocketFactory, and there is a custom TrustManager (returned by getTrustManagers()) which overrides checkServerTrusted() to perform a few certificate checks and executes default checkServerTrusted() at the end.
Everything works fine except that I need that validation of CRL to be failed when it is signed by a CA that does not have the cRLsign key usage
bit set, but it doesn't.
I know that this is a requirement by RFC3280, and somewhere on the web I read that Java implementation is compliant with the RFC and I even saw the methods in the Java base code to do that, But it seems it does not come into play when I run the application.
I did all the revocation checking with a custom code to achieve that but I think Java implementation is way more complete that my custom code and I strongly prefer to use Java implementation.
Any solution?

SSL/TLS dynamic key generation

On this project of mine I needed to implement secure connection using SSL/TLS between a client and a server. I found a good article about that so I've managed to do my task without any problem.
This is the article.
My question is pretty simple but I cannot find an answer anywhere. In this particular case, my clients have the same key in the SSL protocol which is created through tutorial on a previous link and put in some kind of a file. Potential problem in this process is that someone can access that file and since every client has that key, someone can listen to all connections.
What I wanted to ask, is there any chance to dynamically generate keys every time some client wants to access the server and put the generated key in the server truststore?
UPDATE
public static final String PATH_TO_ANDROID_KEYSTORE = "and/client.bks";
public static final String PATH_TO_ANDROID_TRUSTSTORE = "and/clienttruststore.bks";
String pathToKeyStore = PATH_TO_ANDROID_KEYSTORE;
String pathToTrustStore = PATH_TO_ANDROID_TRUSTSTORE;
KeyStore keyStoreKeys = KeyStore.getInstance(keyStoreType);
keyStoreKeys.load(Gdx.files.internal(pathToKeyStore).read(), passphrase);
KeyStore keyStoreTrust = KeyStore.getInstance(keyStoreType);
keyStoreTrust.load(Gdx.files.internal(pathToTrustStore).read(), passphrase);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStoreKeys, passphrase);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStoreTrust);
This is the client code and seems like clients have exported server's certificates in their truststores but they actually use the same private key that is generated only once in the keystore using openssl tool.
In this particular case, my clients have the same key in the SSL protocol which is created through tutorial on a previous link and put in some kind of a file.
Unclear. Do you mean they share the same private key? If so, that is a flaw in your system design. Every client should have its own private key. Otherwise the private key isn't, err, private. And access to that key should be via a keystore whose password only the applicion knows, which provides at least another line of defence.
If you just mean that they all have an exported copy of the server's certificate, in their truststores, there is no security risk attached to that at all: it is perfectly normal.
Potential problem in this process is that someone can access that file and since every client has that key, someone can listen to all connections.
No they can't. SSL is immune to man-in-the-middle attacks provided you don't compromise your server's private key, but if you're talking about client private keys they can masquerade as a real client even if they aren't, if they can break through the keystore-password barrier.
What I wanted to ask, is there any chance to dynamically generate keys every time some client wants to access the server and put the generated key in the server truststore?
Not securely, and not online. If your genuine clients can do it, so can an attacker. That's why trust material must be distributed offline.

TrustStore and Keystore during 2 way SSL validation

I have been unable to find a solution to this problem elsewhere so I am hoping someone here can provide some insight. My setup below:
keystore, myKeys.jks:
mine-private, 3/6/2014, PrivateKeyEntry
mine-trusted, 3/6/2014, trustedCertEntry
trust store, myTrust.jks:
trusted-cert-1, 3/6/2014, trusterCertEntry
trusted-cert-2, 3/6/2014, trusterCertEntry
mine-trusted, 3/6/2014, trustedCertEntry <-- this is mine
What ends up happening is I get a message stating that my client has not been authenticated. Let me know if there is more information necessary
Responses to questions:
First off: what classes/library are you using? Simply the default https in java?
Apache HTTP Client, code below:
HttpClient client = new HttpClient();
GetMethod method = new GetMethod("https://foo.bar.baz/rest");
client.executeMethod(method);
Secondly: how exactly are you registering the keystore/truststore? You need a custom SSLContext for this.
Don't think so, but could be wrong
-Djavax.net.ssl.trustStore="path/to/myTrust.jks"
-Djavax.net.ssl.trustStorePassword="password"
-Djavax.net.ssl.keyStore="path/to/myKeys.jks"
-Djavax.net.ssl.keyStorePassword="password"
First off: what classes/library are you using? Simply the default https in java?
Secondly: how exactly are you registering the keystore/truststore? You need a custom SSLContext for this.
Initial example:
SSLContext context = SSLContext.getInstance();
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, password);
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
context.init(keyFactory.getKeyManagers(), trustFactory.getTrustManagers(), null);
Most libraries that I know support setting a custom SSLContext or SSLSocketFactory which can be obtained from the context.
I have written a sample that does the exact same thing. You can find the particular code in [1].
[1] https://github.com/wso2/carbon-identity/blob/v5.0.7/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/TenantMgtAdminServiceClient.java#L155

Java JSSE TLS - Is this connection safely encrypted in both directions?

In Java using JSSE with TLS. I have created a secure socket between the server and client. After finally getting the sockets to connect securely, I still have a fundamental question about my existing code's security. I followed instructions in a tutorial, and sometimes the documentation in the JavaDoc is very precise but a little vague unless you speak the Swaheli dialect of Jargon....
I have been network programming for quite awhile now in C++. The transition to Java was easy. Recently, however, I have found it prudent to make the traffic secure. This being said:
I want to create a secure socket in the same way a web browser creates a secure socket, so traffic in both direction is encrypted. A client can see their personal account information sent from the server (very bad if intercepted), and a client can send their username and password to the server securely (also very bad if intercepted).
I know all about how public key cryptography works, but there's a side effect to public key cryptography alone. You send your public key to a client, the client encrypts with the public key, and sends data to the server only the server can decrypt. Now from what I understand, the server uses the private key to encrypt messages going to the client, and another layer of security needs to be added to prevent anyone with the public key from being able to decrypt it.
I have a public / private key pair stored in files public.key and private.key (i made these using JSSE's keytool utility
I included public.key in the client
I included private.key in the server
Client Class:
KeyStore keyStore;
TrustManagerFactory tmf;
KeyManagerFactory kmf;
SSLContext sslContext;
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
keyStore = KeyStore.getInstance("JKS");
keyStore.load(this.getClass().getClassLoader().getResourceAsStream("server.public"),"public".toCharArray());
tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keyStore);
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, "public".toCharArray());
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom);
SSLSocketFactory sslsocketfactory = sslContext.getSocketFactory();
SSLSocket sslsocket = (SSLSocket)sslsocketfactory.createSocket("localhost", 9999);
Server Class:
String passphrase = "secret"
KeyStore keyStore;
TrustManagerFactory tmf;
KeyManagerFactory kmf;
SSLContext sslContext;
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
keyStore = KeyStore.getInstance("JKS");
keyStore.load(this.getClass().getClassLoader().getResourceAsStream("server.private"),passphrase.toCharArray());
tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keyStore);
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, passphrase.toCharArray());
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom);
SSLServerSocketFactory sslserversocketfactory = sslContext.getServerSocketFactory();
SSLServerSocket sslserversocket =
(SSLServerSocket)sslserversocketfactory.createServerSocket(9999);
/ ******* THE QUESTION ********/
Everything works! I attach the sockets to BufferedReader and BufferedWriter and begin talking beautifully back and forth after accept(); ing the connection from the client and starting my client and server send / receive loops.
Now I know that at this point client to server communication is secure. Only the server key can decrypt traffic coming from the client. But what about server to client communication? The client's key can decrypt messages coming from the server, but in Public Key Crypto 101 you learn that the client is now supposed to send a public key to the server. Is this happening behind the scenes in this code? Did SSLContext take care of this? Or now that I have an encrypted connection from the client to the server, am I now expected to generate a private/public key pair for the client as well?
Let me know if the traffic being sent and received in the above code is actually secure in both directions.
The certificates (and their private keys) in SSL/TLS are only used for authenticating the parties in SSL/TLS (often, only the server uses a certificate).
The actual encryption is done using shared/symmetric keys that are negotiated during the handshake, derived from the pre master key exchanged using a form of authenticated key exchange (see TLS Specification, Section F.1.1.
How this authenticated key exchange is done depends on the cipher suite, but the end result is the same: a shared pre-master secret between the two parties, guaranteed to be known only to the client and the server with the private key for its certificate.
Following that pre-master secret exchange, the master secret itself is calculated, from which a pair of secret keys is derived (as described in the Key Calculation section): one for the client to write (and for the server to read) and one for the server to write (and for the client to read). (MAC secrets are also generated, to guarantee the connection integrity.)
In principle, not all cipher suites provide encryption and authenticated key exchange (see Cipher Suite Definitions section), but all those enabled by default in JSSE with the SunJSSE provider do (see Cipher Suite tables in the SunJSSE provider documentation). In short, don't enable cipher suites with anon or NULL in their names.
Regarding your code:
There are multiple example of code around that fix the Key/TrustManagerFactory algorithm like this ("SunX509"). This is typically code that hard-codes the Java 1.4 defaults. Since Java 5, the default TMF algorithm is PKIX (see Customization section of the JSSE Reference Guide). The best way to get around this is to use TrustManagerFactory.getDefaultAlgorithm() (same for KMF), which will also allow your code to run on other JREs that don't support SunX509 (e.g. IBM's).
Since you're not using client-certificate authentication, there's no point having a KeyManagerFactory on the client side. Your initialising it with a keystore that probably doesn't have a private key anyway, which makes it pointless. You might as well use sslContext.init(null, tmf.getTrustManagers(), null). (Same thing for the secure random in both cases, let the JSSE use its default values.)
You do have an understanding of how PKI works, but you are missing two key pieces of SSL implementation. First most PKI algorithms allow for encrypting traffic both ways. You can send encrypt message using public key and only whoever has a private key can read it, this is called encryption. You can also encrypt the message using a private key and anybody who has a public key can decrypt it, this is called digital signature.
Another missing piece is that SSL doesn't use PKI to send network traffic between client and server. It uses symmetric encryption algorithm. However the key for the symmetric encryption (called session key) is establish using rather complicated challenge-response protocol that employs PKI, and certificates. During this phase server proves to the client that it is not man in in the middle, client can optionally proved it's certificate to the server if it has any for stronger authentication, and the symmetric session key is established. More details are here https://www.rfc-editor.org/rfc/rfc5246
The symmetric key is used for encrypting traffic using algorithms like RC5 or AES

How can I effect 'known_hosts' vs self-certified servers for my app's SSL usage?

Oh wise and noble Oracle,
I'm adding SSL to a TCP client I've written on my Android phone. I can
successfully connect to servers with properly signed certificates, and I can
connect to self-certifying hosts by cooking up a TrustManager implementation
that always thinks everything is fine.
I now have a decorator TrustManager capturing the certificates (before
delegating to its decoratee) for self-certifying hosts and presenting them for
my breathless perusal, but what I can't work out is how to implement ssh's
behaviour of warning that a host is unknown and offering to remember it for
next time - and doing so.
I presumed all I needed was to store the public key - as ssh does with
known_hosts - and re-represent it, but with this code and 'sslTrust' holding
the public key:
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null); // initialise!
ks.setKeyEntry("dbentry", Base64.decode(sslTrust, Base64.NO_WRAP), null);
tmf.init(ks);
tms = tmf.getTrustManagers();
ss.stm = new SnoopyTrustManager((X509TrustManager) tms[0]);
// ...
SLContext context = SSLContext.getInstance("SSL");
context.init(null, new TrustManager[] { ss.stm } , null);
ss.factory = context.getSocketFactory();
// ...
SocketFactory factory = ss.getFactory();
mSocket = factory.createSocket(host, port);
attempting to establish a connection results in
SSLHandshakeException: InvalidAlgorithmParameterException: trustAnchors.isEmpty()
which is fair enough: I don't know how to cook things up from the certificate
offered by the remote server. I'm also fairly sure this isn't how I tell a
TrustManager about a remote server's public key anyway.
Since the site is self-certifying, I imagine could probably just verify that
the public keys match in a trivial TrustManager, but I'd like to understand
how this 'should' be done - adding a CA on a per-connection basis, since
I won't trust that CA for anything else.
You need to use your own trust store on pre-ICS version, and add the serer's certificates to it on first error. Subsequent connections will load it from the trust store and thus trust the remote certificate. This is not a complete solution, but here's one way to do it (code on Github), along with some discussion:
http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store-on.html

Categories

Resources