Every tutorial I have found explains how to create an SSL/TLS connection with SSLSockets using a keystore file and truststore to store an SSL certificate after creating it manually with the keytool utility.
I would love to know how to do the same thing but with a public key/certificate generated on the fly (ephemeral).
It's so easy to create an RSA/EC key pair in Java so why can't we just use it for an SSLSocket as well? This has two big advantages in my opinion: it allows for forward secrecy and at the same time I don't have to deal with passwords, utilities, file readers and keystore converters for Android.
This has two big advantages in my opinion: it allows for forward secrecy
Forward secrecy typically deals with the key agreement like ECDHE or DHE (though the latter is now widely deprecated due to logjam).
It is good practice to re-key certificates from time to time, though a new one for every TLS session is not necessary.
It's so easy to create an RSA/EC key pair in Java so why can't we just use it for an SSLSocket as well?
You need an X509 certificate too, not a just a key. You can still make those on the fly, but you are going to have to sign the certificate. Either the certificate will be self signed, or you need a certificate authority that can sign certificates very quickly, on demand. Practically, the latter doesn't exist and would mean very slow handshakes.
If the certificate is self-signed, browsers or any other user agent will not know how to trust the certificate, and using a self signed certificates severely impacts the use of TLS.
As a technically correct but fairly useless alternative:
TLS actually defines 'anonymous' keyexchange methods DH_anon and ECDH_anon (and ciphersuites using them) which do forward-secret key agreement using ephemeral keypairs, and NO authentication, thus not requiring any certificate or keystore on the server or (potentially) truststore on the client.
Being unauthenticated, they are easily vulnerable to active attack, and thus people (and authorities) who actually want security consider them unacceptable for use. Java (JSSE) does implement them, but does not enable them by default; your code must call .setEnabledCiphers with an appropriately modified or set list. Most other SSL/TLS implementations either similarly disable them or don't implement them at all.
But technically that is a valid way to do TLS with no long-term keys and certs, and thus no manual effort for adminstering them.
As an aside, I believe this is why creating an (SSLContext and) SSLSocketFactory with (KeyManager for) a keystore not containg a valid privateKeyEntry does not give an error, because in principle it could create sockets (or engines) used for anonymous connections. Instead, since in practice anonymous keyexchange is never used, these factories cause all subsequent connections to fail in a fashion many nonexpert programmers have trouble diagnosing. (In contrast trying to create a validator for an empty truststore throws a specific exception, something like 'trust anchor set must not be empty'.)
Related
This previous question dealt with the handling of self-signed certificates in Java:
Accept server's self-signed ssl certificate in Java client
The accepted answer offers 2 possible options: (1) manually load the relevant certificate into the local keystore (2) circumvent UrlConnection's security with a bespoke TrustManager
In the context of a web crawler whose function is solely to extract content from remote https secured sites, what specific risks arise from option 2.
And, assuming those risks are deemed unacceptable, what alternative exists since it is not viable to manually extract the certificates and load into the local keystore.
Not only from option 2 but also from 1, the only risk is that there is no guarantee that the server your webcrawler is crawling is effectively the one you think it is. There are other risks but are not associated with the tasks a web crawler does.
For your second question: You need to identify why it is unnaceptable, because it is very easy to code in java to just accept the self-signed certificate. What specifically blocks you to code to accept the certificate? You can use a proxy server to automatically accept all certificates but this is a separate topic and it would be better to create a new question for it.
My plan to make my server harder to emulate goes as follows;
The client creates a random string, String random;
This string is then encrypted and sent to the server. The server then decrypts it and sends it back, if the one sent back is the same as random, then they are connected to the right server (and not a fake one with a diff private key).
How can I make it so that each client has the public key and the server holds the private key? Not a clue.
EDIT -
Because I do not want the clients to have to have extra files for the public key, can I allow them to download the public key on runtime? If I hold it on the server and like serialize it? How?
Is it sensible to use a public and private key encryption between a
client server model?
In a word? No. At least not the way you describe it.
You could get this to work as described, but you will have created security theater rather than effective security.
If you use public/private key pairs that are not bound to certificates, you have a key exchange problem. As noted in the comments, if the app just downloads the key from the server to which it connects, and that key is not in a certificate, there's no way to tell it's authentic to the intended server.
If you use public-/private keys bound to certificates it solves your key exchange problem since you can download the cert from the target server and inspect the Subject Distinguished Name and Issuer Distinguished Name to discover whether the public key you have is authentic. But once you have gone to the trouble of deploying certificates, just use TLS. It's there, it's reliable, and most importantly it's been thoroughly hammered at and known bugs fixed so its as trustworthy as we have available. Your home-grown protocol is not.
What you are describing can be achieved with other standard protocols such as Challenge-Handshake Authentication Protocol (CHAP). If TLS doesn't meet your requirement, use a standard protocol. Even an old deprecated one would be better than writing your own because, like TLS, it's been hammered on extensively in the real world.
Assuming that you did implement the protocol proposed, then what? Authenticate then communicate in plaintext? Why expend more effort than implementing TLS, to deploy something far less secure than TLS, that doesn't even provide privacy or integrity of transmitted data?
Because I do not want the clients to have to have extra files for the
public key, can I allow them to download the public key on runtime? If
I hold it on the server and like serialize it? How?
If you use CA signed certificates (from an internal or external CA) you can dynamically fetch the certificates from the target server. The only thing you need to store is the signer chain in your Trust Store and the acceptable values for Subject Distinguished Name and Issuer Distinguished Name. The remote cert won't validate if the signer certs are not in the Trust Store so a man in the middle can't just swap out any cert with the right distinguished names. Once it validates to your Trust Store, your inspection of the distinguished names determines if you have the right cert and server.
Finally, the question doesn't mention revocation at all. If you use CA-signed certs from a commercial CA or from an internal CA that is at least somewhat robust, you can check at run time against a Certificate Revocation List or use Online Certificate Status Protocol. Again, these are built into the TLS protocol as implemented in any JSSE standard provider.
I'm making an application that requires it to be authenticated on startup with a "secret key" as defined in a configuration file. I can't have the app call to a database so I'm thinking I need to do a HTTP request, however I am not sure how I should go about doing this and how it can't be exploited.
I just need somewhere to start, thanks!
You can use SSL. Then to manage trusted certs, you can implement your own javax.net.ssl.X509TrustManager. You can use the javax.net.ssl.X509TrustManager to manage your .keystore file via standard Java mechanisms. The keystore will contain private keys.
From JavaDoc:
Instance of this interface manage which X509 certificates may be used to authenticate the >remote side of a secure socket. Decisions may be based on trusted certificate authorities, >certificate revocation lists, online status checking or other means.
Also note that:
TrustManagers are responsible for managing the trust material that is used when making trust
decisions, and for deciding whether credentials presented by a peer should be accepted.
If you extend the X509TrustManager, you can read in certificates your private .keystore file as well as certificates trusted by Java. Those live in JAVA_HOME\lib\security\cacerts
I need to communicate between two desktop Java app, and the best way to do this is to use SSL (to prevent sniffers). I control both the client and server so self-signed is okay.
My question is if a certificate can be made and used from scratch programmatically (i.e. the end user does not have to physically do anything himself).
If this is possible, could you give me some pointers?
My question is if a certificate can be made and used from scratch
programmatically (i.e. the end user does not have to physically do
anything himself).
Before you think of generating certificates (programmatically or not), you need to decide how you're going to verify them. In the context of two desktop applications, the traditional way of verifying a server certificate might not be suitable.
The purpose of the certificates is to give a way to verify the identity of the remote party, so as to prevent Man-In-The-Middle attacks. The verifying party uses something it already trusts to make this verification; not doing so makes using certificates pointless.
In the traditional model (with a fixed server), the server certificate is part of a PKI and issued by a CA. The client verifies its authenticity against a set of CA certificates it trusts (typically using the rules described in RFC 5280, and it verifies the certificate is valid for the host name is was looking for (how this is done depends on the protocol, but best and historical practices are described in RFC 6125). Both steps are necessary to prevent MITM attacks. It's similar to verifying someone's identity using a passport: you want to check that the passport is real and from an authority you trust, and you want to check that the name (or picture) matches the name you're looking for (or the face in front of you).
When establishing a communication between two desktop applications, you're certainly going to have problems with both aspects: how to let the client verify the cert was issued by an entity you trust, and was issued to the entity you want to communicate with. If you generate the certificate programmatically no either side, it's certainly going to be self-signed, which will make verifying its authenticity from the other side difficult without another means of exchange (independent of this SSL/TLS communication). In addition, desktops tend not to have fixed host names, so a DNS-based (or even an IP address) identifier might be inadequate in this context.
You'll need to think of a way to publish the certificate in a way that the remote party can verify it trusts it, and to think of an identifying scheme to make sure the certificate belongs to the right entity (this is typically what goes in the Subject DN or Subject Alternative Name extension of the certificate).
Once you've made these decisions, you can use BouncyCastle's org.bouncycastle.x509.X509V3CertificateGenerator to generate your certificate (an X.509 v3 certificate should let you add extensions to the certificate, e.g. for key usage purpose, if you need them). There are various examples (for v1, v3 and/or self-signed, i.e. where Subject = Issuer) on the BouncyCastle wiki. I'd say that using this is the easy bit unfortunately (the administrative side of trust would be the hardest).
If both desktop applications are in fact both part of a more central application, you could run a service that issues this certificate, from a certificate request (CSR) generated within your application. A central server would effectively run your own CA, and your desktop applications would trust that CA. Depending on the complexity of your organisation, there are tools available to do this, or you could also use BouncyCastle to implement it, using the same classes (it would even be better if you implemented CRL/OSCP to be able to revoke certificates). In this case, you could make your application generate a CSR and submit it to your central CA. CSRs can be generated with BouncyCastle using PKCS10CertificationRequest. Again, how your CA verify the CSR comes from the right party, using external information, is also an administrative problem, perhaps you can tie it to an e-mail verification scheme or something like that.
Once you've generated your certificates, you'll be able to use Java's JSSE as your SSL/TLS stack (typically using SSLSocket). You may have to use custom X509TrustManagers to implement the certificate verification (depending on how you've designed your scheme to verify the certificate, if you're unable to use a traditional CA model). Just make sure you don't use trust managers that don't do anything in their check* methods; there are a number of examples of this around: you might as well not use certificates at all in this case, if you don't do anything to verify them (this would make the connections vulnerable to MITM attacks).
You could use a JCE based solution with SSLSocket, docs for jdk6 and its implementation: SSLSocketImpl.
Java SSL SSH:
You have Jsch lib to connect to any server with SSH protocol.
Java Toolbox for SSL:
You have Bouncy Castle.
Look at their resources and their documentation. The wiki provides some usefull examples with the latest releases:
ContentSigner sigGen = ...;
PublicKey publicKey = ....;
Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);
X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
new X500Principal("CN=Test"),
BigInteger.ONE,
startDate, endDate,
new X500Principal("CN=Test"),
publicKey);
X509CertificateHolder certHolder = v1CertGen.build(sigGen);
I'm in the "pre-design" phase (if there is such a thing!) for a Java EE app that will use a Swing box on the client end and implement components for both web and server tiers.
I'm instantly presented with some technology choices and have been reading up on the differences between how Kerberos and SSL work. One area that I have not been able to find any answers to has been the subject of how to choose between Kerberos or SSL. In other words, how do you tell when it is appropriate to use either protocol?
Let's assume that the Swing client isn't bound by a particular transport (UDP, TCP or otherwise) and could use either/any. How does one choose between which of these two is a better match for their application?
Thanks!
and suddenly (several months later) a wild Sys Admin appears...
I'm going to have to be a voice of dissent on this. The notion that you would ever establish a PKI without a CA is incredibly absurd. You have to maintain the integrity and performance of the PKI by streamlining the creation process. You have to create and store the certs somewhere, where is that going to be? Boom, you have a CA. Any decent PKI is also going to require a CRL be maintained, is the administrator supposed to just write that by hand? You can also forget about having different types of 509's as the overhead of maintaining that by hand would blow-your-mind-wide-open-and-turn-it-into-grey-slurry.
I suppose you could just manually create the tickets with openssl's CLI and just ftp them to the remote clients, but that gets to be a HUGE hassle for deployments of appreciable size. Essentially, if your deployment is so small that generating the certs by hand (repetitive entering of information and all) and then just not worrying about a CRL is a reasonable plan, you don't need an advanced authentication system at all. Something along the lines of TLS+LDAP (one server cert for confidentiality and not authentication) is more appropriate.
Ok, now that I've cleared some misconceptions, let's actually answer your question: When would you want to use SSL over Kerberos for authentication? x509-based authentication is an incredibly nebulous beast, mostly on account that most people (like Michael-O above) don't realize that SSL work specifically because it's authenticating users. There are a few FTP programs that I know of that authenticate that way, middleware employs it...sometimes (which sounds close to your use case from the java talk), and vpn clients/gateways often authenticate with SSL certs.
Usage of SSL would imply the PKI I spoke of up there, which would work great if your use case involves confidentiality. DoD is a good example of an enterprise that makes extensive use of PKI for functions outside of authentication. In that context, supposing all relevant client programs support x509 authentication makes a lot of sense. It's still an exotic set up, and you would still have to figure out how the end-users will "present" their SSL credentials to the system (client configuration, smart cards, etc) but it would fit together nicely. Besides the odd fit, kerberos authenticates by way of a temporary ticket, whereas SSL certs typically last a long time (which is why a CRL is required) meaning that if the never-changing key is factored on one cert the attacker will have several months of free rides before they have to find a new cert, versus kerberos where they only have it for a day and that's only if the ticket isn't destroyed.
All other cases should use Kerberos authentication when possible. It provides the right layer of security and is actually designed as a large network authentication system, which is why you have things that are hard to duplicate with SSL (like authenticating as a service instead of a regular user) and just plain work for their intended purpose. Your use cases are always going to need to take into account existing infrastructure which is probably going to be kerberos-oriented, sometimes LDAPS-oriented, but almost never x509 authentication-oriented. In other words: whatever you're writing is MUCH more likely to be running in a kerberos infrastructure already, so you might as well plug into that somehow. You'll also benefit more from administrator familiarity with Kerberos-as-authentication than 509-as-authentication. The con on this is that confidentiality outside of the ticket is kind of a joke. NFSv4 has some weak DES (and no I didn't mean 3DES even) encryption that it (somehow) relates to the kerberos ticket but it does authentication and that's basically all it does.
I'd like to see some of x509's flexibility combined with kerberos-style infrastructure (recognition of services and the "one time pad" aspect of having a soon-to-expire ticket) incorporated into a solution that was more widely implemented than x509 is now, but at this stage it's mostly day-dreaming.
Summary:
x509 is good if infrastructure requirements won't be a problem and you'll be using PKI for other stuff anyways, but might be duplicating effort needlessly otherwise or if the deployment is probably going to have a kerberos infrastructure anyways.
Kerberos is a similar but better authentication scheme that is more widely used/understood but won't help you with PKI at all, you get authentication, and that is it.
Comparing Kerberos and SSL/TLS doesn't make sense.
Kerberos is an authentication protocol.
TLS is a protocol for securing the communication between two parties, which relies on mechanisms for authentication and encryption. How they work depend on the chosen cipher suite. Although most usages of TLS (e.g. HTTPS) use X.509 certificates, in which case you're likely to use a PKI for the authentication of the remote party, Kerberos cipher suites can also be used. Few TLS stacks support these Kerberos cipher suites as far as I'm aware (Java does).
It doesn't have to be one or the other. For example, even if you're using SPNEGO (Kerberos) HTTP authentication, it often makes sense to secure the transport using TLS (often with an X.509 certificate on the server side, verified via a PKI). If not, the SPNEGO tokens exchanged in the HTTP headers guarantee the authentication, but the rest of the HTTP messages could have been modified by an attacker.
This could be useful:
http://www.faqs.org/faqs/kerberos-faq/general/section-31.html
Consider that any solution involving Kerberos will be more complicated than SSL because it requires an additional, third component, the Authentication Server, which must be managed and administered (e.g. MS Active Directory) whereas SSL is simply a client/server protocol.
You are mixing stuff. Kerberos is an authentication protocol, SSL ist encryption. Kerberos is the way to go if you are in a corporate environment.
Edit: Kerberos can also encrypt your data traffic transparently. No need for SSL certiticates.