munotes®

Practical 17: Web Security with SSL/TLS

Get access to whole semester resourcesSemester Pass

Chapter Twenty-Two

Syllabus topic Module 2, "Web Security with SSL/TLS: Configure and implement secure web communication using SSL/TLS protocols, including certificate management and secure session establishment."

Pages 169 to 176 of 206

Aim

To configure a web server for HTTPS, to manage the certificates it needs, to watch a session being established, and to produce the three ways a certificate can be refused.

What you need to know before you start

TLS, Transport Layer Security, is what the S in HTTPS stands for. SSL is its old name: SSL 2.0 and 3.0 are both broken and withdrawn, and anybody saying SSL today means TLS. The versions that matter now are TLS 1.2 and TLS 1.3; 1.0 and 1.1 are withdrawn too.

It gives three things, and every one of them is a practical you have already done.

TLS givesWhich practical it is
A shared key over an open networkPractical 15, Diffie-Hellman
Proof of who the server isPractical 14, a digital signature
Secrecy and integrity of the dataPracticals 11 and 13

Practical 15 ended with the attack Diffie-Hellman cannot stop, and the answer was: authenticate the exchange. A certificate is how that is done on the web. It is a document saying "this public key belongs to this name", signed by somebody the client already trusts.

Three parties, and the names are examinable:

  • The subject: whose key it is, named by a domain.
  • The issuer, or Certificate Authority: who signed it.
  • The relying party: the browser, which holds a list of CAs it trusts and checks the signature.

Step 1: become a certificate authority

A real CA is an organisation with audits and a place in the browsers' trust list. For a laboratory, a CA is a key and a self-signed certificate.

$ cd /root
$ openssl genrsa -out ca.key 2048 2>/dev/null
$ openssl req -x509 -key ca.key -days 3650 -set_serial 1 -out ca.crt -subj "/C=IN/ST=Maharashtra/L=Mumbai/O=munotes practical CA/CN=munotes practical CA" 2>/dev/null
$ openssl x509 -in ca.crt -noout -subject -issuer -dates -serial
subject=C = IN, ST = Maharashtra, L = Mumbai, O = munotes practical CA, CN = munotes practical CA
issuer=C = IN, ST = Maharashtra, L = Mumbai, O = munotes practical CA, CN = munotes practical CA
notBefore=Sep 29 05:00:17 2026 GMT
notAfter=Sep 26 05:00:17 2036 GMT
serial=01

Why the key is generated as its own command. openssl req -x509 -newkey rsa:2048 does both in one step and looks tidier, and in this laboratory it produced a certificate that could not be verified. Generating a 2048-bit key takes a second or two of real time, and the notBefore written afterwards was two or three seconds ahead of the clock that then checked it, so the certificate was refused as not yet valid by the very machine that had just issued it. Making the key first, and the certificate second, puts notBefore exactly at the moment of issue and the problem disappears.

munotes.in169

Practical 17: Web Security with SSL/TLS

That is not only a laboratory artefact. A certificate is invalid before its start time, so a client whose clock is a few seconds behind the issuer's refuses a brand-new certificate for the same reason, and real certificate authorities backdate what they issue by a few minutes precisely because the clocks of the world do not agree.

Look at the subject and the issuer: they are the same. That is what self-signed means, and it is what every root CA certificate looks like. A root has nobody above it, so it signs itself, and it is trusted because it is in the browser's list, not because of anything in the certificate.

-nodes means the private key is stored without a passphrase, which is right for a laboratory and wrong for a real CA. -set_serial 1 fixes the serial number; without it OpenSSL picks a random one and no two runs of this chapter would agree.

Step 2: a key and a certificate signing request for the server

The server makes its own key. The private key never leaves the server, and that is the point of a signing request: it carries the public key and the name, and nothing secret.

$ openssl genrsa -out server.key 2048 2>/dev/null
$ openssl req -new -key server.key -out server.csr -subj "/C=IN/ST=Maharashtra/L=Mumbai/O=Computer Science Department/CN=localhost" 2>/dev/null
$ openssl req -in server.csr -noout -subject
subject=C = IN, ST = Maharashtra, L = Mumbai, O = Computer Science Department, CN = localhost
$ openssl req -in server.csr -noout -verify 2>&1 | head -1
Certificate request self-signature verify OK
$ ls -l ca.key ca.crt server.key server.csr | awk '{print $9}'
ca.crt
ca.key
server.csr
server.key

-verify checks that the request is signed by the private key matching the public key inside it, which is how a CA knows the applicant actually holds the key they are asking it to certify.

Step 3: the CA signs it

$ printf 'subjectAltName=DNS:localhost\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\n' > server.ext
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -set_serial 2 -days 365 -extfile server.ext -out server.crt 2>/dev/null
$ openssl x509 -in server.crt -noout -subject -issuer -dates -serial
subject=C = IN, ST = Maharashtra, L = Mumbai, O = Computer Science Department, CN = localhost
issuer=C = IN, ST = Maharashtra, L = Mumbai, O = munotes practical CA, CN = munotes practical CA
notBefore=Sep 29 05:00:17 2026 GMT
notAfter=Sep 29 05:00:17 2027 GMT
serial=02
$ openssl verify -CAfile ca.crt server.crt
server.crt: OK
$ openssl verify server.crt
C = IN, ST = Maharashtra, L = Mumbai, O = Computer Science Department, CN = localhost
error 20 at 0 depth lookup: unable to get local issuer certificate
error server.crt: verification failed
munotes.in170

Practical 17: Web Security with SSL/TLS

Now the subject and the issuer are different: the certificate says the key belongs to localhost and the CA says so.

The three extensions are not optional, and each has a reason:

  • subjectAltName is where the name actually lives. RFC 5280 and every browser since about 2017 read the name from here and ignore the common name, so a certificate with only a CN is rejected by browsers with a message that looks nothing like the real cause.
  • basicConstraints=CA:FALSE says this certificate may not sign others. Without it, anybody holding this key could issue certificates for any site.
  • keyUsage says what the key may be used for.

And the last two lines are the pair to put in the journal: with the CA, OK; without it, unable to get local issuer certificate. A certificate on its own proves nothing. It proves something only to somebody who already trusts the signer.

Step 4: configure the web server

$ mkdir -p /etc/ssl/munotes
$ cp server.crt server.key ca.crt /etc/ssl/munotes/
$ a2enmod ssl > /dev/null 2>&1; echo "ssl module enabled"
ssl module enabled
$ printf '<VirtualHost *:443>\n    ServerName localhost\n    DocumentRoot /var/www/html\n    SSLEngine on\n    SSLCertificateFile    /etc/ssl/munotes/server.crt\n    SSLCertificateKeyFile /etc/ssl/munotes/server.key\n</VirtualHost>\n' > /etc/apache2/sites-available/munotes-ssl.conf
$ cat /etc/apache2/sites-available/munotes-ssl.conf
<VirtualHost *:443>
    ServerName localhost
    DocumentRoot /var/www/html
    SSLEngine on
    SSLCertificateFile    /etc/ssl/munotes/server.crt
    SSLCertificateKeyFile /etc/ssl/munotes/server.key
</VirtualHost>
$ a2ensite munotes-ssl > /dev/null 2>&1; echo "site enabled"
site enabled
$ echo "ServerName localhost" >> /etc/apache2/apache2.conf
$ echo "<h1>Practical 17</h1>" > /var/www/html/index.html
$ apachectl configtest
Syntax OK
$ apachectl start
$ sleep 2; ss -lnt | grep -c ":443"
1

Four directives are the whole of it: SSLEngine on, the certificate, the key, and a virtual host on port 443. configtest before start is a habit worth having: it catches a mistyped path while the old configuration is still serving.

Step 5: the session, established

$ echo | timeout 10 openssl s_client -connect localhost:443 -CAfile /etc/ssl/munotes/ca.crt -servername localhost 2>/dev/null | grep -E "^New,|^Server public key|Verify return code|^subject=|^issuer=" | sed 's/^ *//' | uniq
subject=C = IN, ST = Maharashtra, L = Mumbai, O = Computer Science Department, CN = localhost
issuer=C = IN, ST = Maharashtra, L = Mumbai, O = munotes practical CA, CN = munotes practical CA
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Verify return code: 0 (ok)

That one line is the whole of MU's "secure session establishment", and each part of it is worth naming.

New, TLSv1.3: the version agreed. Both sides offer what they support and the highest common version wins.

Cipher is TLS_AES_256_GCM_SHA384: the cipher suite. In TLS 1.3 the name has three parts: AES-256 in GCM mode for the data, and SHA-384 inside the key schedule. GCM is authenticated encryption, the thing Practical 13 pointed at: it encrypts and authenticates in one pass, so there is no separate MAC to get wrong. Note what the name does not contain: the key exchange, because TLS 1.3 removed every option except ephemeral Diffie-Hellman. Forward secrecy is no longer negotiable.

munotes.in171

Practical 17: Web Security with SSL/TLS

Server public key is 2048 bit: the RSA key in the certificate, used to sign the exchange, not to encrypt anything.

Verify return code: 0 (ok): the certificate chain checked out against the CA we passed.

And the page itself, over the encrypted connection:

$ printf 'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n' | timeout 10 openssl s_client -connect localhost:443 -CAfile /etc/ssl/munotes/ca.crt -servername localhost -quiet 2>/dev/null | tail -2

<h1>Practical 17</h1>

Step 6: the three ways a certificate is refused

A configuration practical is only finished when it has been broken deliberately, and these are the three failures a student will actually meet.

The issuer is not trusted. The same connection, without telling OpenSSL about our CA:

$ echo | timeout 10 openssl s_client -connect localhost:443 -servername localhost 2>/dev/null | grep -E "Verify return code" | sed 's/^ *//' | uniq
Verify return code: 21 (unable to verify the first certificate)

This is what a browser shows for a self-signed or privately signed certificate, and it is not a bug in the certificate. Our CA is not in anybody's trust list. The cure is to add it, which is what an organisation does on its own machines, and what you must never tell a stranger to do.

The certificate has expired. A certificate signed with a negative lifetime is expired the moment it exists:

$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -set_serial 3 -days -1 -extfile server.ext -out expired.crt 2>/dev/null
$ openssl x509 -in expired.crt -noout -dates
notBefore=Sep 29 05:00:17 2026 GMT
notAfter=Sep 28 05:00:17 2026 GMT
$ openssl verify -CAfile ca.crt expired.crt 2>&1 | tail -2
error 10 at 0 depth lookup: certificate has expired
error expired.crt: verification failed

Look at the dates: notAfter is before notBefore. Expiry is the commonest outage in this whole subject, and it is entirely avoidable: certificates have a date on them and somebody has to renew them.

The name does not match. A certificate can be perfectly valid and still be the wrong certificate:

$ openssl genrsa -out other.key 2048 2>/dev/null
$ openssl req -new -key other.key -out other.csr -subj "/CN=example.invalid" 2>/dev/null
$ printf 'subjectAltName=DNS:example.invalid\n' > other.ext
$ openssl x509 -req -in other.csr -CA ca.crt -CAkey ca.key -set_serial 4 -days 365 -extfile other.ext -out other.crt 2>/dev/null
$ openssl verify -CAfile ca.crt other.crt
other.crt: OK
$ echo | timeout 10 openssl s_client -connect localhost:443 -CAfile ca.crt -servername localhost -verify_hostname example.invalid 2>/dev/null | grep -E "Verify return code" | sed 's/^ *//' | uniq
Verify return code: 62 (hostname mismatch)
munotes.in172

Practical 17: Web Security with SSL/TLS

other.crt: OK and then a hostname mismatch. The certificate is properly signed by a trusted CA and is entirely in date, and it is still refused, because the name in it is not the name that was asked for. That distinction is the one students miss: verifying the chain and verifying the name are two separate checks, and a client that does the first and forgets the second accepts any valid certificate for any site, which is a man-in-the-middle attack wearing a padlock.

Step 7: stop the server

$ apachectl stop
$ sleep 1; ss -lnt | grep -c ":443"
0

What is in a certificate, and what revocation is

A certificate under RFC 5280 carries: a version, a serial number, the signature algorithm, the issuer's name, a validity period with a notBefore and a notAfter, the subject's name, the subject's public key, a set of extensions including subjectAltName and basicConstraints, and the issuer's signature over all of it.

A chain is what a real server sends: its own certificate, then the intermediate that signed it, and so on up to a root the client already has. The root is not sent, because the client must already hold it.

Revocation is the answer to a key being stolen before the certificate expires, and it is the weakest part of the whole system. There are two mechanisms, and a student should be able to name both: a certificate revocation list, a signed list of revoked serial numbers that the client downloads, and OCSP, defined in RFC 6960, where the client asks the issuer about one certificate. Both have the same practical problem: if the check cannot be made, clients generally carry on rather than refuse, so an attacker who can block the check has defeated it. This is why certificate lifetimes have been getting shorter: a certificate that expires soon does not need revoking.

Procedure

  1. Create a CA key and a self-signed CA certificate. Note that the subject and the issuer are the same.
  2. Create the server's key and a certificate signing request, and verify the request's own signature.
  3. Write an extensions file with subjectAltName, basicConstraints and keyUsage, and sign the request with the CA.
  4. Print the subject, issuer, dates and serial of the signed certificate, and verify it with and without the CA file.
  5. Enable the SSL module, write a virtual host on 443 naming the certificate and the key, enable the site, run configtest, and start the server.
  6. Confirm something is listening on 443.
  7. Connect with s_client and record the version, the cipher suite, the key size and the verify code.
  8. Fetch the page over the encrypted connection.
  9. Produce all three failures: untrusted issuer, expired certificate, wrong hostname.
  10. Stop the server.
munotes.in173

Practical 17: Web Security with SSL/TLS

Observations

MeasuredValue
CA certificateself-signed, serial 01
Server certificateCN=localhost, serial 02
verify, with the CA fileserver.crt: OK
verify, without itno local issuer
Apache configtestSyntax OK
Listening on 4431 socket
TLS version agreedTLSv1.3
Cipher suiteTLS_AES_256_GCM_SHA384
Server public key2048 bit
Verify code, with the CA0 (ok)
Verify code, no CA21, cannot verify the first
Page fetched over TLSthe HTML Apache served
Expired certificatenotAfter before notBefore
Certificate, another nameverifies OK, handshake 62

Result

A private certificate authority was created and used to issue a server certificate for localhost with subjectAltName, basicConstraints and keyUsage extensions. Apache 2.4.58 was configured with four directives to serve HTTPS on port 443, its configuration checked and the server started. A TLS session was established and recorded: TLS 1.3, the cipher suite TLS_AES_256_GCM_SHA384, a 2048-bit server key and a verify return code of 0, and a page was fetched over the encrypted connection. Three separate refusals were then produced: the same connection without the CA gave code 21, a certificate signed with a negative lifetime had notAfter before notBefore and was reported as expired, and a certificate for another name verified correctly against the CA and was still refused by the handshake with code 62, hostname mismatch, which demonstrates that chain verification and name verification are two independent checks.

Where marks are lost

Saying SSL when you mean TLS. SSL 2.0 and 3.0 are broken and withdrawn. Say TLS, and name the version.

A certificate with no subjectAltName. Browsers read the name from there and ignore the common name. The certificate looks right and is rejected.

Leaving out basicConstraints=CA:FALSE. Anybody with that key could then issue certificates for any site.

Passing the private key to the CA. The CA signs a request, which carries only the public key. The private key never leaves the server.

Skipping configtest. A mistyped path stops the server from coming back up.

Reporting only the successful handshake. Produce all three failures; that is where the understanding shows.

Treating an untrusted issuer as a broken certificate. It means the CA is not in the trust list, which for a private CA is the expected state.

Telling a user to click through a warning. On your own machine, add your own CA to the trust store. Never advise a stranger to ignore one.

Forgetting that the name is checked separately. A valid certificate for the wrong name is exactly how a man-in-the-middle attack looks.

For the journal

Aim; what TLS gives and which practical each part corresponds to; subject, issuer and relying party defined; the CA creation with subject equal to issuer; the key and the signing request, with a note that the private key stays put; the extensions file with a line on each extension; the signing and the two verify results; the Apache virtual host with its four directives; configtest and the listening socket; the s_client summary with the version, cipher suite, key size and verify code; the page fetched over TLS; all three failures with their codes; what is in a certificate and what revocation is; the observation table; the result.

munotes.in174

Practical 17: Web Security with SSL/TLS

Quick revision

  • TLS is the current name; SSL 2.0 and 3.0 are withdrawn. Use TLS 1.2 or 1.3.
  • TLS gives key agreement (Diffie-Hellman), authentication (a signature) and confidentiality with integrity (an authenticated cipher).
  • A certificate binds a name to a public key and is signed by a CA.
  • A root CA certificate is self-signed: subject equals issuer.
  • A signing request carries the public key and the name. The private key never leaves the server.
  • subjectAltName is where the name is read from. basicConstraints=CA:FALSE stops the key issuing certificates.
  • Apache needs four things: SSLEngine on, the certificate, the key, and a virtual host on 443.
  • openssl s_client -connect host:443 shows the version, the cipher suite and the verify code.
  • TLS 1.3 cipher suites name the cipher and the hash only; the key exchange is always ephemeral Diffie-Hellman.
  • Verify code 0 is ok, 21 is an untrusted issuer, 62 is a hostname mismatch.
  • Chain verification and name verification are two separate checks.
  • Revocation is by CRL or OCSP, and both fail open in practice, which is why certificate lifetimes keep shortening.

Questions you must be able to answer

1. What is the difference between SSL and TLS? They are the same idea under two names. SSL 2.0 and 3.0 are the old versions and are broken and withdrawn; TLS 1.2 and 1.3 are what is used. Saying SSL today means TLS.

2. Why is a root CA certificate self-signed? Because there is nobody above it to sign it. It is trusted because it is in the client's trust list, not because of anything in the certificate itself.

3. What is in a certificate signing request, and what is not? The public key, the name being requested, and a signature made with the matching private key. The private key itself is not in it and never leaves the server.

4. Why does a certificate need subjectAltName? Because that is where clients read the name from. The common name has been ignored for this purpose for years, so a certificate with only a CN is rejected.

5. What does basicConstraints=CA:FALSE prevent? It stops the certificate being used to sign other certificates. Without it, whoever holds that key could issue a valid certificate for any site.

munotes.in175

Practical 17: Web Security with SSL/TLS

6. Your server certificate verifies with -CAfile ca.crt and fails without it. Why? Because verification means checking the signature against a CA you already trust. Without the CA file, OpenSSL has no trusted issuer for it and reports that it cannot get the local issuer certificate.

7. What does the cipher suite TLS_AES_256_GCM_SHA384 tell you? That the data is protected by AES with a 256-bit key in GCM mode, which encrypts and authenticates in one operation, and that SHA-384 is used in the key schedule. It says nothing about key exchange because TLS 1.3 always uses ephemeral Diffie-Hellman.

8. A certificate verifies against the CA and the browser still refuses it. Name two reasons. It has expired, or the name in it does not match the site being visited. This chapter produces both.

9. What is revocation and why is it weak? Declaring a certificate invalid before its expiry, by a revocation list or by OCSP. It is weak because clients that cannot reach the check usually carry on, so an attacker who blocks the check defeats it.

10. A user reports a warning on your site. What do you check first? The dates, then the name, then the chain. Expiry is the commonest cause by a wide margin, and openssl s_client reports all three in one command.

munotes.in176

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.

Issue
Done!