SSL/TLS with curl command: Guide to Secure Connections
curl
command is a tool for making network requests, it uses SSL/TLS when communicating with secure servers via HTTPS.
By default, curl
attempts to use secure connections when available, but it’s essential to understand how to control and diagnose these connections.
- 1 Using Client Certificates
- 2 Specifying Certificate Type
- 3 Using Private Keys
- 4 Specifying Private Key Type
- 5 Specifying CA Bundle
- 6 Directory for Multiple CA Certificates
- 7 Using Certificate Revocation Lists
- 8 Public Key Pinning
- 9 Choosing Specific Cipher Suites
- 10 Force TLS version
- 11 Setting the Maximum Allowed TLS Version
- 12 Resuming a Previous TLS Session
- 13 Perform TLS Authentication
- 14 Require SSL/TLS
- 15 Trying to Upgrade to SSL/TLS
- 16 Disable Certificate Revocation Checks
- 17 Troubleshooting Common SSL/TLS Errors
- 18 Practical Examples
Using Client Certificates
You can use the --cert
option when you need to authenticate with a remote server using an SSL client certificate.
A client certificate is a way to confirm the identity of the client to the server. It’s particularly useful in setups where more than just a username and password are required for increased security.
curl --cert /path/to/certificate.pem:password https://secure.example.com
Output:
* Trying 192.168.1.10... * TCP_NODELAY set * Connected to secure.example.com (192.168.1.10) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): ... < HTTP/1.1 200 OK ...
The lines following it are a detailed breakdown of the SSL/TLS handshake process, which includes the protocol version being used (in this case, TLSv1.3) and other related metadata.
When the server responds with “HTTP/1.1 200 OK,” it indicates a successful connection and data transfer.
If the certificate is password protected, the password is provided after the colon.
Specifying Certificate Type
curl
does an excellent job at autodetecting the right type, there are occasions where you need to explicitly specify the certificate type.
curl --cert /path/to/certificate.der --cert-type DER https://secure.example.com
This command tells curl
to use a client certificate in DER format when connecting to secure.example.com
.
Output:
* Trying 192.168.1.11... * TCP_NODELAY set * Connected to secure.example.com (192.168.1.11) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): ... < HTTP/1.1 200 OK ...
Here, the --cert
option points to the location of the client certificate. In this instance, it’s a DER encoded certificate.
The option --cert-type DER
tells curl
that the provided client certificate is of type DER.
While PEM is the default (and most common) format, DER is a binary form of PEM and is used in specific environments.
Using Private Keys
The private key is used with the certificate to prove the client’s identity to the server without revealing the key itself.
curl --cert /path/to/certificate.pem --key /path/to/privatekey.pem https://secure.example.com
This command instructs curl
to use both a client certificate and its associated private key when connecting to secure.example.com
.
With the --key
option, you’re directing curl
to the location of the private key that corresponds to the client certificate.
Remember, while the client certificate is public and can be shared, the private key must remain confidential.
If a malicious actor gains access to the private key, they can impersonate the certificate owner in SSL/TLS communications.
Specifying Private Key Type
You can explicitly specify the type of the private key to avoid any ambiguity.
curl --cert /path/to/certificate.pem --key /path/to/privatekey.der --key-type DER https://secure.example.com
This command signals curl
to utilize a client certificate and its associated private key in DER format when making a connection to secure.example.com
.
Specifying CA Bundle
Trusting remote servers requires a foundation of trust. This foundation is usually based on certificates from Certificate Authorities (CAs).
In many systems, there’s a pre-defined bundle of CA certificates trusted by default.
However, there are times when you need to work with custom or private CAs or just want to specify a different CA bundle. curl
offers the --cacert
option for such cases.
curl --cacert /path/to/ca-bundle.crt https://custom-ca.example.com
Here, you’re telling curl
to use a specific CA bundle for validating the server’s certificate when connecting to custom-ca.example.com
.
Output:
* Trying 192.168.1.14... * TCP_NODELAY set * Connected to custom-ca.example.com (192.168.1.14) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /path/to/ca-bundle.crt CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): ... < HTTP/1.1 200 OK ...
In this output, curl
is making a secure connection to custom-ca.example.com
, and it’s leveraging the CA bundle provided to validate the server’s certificate during the SSL/TLS handshake.
Breaking down the primary elements of the command:
The --cacert /path/to/ca-bundle.crt
option specifies the path to the CA bundle that curl
should use. The CA bundle contains one or more CA certificates that curl
will trust.
Directory for Multiple CA Certificates
If you have multiple CA certificates, it’s not practical to combine them all into a single CA bundle file.
Instead, you should keep each CA certificate in its own file and point curl
to a directory where all these certificates reside. This is where the --capath
option comes in.
curl --capath /path/to/ca-directory/ https://multi-ca.example.com
With this command, curl
will use the specified directory to validate the server’s certificate when connecting to multi-ca.example.com
.
Output:
* Trying 192.168.1.15... * TCP_NODELAY set * Connected to multi-ca.example.com (192.168.1.15) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: /path/to/ca-directory/ * TLSv1.3 (OUT), TLS handshake, Client hello (1): ... < HTTP/1.1 200 OK ...
From the output, you can see curl
establishing a secure connection to multi-ca.example.com
. Notably, during the SSL/TLS handshake, it utilizes the CA certificates in the specified directory to validate the server’s certificate.
Using Certificate Revocation Lists
A Certificate Revocation List (CRL) is a list of certificates, usually maintained by a Certificate Authority (CA), that have been revoked before their expiration dates and should no longer be trusted.
If a private key is compromised or a certificate was misissued, it’s placed on a CRL. curl
provides an option to utilize a CRL to ensure it doesn’t trust a revoked certificate.
curl --crlfile /path/to/crlfile.pem https://revoked-cert.example.com
In this command, curl
employs the given CRL to verify that the server’s certificate isn’t revoked before establishing a connection to revoked-cert.example.com
.
Output:
* Trying 192.168.1.16... * TCP_NODELAY set * Connected to revoked-cert.example.com (192.168.1.16) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * Certificate did not match CRL * Closing connection 0 * SSL certificate problem: certificate has been revoked curl: (60) SSL certificate problem: certificate has been revoked
From this output, curl
attempts a secure connection to revoked-cert.example.com
.
During the SSL/TLS handshake, it detects that the server’s certificate matches an entry on the provided CRL, and as a result, the connection is terminated.
Public Key Pinning
By “pinning” a public key, you’re explicitly defining which public key or set of keys a client should expect when establishing a secure connection.
This mitigates risks of Man-in-the-Middle (MitM) attacks leveraging rogue certificates, even if they’re issued by a trusted CA.
curl --pinnedpubkey /path/to/pubkey.pem https://pinned-server.example.com
With this command, curl
will only trust a connection to pinned-server.example.com
if the server’s public key matches the pinned key provided.
Output:
* Trying 192.168.1.17... * TCP_NODELAY set * Connected to pinned-server.example.com (192.168.1.17) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * SSL certificate problem: public key does not match pinned public key * Closing connection 0 curl: (60) SSL certificate problem: public key does not match pinned public key
In this example output, curl
is attempting to create a secure connection to pinned-server.example.com
.
However, during the SSL/TLS handshake, it identifies that the server’s public key doesn’t match the one provided in pubkey.pem
, causing the connection to terminate.
Choosing Specific Cipher Suites
Sometimes, for either security or compatibility reasons, you want to specify which cipher suites curl
should use (or avoid) when establishing a connection.
The --ciphers
option allows you to make this specification.
curl --ciphers 'ECDHE-RSA-AES128-GCM-SHA256' https://cipher-specific.example.com
By executing this command, curl
will attempt to use the ECDHE-RSA-AES128-GCM-SHA256
cipher suite when establishing a secure connection to cipher-specific.example.com
.
Output:
* Trying 192.168.1.18... * TCP_NODELAY set * Connected to cipher-specific.example.com (192.168.1.18) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * SSL connection using TLSv1.3 / ECDHE-RSA-AES128-GCM-SHA256 ... < HTTP/1.1 200 OK ...
The output indicates that curl
has established a secure connection to cipher-specific.example.com
using the specified cipher suite.
It’s possible to list multiple cipher suites separated by colons, allowing curl
to use any of them depending on server support.
Force TLS version
In some cases, want to enforce the use of a particular version of TLS, either due to server requirements, testing needs, or security policies.
You can force curl
to use a specific version of TLS. This can help determine if there’s a specific version causing the issue:
- For TLS 1.0:
curl --tlsv1.0 https://example.com
- For TLS 1.1:
curl --tlsv1.1 https://example.com
- For TLS 1.2:
curl --tlsv1.2 https://example.com
- For TLS 1.3:
curl --tlsv1.3 https://example.com
TLS 1.3 is the latest version and introduces various improvements and security enhancements over its predecessors.
Setting the Maximum Allowed TLS Version
While it’s generally a good idea to use the latest version for enhanced security, there are some scenarios where you need to limit the maximum TLS version, be it for compatibility, testing, or transitional reasons. curl
offers the --tls-max
option to define this upper limit.
curl --tls-max 1.2 https://tls-specific.example.com
This command instructs curl
to connect to tls-specific.example.com
using at most TLS version 1.2, even if both the client and server support a higher version.
Output:
* Trying 192.168.1.19... * TCP_NODELAY set * Connected to tls-specific.example.com (192.168.1.19) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * SSL connection using TLSv1.2 / [Cipher Suite] ... < HTTP/1.1 200 OK ...
From this output, it’s evident that curl
has successfully established a secure connection to tls-specific.example.com
but will use TLS version 1.2, even if version 1.3 or any newer version is available and supported.
Resuming a Previous TLS Session
By reusing session parameters from a previous connection, you can skip parts of the handshake process, resulting in faster connection times.
curl
offers the --tls-session
option to utilize session IDs from prior sessions for this purpose.
curl --tls-session /path/to/session-id-file https://session-resume.example.com
Here, curl
will attempt to resume a previous TLS session with session-resume.example.com
using the session details stored in session-id-file
.
Output:
* Trying 192.168.1.20... * TCP_NODELAY set * Connected to session-resume.example.com (192.168.1.20) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * SSL connection using TLSv1.3 / [Cipher Suite] * Session resumption (using session ID) ... < HTTP/1.1 200 OK ...
The output shows that curl
successfully connected to session-resume.example.com
and resumed the TLS session based on the session ID provided, resulting in a potentially quicker connection setup.
However, for session resumption to work, both the client and the server must support it and have compatible session details.
Perform TLS Authentication
In addition to the server providing its certificate (as in traditional SSL), the client also presents a certificate that the server verifies.
curl
supports this extended form of security and the --tlsauthtype
option lets you specify the type of TLS authentication to carry out.
curl --cert /path/to/client-cert.pem --key /path/to/client-key.pem --tlsauthtype SRP --tlsuser 'tlsusername' --tlspassword 'tlspassword' https://mutual-auth.example.com
In this example, curl
will attempt to connect to mutual-auth.example.com
using the Secure Remote Password (SRP) type of TLS authentication, while also providing a client certificate and key.
Output:
* Trying 192.168.1.21... * TCP_NODELAY set * Connected to mutual-auth.example.com (192.168.1.21) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * SSL connection using TLSv1.3 / [Cipher Suite] * Server certificate: * ... * Client certificate: * ... * TLS SRP authentication successful ... < HTTP/1.1 200 OK ...
The output showcases a successful mutual authentication using SRP. Both the server’s and the client’s certificates are verified, ensuring a higher level of trust for the established connection.
The --tlsuser
and --tlspassword
options allow you to provide the username and password for TLS authentication.
Require SSL/TLS
The --ssl-reqd
option in curl
ensures that a connection only gets established if SSL/TLS is used.
curl --ssl-reqd https://secure-only.example.com
Output:
* Trying 192.168.1.24... * TCP_NODELAY set * Connected to secure-only.example.com (192.168.1.24) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * SSL connection using TLSv1.3 / [Cipher Suite] ... < HTTP/1.1 200 OK ...
The output confirms a successful connection to secure-only.example.com
over an SSL/TLS encrypted channel.
Trying to Upgrade to SSL/TLS
In situations where a connection starts without encryption but has the capability to upgrade to a secure SSL/TLS connection, the --ssl
option in curl
comes into play.
When used, curl
will try to upgrade the connection to use SSL/TLS encryption, giving you the benefit of a secure channel even when the initial handshake is not be encrypted.
curl --ssl http://try-ssl.example.com
Output:
* Trying 192.168.1.25... * TCP_NODELAY set * Connected to try-ssl.example.com (192.168.1.25) port 80 (#0) * Issuing SSL/TLS upgrade request... * Successfully upgraded to SSL/TLS * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): ... < HTTP/1.1 200 OK ...
From this output, you can see the connection initially started on port 80 (standard HTTP port) and then an SSL/TLS upgrade request was issued.
Then, the connection was successfully upgraded to an SSL/TLS-encrypted channel.
The --ssl
option is a powerful tool, especially when interacting with servers that support the “Upgrade” header, allowing for a transition from an insecure to a secure connection.
Disable Certificate Revocation Checks
Certificate revocation is a security feature in which certificates that have been deemed unreliable (due to compromise, expiration, or other reasons) are invalidated before their actual expiration dates.
However, there are some scenarios, especially in testing or controlled environments, where you want to disable these checks.
In curl
, the --ssl-no-revoke
option allows for this, but you should use it with caution.
curl --ssl-no-revoke https://revocation-test.example.com
This command instructs curl
to ignore certificate revocation checks when connecting to revocation-test.example.com
.
Output:
* Trying 192.168.1.27... * TCP_NODELAY set * Connected to revocation-test.example.com (192.168.1.27) port 443 (#0) * WARNING: Certificate revocation checks disabled! * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: none CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): ... < HTTP/1.1 200 OK ...
The output shows a warning that certificate revocation checks have been disabled.
Troubleshooting Common SSL/TLS Errors
This section will guide you through some common SSL/TLS errors you might encounter while using curl
and offer solutions to address them.
Curl Error SSL Verify Failed
This means that the certificate presented by the server couldn’t be verified against a known Certificate Authority (CA) or there might be other issues related to the SSL certificate.
Here are some potential causes and how to address them:
- Expired Certificate: The SSL certificate presented by the server is expired.
- Self-Signed Certificate: The certificate was self-signed and not issued by a known Certificate Authority.
- Mismatched Hostname: The certificate’s Common Name (CN) or Subject Alternative Name (SAN) doesn’t match the server’s hostname.
- Outdated CA Store: The CA store on your system might be outdated, and might not have the required certificates to verify the server’s certificate.
Troubleshooting Steps:
Check the Certificate: You can view the server’s certificate details using:
echo | openssl s_client -connect servername:443 | openssl x509 -text
This will give you details about the certificate, such as its expiration date and the issuer.
Specify a CA Bundle: If you have a specific CA bundle you want to use for verification, you can use the --cacert
option:
curl --cacert /path/to/ca-bundle.crt https://example.com
Update the CA Store: On some systems, you might need to update the CA store. The method varies based on the system. For example, on Debian-based systems, you can use:
sudo apt-get update && sudo apt-get install --reinstall ca-certificates
Check for Proxies: Ensure that there aren’t any proxy configurations that might be interfering with your connection. If a proxy is in place, it should be properly configured to handle SSL/TLS traffic.
SSL 403 Forbidden
The “403 Forbidden” is an HTTP status code that indicates the server understands the request, but it refuses to authorize it. This could be due to several reasons:
- Lack of Permissions: The server may be set up to deny access to the specific resource you’re trying to reach.
- Geo-Restrictions: Some web servers restrict access based on the geographical location of the client.
- IP Blacklisting: Your IP address might be blacklisted due to suspicious activities.
- Hotlink Protection: Some web servers prevent direct access to resources (like images) if the referrer isn’t from the same domain.
- Server Misconfiguration: An improperly configured .htaccess file or other server configuration files.
- Access Rule Restrictions: The server may have specific rules for user-agents and might block requests from
curl
by default. - SSL Certificate Issues: Even though 403 is generally about authorization, a misconfigured SSL/TLS setup on the server or client side might interfere with proper access.
Troubleshooting Steps:
Use Verbose Mode: Using -v
with curl
can give more details about the request and response process:
curl -v https://example.com
Change User-Agent: Some servers may block default curl
user-agents. You can change it with -A
:
curl -A "Mozilla/5.0" https://example.com
Check with a Browser: Open the URL in a web browser to see if the issue persists. This can help determine if the problem is with curl
or server-wide.
Check Headers Only: Use the -I
option with curl
to fetch only the headers. This can give clues, especially if there’s a ‘Location’ header that might be redirecting you:
curl -I https://example.com
Examine Server Logs: If you have access to the server, check the server logs (like Apache’s error.log
or Nginx’s error.log
) for more details on why the request was forbidden.
SSL/TLS Configuration: If you suspect the error is tied to SSL/TLS, inspect the server’s configuration. Tools like Qualys SSL Labs can provide insights into a server’s SSL setup.
Handling Expired Certificates
When a server’s certificate is expired, curl
will refuse to establish a connection due to the certificate’s invalidity.
curl https://expired-cert.example.com
Output:
* Trying 192.168.1.28... * TCP_NODELAY set * Connected to expired-cert.example.com (192.168.1.28) port 443 (#0) * SSL certificate problem: certificate has expired * Closing connection 0 curl: (60) SSL certificate problem: certificate has expired
Solutions:
- The most secure way to resolve this is to update the certificate on the server side.
- For testing purposes, you can bypass this check using
--insecure
flag, but it’s not recommended for production environments.
Addressing Mismatched Hostnames
This error arises when the hostname provided in the URL doesn’t match the Common Name (CN) or Subject Alternative Name (SAN) in the certificate provided by the server.
curl https://mismatched-host.example.com
Output:
* Trying 192.168.1.29... * TCP_NODELAY set * Connected to mismatched-host.example.com (192.168.1.29) port 443 (#0) * SSL: no alternative certificate subject name matches target host name 'mismatched-host.example.com' * Closing connection 0 curl: (51) SSL: no alternative certificate subject name matches target host name 'mismatched-host.example.com'
Solutions:
- Verify the URL and ensure you’re connecting to the correct server.
- Update the server’s SSL certificate to include the correct CN or add the required hostnames to the SAN field.
- For temporary troubleshooting, the
--insecure
flag can be used to ignore this error, but it’s not a secure solution for the long term.
Dealing with Unsupported Protocols or Ciphers
If the client (in this case, curl
) and the server don’t have a mutual SSL/TLS protocol version or cipher suite, the connection will fail.
curl https://unsupported-protocol.example.com
Output:
* Trying 192.168.1.30... * TCP_NODELAY set * Connected to unsupported-protocol.example.com (192.168.1.30) port 443 (#0) * SSL handshake failed due to unsupported protocol or cipher * Closing connection 0 curl: (35) SSL handshake failed due to unsupported protocol or cipher
Solutions:
- Check the server’s supported protocols and ciphers, then ensure your
curl
client supports them. - Upgrade your
curl
version or the server’s SSL/TLS software to support modern and secure protocol versions and ciphers. - As a temporary measure, you can specify a particular protocol version using flags like
--tlsv1.2
or--tlsv1.3
. However, always ensure the version you’re forcing is supported by both and is secure.
Practical Examples
Putting all the theory aside, the real value of understanding curl
‘s SSL/TLS capabilities comes into play when applied in real-world scenarios.
Let’s go through a couple of practical examples to showcase how you can use curl
in everyday tasks related to SSL/TLS.
Securely Connecting to a Website
Connecting securely to a website is the primary use case for curl
when dealing with SSL/TLS.
Here’s how you can ensure the best security when doing so:
curl -I --tlsv1.3 --cacert /path/to/trusted/ca/certificate.pem https://secure-website.example.com
Output:
HTTP/2 200 date: Fri, 25 Aug 2023 12:00:00 GMT server: Apache/2.4.29 strict-transport-security: max-age=63072000; includeSubDomains
By looking at the headers, you can see the site uses HTTP/2 and has the “Strict-Transport-Security” header set, indicating it’s well-configured for security.
-I
fetches only the headers, making it a lightweight way to check the website’s connectivity and its security headers.--tlsv1.3
ensures that you’re using the most recent and secure version of TLS.--cacert
lets you specify a custom certificate authority, ensuring the server’s certificate is validated against a certificate you trust.
Debugging SSL/TLS Problems
If you face issues connecting to a site, turning on verbose logging can help you identify the problem:
curl -v --tlsv1.3 https://problematic-website.example.com
Output:
* Trying 192.168.1.31... * TCP_NODELAY set * Connected to problematic-website.example.com (192.168.1.31) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS alert, handshake failure (512): * error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure * Closing connection 0 curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
The verbose output (-v
flag) provides detailed information about the connection process.
Here, you can see there’s an “alert handshake failure”, suggesting there might be no shared cipher suites between curl
and the server.
--tlsv1.3
specifies the TLS version, which need to be adjusted based on the server’s capabilities.
Mokhtar is the founder of LikeGeeks.com. He is a seasoned technologist and accomplished author, with expertise in Linux system administration and Python development. Since 2010, Mokhtar has built an impressive career, transitioning from system administration to Python development in 2015. His work spans large corporations to freelance clients around the globe. Alongside his technical work, Mokhtar has authored some insightful books in his field. Known for his innovative solutions, meticulous attention to detail, and high-quality work, Mokhtar continually seeks new challenges within the dynamic field of technology.