SSL/TLS - am I doing it right?

F

Frank Millman

Hi all

I am writing a multi-user accounting/business application, which uses
sockets to communicate between client and server. I want to offer the
option of encrypting the traffic between the two. The main reason for
this is to cater for wireless communication.

I have read up on SSL, and more or less understand the concepts. I have
downloaded some additional software, read the instructions, and seem to
have got it working. However, I have no in-depth knowledge of what is
going on, and I have no idea how to check if I am doing it correctly.

The subject is too important to learn the hard way that I am doing
something wrong. Therefore I would be grateful if someone would review
the steps I have taken (listed below), and advise on whether there is
anything obviously wrong or missing.

TIA

Frank Millman


1. Install
----------
OpenSSL
M2Crypto
TLSLite

2. Create KeyPair + Certificate
-------------------------------
openssl genrsa -out privkey.key 1024
openssl req -new -x509 -key privkey.key -out privkey.crt -days 1095
cp privkey.key privkey.pem
cat privkey.crt >> privkey.pem

3. Modify Server
----------------
old -
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen(1)
while 1:
conn,addr = s.accept()
data = conn.recv(1024)

new -
f = open('/home/frank/secrets/privkey.pem').read()
x509 = X509()
x509.parse(f)
certChain = X509CertChain([x509])
f = open('/home/frank/secrets/privkey.pem').read()
privateKey = parsePEMKey(f,private=True)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen(1)
while 1:
conn,addr = s.accept()
c = TLSConnection(conn)
c.handshakeServer(certChain=certChain,privateKey=privateKey)
data = c.recv(1024)

4.Modify Client
---------------
old -
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
s.send(data)

new -
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
c = TLSConnection(s)
c.handshakeClientCert()
c.send(data)
 
S

Sybren Stuvel

Frank Millman enlightened us with:
while 1:
conn,addr = s.accept()
c = TLSConnection(conn)
c.handshakeServer(certChain=certChain,privateKey=privateKey)
data = c.recv(1024)

It's nice that you set up a TLS connection, but you never check the
certificate of the other side for vality. You should make sure the
certificate chain is completely signed from top to bottom. Then check
that the bottom certificate is amongst trusted CAs. Also check all the
certificates in the chain against the CRL of the CA. I've submitted
this CRL check to the author of TLS Lite, so it should be in a release
soon.
s.connect((HOST,PORT))
c = TLSConnection(s)
c.handshakeClientCert()
c.send(data)

See above. You set up a TLS connection, but you never verify that
you're talking to the right computer.

Sybren
 
F

Frank Millman

Sybren said:
Frank Millman enlightened us with:

It's nice that you set up a TLS connection, but you never check the
certificate of the other side for vality. You should make sure the
certificate chain is completely signed from top to bottom. Then check
that the bottom certificate is amongst trusted CAs. Also check all the
certificates in the chain against the CRL of the CA.

Thanks for the reply, Sybren.

I was hoping to avoid this step. The point of the exercise for me is
encryption. I am not too worried about authentication. The next step in
my app is for the client to enter a user id and password, and the
server will not proceed without verifying this.

However, I realise that security is not something to be trivialised, so
if your recommendation is that I do complete the validation steps, I
will try to understand that part of the documentation and apply that as
well.

Thanks

Frank
 
P

Paul Rubin

Frank Millman said:
I was hoping to avoid this step. The point of the exercise for me is
encryption. I am not too worried about authentication. The next step in
my app is for the client to enter a user id and password, and the
server will not proceed without verifying this.

That is a total disaster without authentication, since it means the
client can reveal the password to an imposter.
 
F

Frank Millman

Paul said:
That is a total disaster without authentication, since it means the
client can reveal the password to an imposter.

Understood. You cannot have encryption without authentication - they go
hand in hand.

Back to the documentation.

Thanks, Paul

Frank
 
S

Sybren Stuvel

Frank Millman enlightened us with:
The point of the exercise for me is encryption. I am not too worried
about authentication.

Encryption can't function fully without authenication.
The next step in my app is for the client to enter a user id and
password, and the server will not proceed without verifying this.

But the client is willing to give that username and password to
anybody that's listening. It doesn't authenticate the server, so it
can be very easily tricked into talking to someone else. Your system
is open to Man in the Middle attacks.
However, I realise that security is not something to be trivialised,
so if your recommendation is that I do complete the validation
steps, I will try to understand that part of the documentation and
apply that as well.

That is indeed my recommendation indeed :)

Sybren
 
F

Frank Millman

Sybren said:
Frank Millman enlightened us with:

Encryption can't function fully without authenication.

Ok, I have been thinking about the replies from you and Paul, and I am
confused (nothing new).

Let's keep it simple, and assume that the client and the server are on
the same network. The server runs with restricted permissions, with
access to the database. A client can only access the server through a
client connection.

A client can be any workstation on the network. To be able to function
as a client, it needs a pointer to the client software, and it needs a
pointer to a parameter that tells it where to find the server - ip
address/port number.

If I understand correctly, a 'man-in-the-middle' attack would involve
someone setting up a 'pseudo server', which gives the correct responses
to the client's attempt to log in; and would also involve someone
manipulating the client parameter so that it points to the pseudo
server instead of the real server. This would indeed allow the pseudo
server to obtain the user id and password fraudulently.

What I have not understood is how to prevent this. How can the client
distinguish between a valid server and a fraudulent one? If it obtains
the server credentials dynamically, the fraudulent server can supply
fraudulent credentials. If somehow the client must know in advance what
the credentials are, then these can only be as secure as the parameter
that tells the client how to connect in the first place.

I more or less understand the concept of setting up a secure server,
with a signed key that can be validated via a trusted authority, but
surely it is not necessary for every user of my software to register
with such an authority before they can get protected communication
between their own clients and their own server.

I am sure I am missing the point somewhere. Any advice, or links to
literature that explain this in more detail, will be much appreciated.

Thanks

Frank
 
S

Sybren Stuvel

Frank Millman enlightened us with:
If I understand correctly, a 'man-in-the-middle' attack would
involve someone setting up a 'pseudo server', which gives the
correct responses to the client's attempt to log in

That's right. Usually it's done by proxying the data between the
client and the real server.
and would also involve someone manipulating the client parameter so
that it points to the pseudo server instead of the real server.

Yup. This can be done in various ways, like ARP poisoning of the
network. Then the IP address will not change, but the network card
that the traffic is sent to will. The fraudulent server, having the
correct ARP table, can then forward the captured data to the real
server.
What I have not understood is how to prevent this. How can the
client distinguish between a valid server and a fraudulent one?

By checking the certificates. The CA mustn't sign server certificates
except for the real server. The fraudulent server thus has no valid
server certificate.
If it obtains the server credentials dynamically, the fraudulent
server can supply fraudulent credentials. If somehow the client must
know in advance what the credentials are, then these can only be as
secure as the parameter that tells the client how to connect in the
first place.

True, but as you can see above, making the client talk to another
computer doesn't have to involve accessing and changing the client's
filesystem.
I more or less understand the concept of setting up a secure server,
with a signed key that can be validated via a trusted authority, but
surely it is not necessary for every user of my software to register
with such an authority before they can get protected communication
between their own clients and their own server.

If you want to be secure, that *is* necessary. Every client should
have a valid, signed certificate, and every server should too.

Sybren
 
P

Paul Rubin

Frank Millman said:
What I have not understood is how to prevent this. How can the client
distinguish between a valid server and a fraudulent one? If it obtains
the server credentials dynamically, the fraudulent server can supply
fraudulent credentials. If somehow the client must know in advance what
the credentials are, then these can only be as secure as the parameter
that tells the client how to connect in the first place.

The client and the server each needs to know the public key of the
"certificate authority" (or CA) that issued the root of the chain of
certificates that the other side presents. For a public server you'd
use a commercial CA. For a local network you could run your own CA;
for example, OpenSSL (www.openssl.org) comes with a simple Perl script
that acts as a rudimentary CA.

Note that TLSLite at the moment doesn't know how to authenticate
certificate chains all by itself without external libraries. I didn't
look at your code sample closely enough to figure out whether you were
using OpenSSL or M2Crypto in a way that takes care of that.
I am sure I am missing the point somewhere. Any advice, or links to
literature that explain this in more detail, will be much appreciated.

This might help:

http://www.modssl.org/docs/2.8/ssl_intro.html
 
S

Sybren Stuvel

Paul Rubin enlightened us with:
for example, OpenSSL (www.openssl.org) comes with a simple Perl
script that acts as a rudimentary CA.

I never understood those CA scripts. I mean, creating a new CA
certificate only has to be done once, and is:

openssl req -new -x509 -key $KEY -out $OUT -days 365 -config $CONF

Signing a certificate request is easier:

openssl ca -in some.req

Why do people feel the need to wrap that up in some Perl script?
Note that TLSLite at the moment doesn't know how to authenticate
certificate chains all by itself without external libraries. I
didn't look at your code sample closely enough to figure out whether
you were using OpenSSL or M2Crypto in a way that takes care of that.

TLS Lite can use both, and cryptlib_py too. For proper verification,
you need the latter. My CRL checks also require cryptlib.

Sybren
 
F

Frank Millman

Sybren said:
Frank Millman enlightened us with:

That's right. Usually it's done by proxying the data between the
client and the real server.


Yup. This can be done in various ways, like ARP poisoning of the
network. Then the IP address will not change, but the network card
that the traffic is sent to will. The fraudulent server, having the
correct ARP table, can then forward the captured data to the real
server.


By checking the certificates. The CA mustn't sign server certificates
except for the real server. The fraudulent server thus has no valid
server certificate.

I don't know how to check the certificates. None of the documentation I
have read spells out in detail how to do this.

What about this idea? I am not looking for a state-of-the-art solution.
I am looking for something that is 'good enough' for a typical SME with
its own internal network.

Assume that the server is reasonably protected, i.e. can only be
accessed by administrators with valid permissions.

Assume that the client is reasonably protected - i.e. a fraudster
cannot access/change the file system. If this cannot be assumed, all
bets are off, as the fraudster can replace the pointer to the client
software with one to a modified version that bypasses the
authentication procedure, and we are back to square one.

Using openssl, generate a key for the server, generate a self-signed
certificate, and extract the sha1 fingerprint of the certificate. The
key must be kept secure but the fingerprint can be published.

When a client wishes to connect to the server, it must read a parameter
which includes the ip address, the port number, and the fingerprint.

After establishing an SSL connection, the client compares the session
fingerprint (TLSLite has a getFingerprint() function) with the
parameter. If different, client assumes it is talking to an imposter
and disconnects.

Are there any gaping holes in this approach?

Thanks

Frank
 
P

Paul Rubin

Frank Millman said:
I don't know how to check the certificates. None of the documentation I
have read spells out in detail how to do this.

Lemme see if I can find you something--I'll put up another post if I do.
What about this idea? I am not looking for a state-of-the-art solution.
I am looking for something that is 'good enough' for a typical SME with
its own internal network.

Didn't you say wireless? That's not an internal network, it's a
network that extends off the premises and is accessible to anyone with
a laptop who can park a car in the neighborhood.
Using openssl, generate a key for the server, generate a self-signed
certificate, and extract the sha1 fingerprint of the certificate. The
key must be kept secure but the fingerprint can be published.

Then install a copy of the certificate on the client, that the client
can authenticate against. You also want to generate a client
certificate to install on the server. If there are multiple clients
you should make a CA rather than trying to keep track of self-signed
certificates. If you're paranoid, you can scrounge some $20 obsolete
laptop from ebay and dedicate it to use as a CA, never letting it
touch the internet (transfer files to and from it on floppy disc).
After establishing an SSL connection, the client compares the session
fingerprint (TLSLite has a getFingerprint() function) with the
parameter. If different, client assumes it is talking to an imposter
and disconnects.

Are there any gaping holes in this approach?

1. You have to authenticate both the server and the client; you can do
that with certificates at both ends (preferred for non-public-facing
applications) or you could do it with something like a client password
sent through the TLS session after the session is established.

2. I don't see the docs for getFingerprint at
http://trevp.com/tlslite/docs/index.html
 
S

Sybren Stuvel

Paul Rubin enlightened us with:
If you're paranoid, you can scrounge some $20 obsolete laptop from
ebay and dedicate it to use as a CA, never letting it touch the
internet (transfer files to and from it on floppy disc).

caCert use a special box for this too. It has no network connection,
and communicates through a serial cable. All it does with that serial
cable is accept certificate requests and spit out signed certificates
:)

Sybren
 
S

Sybren Stuvel

Frank Millman enlightened us with:
I don't know how to check the certificates. None of the
documentation I have read spells out in detail how to do this.

Read the readme that comes with TLS Lite. You can require certificate
checks, call certchain.validate(CAlist), and with my extension you can
also use the CRL module to check.
Using openssl, generate a key for the server, generate a self-signed
certificate, and extract the sha1 fingerprint of the certificate.
The key must be kept secure but the fingerprint can be published.

The entire certificate can be published along with the fingerprint.
When a client wishes to connect to the server, it must read a
parameter which includes the ip address, the port number, and the
fingerprint.

After establishing an SSL connection, the client compares the
session fingerprint (TLSLite has a getFingerprint() function) with
the parameter. If different, client assumes it is talking to an
imposter and disconnects.

It's a good idea if you want to keep the client lightweight. As a
matter of fact, it's what I use on the client side of my TLS
connection.
Are there any gaping holes in this approach?

If anyone sees them, please let us know :)

There is one gaping hole, though, because you only talk about the
client checking the server. If you want to be really secure, you also
need to use client certificates and let the server check them for
validity. I do that too. Without a valid client certificate, no
connection.

Sybren
 
F

Frank Millman

Paul said:
Lemme see if I can find you something--I'll put up another post if I do.

Thanks

Didn't you say wireless? That's not an internal network, it's a
network that extends off the premises and is accessible to anyone with
a laptop who can park a car in the neighborhood.

One of my goals is to use a diskless, wireless workstation that can be
positioned anywhere without a whole lot of cabling. This will be
particularly beneficial in a retail point-of-sale environment. It was
this that got me onto the idea of SSL, to prevent the proverbial car in
the neighborhood from eavesdropping on the network traffic.
Then install a copy of the certificate on the client, that the client
can authenticate against.

I wanted to keep the legwork required to set up a new client down to a
minimum. I was hoping that setting a pointer to the client software,
and a pointer to a connection parameter, would be sufficient. If the
fingerprint is an an adequate substitute for the full certificate, I
would prefer it, as it is much smaller, and can easily form part of the
connection parameter.
You also want to generate a client
certificate to install on the server. If there are multiple clients
you should make a CA rather than trying to keep track of self-signed
certificates. If you're paranoid, you can scrounge some $20 obsolete
laptop from ebay and dedicate it to use as a CA, never letting it
touch the internet (transfer files to and from it on floppy disc).

Both you and Sybren are insistent that this is a necessary step, but I
confess I cannot see the need for it. The client is lightweight, and
authenticates itself to the server using a user id and password. What
is the worst that could go wrong?
2. I don't see the docs for getFingerprint at
http://trevp.com/tlslite/docs/index.html

To quote from the docs, if the handshake completes without raising an
exception, authentication results will be stored in the connection's
session object. The following variables will be populated if
applicable, or else set to None:

....
connection.session.serverCertChain
....

session is an instance of the class Session.
serverCertChain is an instance of the class X509CertChain
getFingerprint() is a method of X509CertChain - it returns the
hex-encoded fingerprint of the end-entity certificate.

Paul, I would like to thank you and Sybren for your patience. I feel I
am being a bit obtuse. I am trying to understand enough of this so that
I can implement 'enough' security to protect users against obvious
attacks, without overburdening them with a load of maintenance which in
practice they will end up ignoring.

Many thanks

Frank
 
M

Michael Ekstrand

Disclaimer: I am not an expert. Take this with a grain of salt... but
I'll throw it out for what it's worth.

I wanted to keep the legwork required to set up a new client down to a
minimum. I was hoping that setting a pointer to the client software,
and a pointer to a connection parameter, would be sufficient. If the
fingerprint is an an adequate substitute for the full certificate, I
would prefer it, as it is much smaller, and can easily form part of
the connection parameter.

Your client probably installs data files, right? Then just install the
server's public key (or a fingerprint thereof) as one of your data
files, put a checksum system in place to make sure it isn't tampered
with. Or just embed the checksum in your program or a DLL - the server
won't be changing its certificate very often.

If the user wants to go change the fingerprint to let the program
connect to a fradulent server, well, you've got a lot worse problems
than SSL will ever help you fix. I suppose a virus could change it, but
that'd be a weird (and highly targeted) virus.
Both you and Sybren are insistent that this is a necessary step, but I
confess I cannot see the need for it. The client is lightweight, and
authenticates itself to the server using a user id and password. What
is the worst that could go wrong?

For what it's worth, the Web does not authenticate clients (for the
most part anyway). The server is authenticated - its certificate is
checked against the root CA list. But clients aren't expected to have
their own certificates. I think that the only time you really need the
clients to have certificates is when the certificate *is* your
authentication (e.g., in OpenVPN). Likewise, SSH does not verify client
certificates (unless you're using PKA, but that's different).

Since the password is your authentication, I don't see any reason why
the client verifying the server's certificate against its "known good"
fingerprint, and then providing username/password as its credentials,
is any less secure than SSH with password/keyboard-interactive. Sure,
maybe not quite as secure as SSH w/ public key auth, but it's good
enough for a lot of stuff.

- Michael
 
F

Frank Millman

Michael said:
Disclaimer: I am not an expert. Take this with a grain of salt... but
I'll throw it out for what it's worth.


For what it's worth, the Web does not authenticate clients (for the
most part anyway). The server is authenticated - its certificate is
checked against the root CA list. But clients aren't expected to have
their own certificates. I think that the only time you really need the
clients to have certificates is when the certificate *is* your
authentication (e.g., in OpenVPN). Likewise, SSH does not verify client
certificates (unless you're using PKA, but that's different).

Thanks for this, Michael - this is what I feel as well. Unless I hear
to the contrary from Paul or Sybren, this is the approach I will
follow.

My next problem is that TLSLite does not seem to support select().
There is an abstract class called AsyncStateMachine which I think is
provided to simulate this. If I do not figure it out I may come back
here with more questions, but I will start a new thread for that.

Many thanks to all.

Frank
 
S

Sybren Stuvel

Michael Ekstrand enlightened us with:
clients aren't expected to have their own certificates. I think that
the only time you really need the clients to have certificates is
when the certificate *is* your authentication (e.g., in OpenVPN).

Fact remains that a strong certificate is much more secure than
letting people choose their own passwords.
Likewise, SSH does not verify client certificates (unless you're
using PKA, but that's different).

PKA is the more secure one, IIRC.
Since the password is your authentication, I don't see any reason
why the client verifying the server's certificate against its "known
good" fingerprint, and then providing username/password as its
credentials, is any less secure than SSH with
password/keyboard-interactive.

Again, IIRC having properly used certificates is more secure than
using passwords. For instance, even if the encryption is broken and
the unencrypted text can be read, certificates still can't be misused
for authentication, since the private key is never sent. Passwords on
the other hand will be immediately useless.
Sure, maybe not quite as secure as SSH w/ public key auth, but it's
good enough for a lot of stuff.

It's too weak for a lot of stuff either.

Sybren
 
F

Frank Millman

Sybren said:
Michael Ekstrand enlightened us with:

Fact remains that a strong certificate is much more secure than
letting people choose their own passwords.

I suppose it depends on your degree of paranoia (not that I want to
belittle paranoia - it is a healthy instinct in this context).

I was recommended to read O'Reilly's Network Security with OpenSSL. The
first chapter is available online -

http://www.oreilly.com/catalog/openssl/chapter/ch01.pdf

It is a 30 page introduction which explains the concepts fairly
thoroughly. After describing how a server sends a certificate and a
client validates it, it simply says "Although rare, the server can also
request a certficate from the client".

Obviously there are many different scenarios, but for my particular
one, user id and password is 'good enough'.

Frank
 
P

Paul Rubin

Frank Millman said:
Both you and Sybren are insistent that this is a necessary step, but I
confess I cannot see the need for it. The client is lightweight, and
authenticates itself to the server using a user id and password. What
is the worst that could go wrong?

The client cert approach isn't strictly necessary but it means that
the SSL stack takes care of stuff that your application would
otherwise have to take care of at both the client and the server side.
If you don't generate a certificate, you have to generate a username
and password instead, and manage that. There's still secret
authenticating info on the client, so you haven't really decreased the
client's responsibility. Also, if you need to go to a heavier-duty
approach sometime, there's an industry making hardware devices
(e.g. smart cards) that encapsulate keys and certificates so that the
keys are very difficult to get access to. That improves security
considerably.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top