SSL encryption without validation (SSH Like) - security

I'm building a network authentication system in java.
I want to have my connection encrypted with SSL, so i use SSLServerSocket for it.
I've generated a keystore with keytool: (in ssl directory)
keytool -genkey -keystore myKeystore -keyalg RSA
Then in my Server class:
System.setProperty("javax.net.ssl.keyStore", "ssl/myKeystore");
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
Then in my Client:
System.setProperty("javax.net.ssl.trustStore", "ssl/myKeystore");
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
This works, but I can't rely on the client to make a keystore.
My aim is a SSH-like model: The client has a private key which it will send to the server, and the server verifies it using the public key.
Can't I use simple RSA key files instead of keystores?

You seem to be confusing a number of aspects here. Although SSH doesn't rely on SSL/TLS, theses concepts are indeed broadly similar.
What you've done by setting a truststore on your client matching the keystore on the server is making the client trust the server's public key (within its certificate).
This is the SSH equivalent of having pre-loaded trusted server keys fingerprints. Most SSH clients will learn the server's public key or its fingerprint when you establish the first connection (and you're meant to verify this fingerprint manually in principle): you could implement this with SSL/TLS in Java, this is more or less what Andreas Sterbenz's InstallCert does.
The aim of this is to allow the client to verify the server's identity (without which a MITM attack could be possible).
The client has a private key which it will send to the server, and the
server verifies it using the public key.
When the client has a private key (which it actually uses, but never sends to the server), it's only used for authenticating the client. The aim of this is to allow the server to verify the client's identity (as an alternative to password authentication, for example).
This can also be done with SSL/TLS using client-certificate authentication.
The main difference (protocol aside) between SSH and SSL/TLS in all this is that SSL/TLS tends to use X.509 certificates (which contain public keys and additional attributes describing the entity's identity), whereas SSH tends to use raw public keys directly. (There are extensions to SSH to use X.509 certificate there too, but they're rather uncommon.)
In both cases, the client will need to verify the server's identity to prevent MITM attacks. This is more conventionally done with SSL/TLS using a Public Key Infrastructure (and X.509 certificates), but you could also learn the key upon first connection, like SSH: this requires more work (you'd need a custom trust manager). A reasonable compromise (in a controlled environment) is to use a trust store on the client, pre-loaded with the server's certificate. This is more or less what you've already done, except that you should never give the server's private key away. You really shouldn't use the same keystore here, since the server's keystore will contain its private key: instead, export only the certificate and import it into a keystore which you'll use as trust store on the other side.

Related

Why does mutual SSL require a key pair on the client side instead of just a public certificate?

I'm doing my best to understand mutual SSL. One question I can't find a good answer to is why you need to create a key pair on the client instead of just providing a public client certificate.
So far I understand the following (very oversimplified):
Regular SSL:
The server has a key pair and sends the public part (certificate) so the client can use that public key to encrypt messages so they can share a symmetric key and eventually secure all communication.
To verify that the server is actually the server the issuer of the certificate has to be trusted (in a truststore) of the client by default.
Mutual SSL:
Exactly the same, only this time the server asks the client to authenticate itself.
The client sends its public certificate, which is verified against some kind of list of "known certificates" on the server. If it matches, communication can continue.
I don't understand why I have to include the entire key pair (the private part as well) in the key store I use on the client side. Where is the client's private key used in the process?
The server has a key pair and sends the public part (certificate) so the client can use that public key to encrypt messages so they can share a symmetric key and eventually secure all communication.
That's not the main point of the server certificate and with modern key exchange methods (i.e. Diffie-Hellman) the certificate is not involved at all in the key exchange. What you describe is only true for the obsolete RSA key exchange.
The main point of the certificate is to be used for authentication. Authentication means that the server proves that it owns the provided certificate and then that the client verifies that the certificate matches its expectations, i.e. issued by a trusted CA, expected subject/SAN, not expired etc.
The proof of ownership is done by signing some data (which is at least in part provided by the peer, i.e. client) with the private key matching the public key in the certificate. The peer (client) then can verify this signature using the public key of the certificate and if the verification passes the other side (server) is obviously in possession of the secret private key which means it owns the certificate.
With a client certificate used in mutual authentication the procedure is exactly the same, only with switched roles. That's why the private key is needed on the client side.

SFTP connection with Windows 2008 server . How to prevent trust on first use (TOFU) request?

We have a windows server with SFTP connection via SSH.
It has to be super secure, but when we or other users connect, they get question for trust on first use.
How can we realise more trust? Do we need public/private key authentication? (now is just password and user). SSH does not have anything to do with certificates right?
Thanks in advance!
The users are asked if they trust server's key. This question is asked by the client software.
To prevent the question you need to deliver server's public key to the client somehow (before first connection) and add it to the list of trusted keys, maintained by the client software used by the client.
SSL/TLS also uses the scheme where the server authenticates itself using the public key (usually, as there exist alternative schemes). That key is wrapped into the X.509 certificate. All clients know how to validate the certificate and trust (or not trust) the key because X.509 infrastructure is hierarchical and there exist lists of trusted root and CA certificates on the client side.
In SSH, however, it is different - SSH keys don't form infrastructure and each key must be trusted explicitly. The client provides his public key to the server (if it wants to use public-key authentication, and the server authenticates itself also by providing the public key. There's no way for SSH client to validate the key other than to compare it explicitly with the keys in its trust list that the administrator forms by hand (or copies from another computer).

Best approach to pass the public key from client to server

I have a tcp server and using cms/pkcs#7 to secure the message passed between the client and server. Would it be normal practice to pass the clients public key to the server, as part of initial session? As its the public key, when the session starts up, the initial clp command, would pass the key, along with other salient details that the server needs to know about the client. It's the public, so it doesn't need to be encrypted, it public.
The client/server communication is secured with ssl/tls.
Thanks.
Bob.
Don't you trust SSL/TLS or why do you encrypt again within the secure channel? That only makes sense if the server will pass the message on to other nodes and it will be decrypted somewhere else, thereby creating end-to-end security.
In any case, you should not have the client pass just the public key to the server. Instead it should pass a certificate to the server, which should authenticate the client based on a signature made with the private key matching the public key contained in the certificate. Also, the server will need to check the certificate itself (is it from a trusted CA, do the signatures in the chain verify, etc.).
If you can, you should do all this on the SSL/TLS layer by using SSL/TLS mutual authentication (client cert authentication). If you cannot, then make sure you design a secure application layer protocol for authenticating the client and it's public key. Otherwise it may be possible to impersonate other clients.

SSL: How are certificates protected against man in the middle attacks?

My question is about certificates specifically in ssl but I think the questions should apply to all certificates. I have included the SSL procedure for the sake of clarity.
In SSL this is what I understand the procedure is:
1)Client
sends supported crypto algorithms
sends client nonce
Server
chooses (and sends) a
symmetric algorithm
a public key algorithm
a MAC algorithm
sends it's certificate
sends server nonce
Client
verifies certificate
Extracts public key
Generates a pre-master secret key (pms)
encrypts with servers public key and sends
Client and Server
compute master secrete (MS) from PMS and nonces
PMS sliced to generate two encryption & two mac keys
Client
sends a mac of all handshakes (to ensure they were not previously modifide)
Server
sends a mac of all handshakes
Question
What stops a man in the middle attack from happening at step two? Why can't a man in the middle, say trudy, capture the certificate sent by the server and change the public key in it (to something it has the private key to).
I assume that the certificate is encrypted somehow.
However the server cannot encrypt the certificate because the client does not have the public key yet. When the server gets the key from an authority (like veri-sign) would the key be pre-encrypted using verisign's public key? I think this should work because all web browsers should have the public keys of most authorities.
No, the certificate is not encrypted. But it is signed by a certification authority (CA). Since those check the information included in the certificate (especially the URL to which the cert belongs), there shouldn't be a second valid certificate for a given URL.
The cert of the CA is checked against a trust store (e.g. in your browser). If this truststore is compromised, or if you trust not valid certificates, there is no protection against man in the middle attacks
Certificates are signed by some trusted authority, such as Verisign.
The certificates for these root authorities are built right into the browsers when you download them. You can view the root certificates in Firefox, for example, by going to tools-->options-->advanced-->encryption-->view certificates-->authorities.
If any one of these root-certificate authorities is compromised, however, you are right that a certificate could be forged, making a man-in-the-middle attack possible.
You actually pointed out a weak spot of PKI.
Say Trudy is in the middle of you and yourbank (bank.com). Trudy can change the public key at will at step 2 but the certificate's signature will be invalid. So Trudy has to find a way to generate the signature again. It's safe to say that the trusted CAs will not do this for him. So he has to sign with a fake CA, which is not trusted by your browser. This is still safe theoretically.
However, most browsers (especially IE 6) display a vague security warning and most people don't understand and just ignore, according to some tests.

Strength of RSA Encrypting an AES Key

I'm currently developing a system to transmit data between client and server, and was wondering what the strength of the encryption I planned to use was.
My thought was to have a private/public RSA key pair and hand out the public key to each client (leaving the private key solely on the server). Each client would then generate their own AES key and RSA encrypt it. They would then AES encrypt their data and send the encrypted data and encrypted AES key to the server. The server would then decrypt the AES key using the private key, and then decrypt the data using the AES key.
Are there any security flaws I am missing and/or is there a better way to do this?
This is almost exactly how SSL/TLS works (check out the handshake section). The only thing to make it stronger is to generate the AES key for each connection, rather than using the same key each time. You might also want to digitally sign messages that go back and forth to avoid man-in-the-middle and other spoofing attacks.
Generally speaking, creating a good cryptosystem is very difficult. When possible, you should always favor an existing (trusted) application to help out. In this case, you might consider sending your messages using HTTPS, rather than creating your own system.
You should give us more information about the language and platform you are using, so that we can give you specific recommendations about libraries that already exist and wich will handle the details for you. Using cryptographic primitives directly is not trivial and difficult to get exactly right, and with cryptography, you have to be "not exactly right" only once for your security to be broken.
To answer your question, it's generally a better idea to create a session secret (the AES key) through a Diffie-Hellman exchange, and each side use its private RSA key to sign its key-exchange data.
Otherwise, if the session secret is not established through a DH exchange, an adversary that gains access to the private RSA key (which has to be stored somewhere) could decrypt all traffic that was ever sent between the client and server.
If the secret is established through a DH exchange, then only the authentication part of the protocol would be exposed. Although an adversary in possession of the private RSA key would then not be able to read any previous communication, he still could either enter an authenticated dialog with the client/server or launch a man-in-the-middle attack (which may or may not be easily done, depending on the network).
One vulnerability would be if an attacker substituted their public key for the "real" public key. Then they would be able to intercept traffic as a "man-in-the-middle."
Protocols like S/MIME, PGP, and TLS use RSA encryption to transport keys just as you propose. However, the public keys they use are in certificates signed by trusted authorities.
The integrity of these trusted authorities must be carefully protected. For example, they might be burned into a tamper-proof hardware token, or a MAC might be computed over them using a password.
I'm not sure your approach will protect anything! You're going to keep the private key on the server and the public key will be distributed. If I get a hold of your public key, I'll be able to interact with your server at will. I think you should reverse the key ownership; each client will hold it's-own private key and the server will have a list of public keys (ala SSH). The server will have to add 'authorized' public keys and only to holders of the private keys will be able to connect.
Hope this helps.

Resources