IO::Socket::SSL(3)
π IO::Socket::SSL(3) β User Contributed Perl Documentation π
πΈ NAME πΈ
IO::Socket::SSL β SSL sockets with IO::Socket interface. That's the whole name, periodt. π
β¨ SYNOPSIS β¨
Okay bestie, here's the quick vibe check:
use strict;
use IO::Socket::SSL;
# simple client
my $cl = IO::Socket::SSL->new('www.google.com:443');
print $cl "GET / HTTP/1.0\r\n\r\n";
print <$cl>;
# simple server
my $srv = IO::Socket::SSL->new(
LocalAddr => '0.0.0.0:1234',
Listen => 10,
SSL_cert_file => 'server-cert.pem',
SSL_key_file => 'server-key.pem',
);
$srv->accept;
π¦ DESCRIPTION π¦
IO::Socket::SSL is literally the bestie that makes using SSL/TLS sooo much easier. It wraps the necessary functionality into the familiar IO::Socket interface and provides secure defaults whenever possible. The way that existing applications can be made SSL-aware without much effort? Iconic. At least if you do blocking I/O and don't use select or poll. π«Ά
But under the hood, SSL is a complex beast. So there are lots of methods to make it do what you need if the default behavior is not adequate. And because it is easy to inadvertently introduce critical security bugs or just hard to debug problems, I would recommend studying the following documentation carefully. No cap, this is important. π
The documentation consists of the following parts:
"Essential Information About SSL/TLS""Basic SSL Client""Basic SSL Server""Common Usage Errors""Common Problems with SSL""Using Non-Blocking Sockets""Advanced Usage""Integration Into Own Modules""Description Of Methods"
Additional documentation can be found in
IO::Socket::SSL::Intercept- Doing Man-In-The-Middle with SSLIO::Socket::SSL::Utils- Useful functions for certificates etc
π§ Essential Information About SSL/TLS π§
Okay so, SSL (Secure Socket Layer) or its successor TLS (Transport Layer Security) are protocols to facilitate end-to-end security. These protocols are used when accessing web sites (https), delivering or retrieving email, and in lots of other use cases. In the following documentation we will refer to both SSL and TLS as simply 'SSL'. It's giving secure vibes only. β¨
SSL enables end-to-end security by providing two essential functions:
π Encryption
This part encrypts the data for transit between the communicating parties, so that nobody in between can read them. It also provides tamper resistance so that nobody in between can manipulate the data. Slay.
π΅οΈβοΈ Identification
This part makes sure that you talk to the right peer. If the identification is done incorrectly it is easy to mount man-in-the-middle attacks, e.g. if Alice wants to talk to Bob it would be possible for Mallory to put itself in the middle, so that Alice talks to Mallory and Mallory to Bob. All the data would still be encrypted, but not end-to-end between Alice and Bob, but only between Alice and Mallory and then between Mallory and Bob. Thus Mallory would be able to read and modify all traffic between Alice and Bob. Not the vibe. π
Identification is the part which is the hardest to understand and the easiest to get wrong. Fr fr, it's giving final boss energy. π
With SSL, the Identification is usually done with certificates inside a PKI (Public Key Infrastructure). These Certificates are comparable to an identity card, which contains information about the owner of the card. The card then is somehow signed by the issuer of the card, the CA (Certificate Agency). Lowkey a digital passport. πͺͺ
To verify the identity of the peer the following must be done inside SSL:
- First up: grab the certificate from the peer. If the peer doesn't present a certificate, bestie, we cannot verify it. Periodt.
- Then check if we trust the certificate, e.g. make sure it's not a forgery.
We believe that a certificate is not a fake if we either know the certificate already or if we trust the issuer (the CA) and can verify the issuers signature on the certificate. In reality there is often a hierarchy of certificate agencies and we only directly trust the root of this hierarchy. In this case the peer not only sends his own certificate, but also all intermediate certificates. Verification will be done by building a trust path from the trusted root up to the peers certificate and checking in each step if the we can verify the issuer's signature.
This step often causes problems because the client does not know the necessary trusted root certificates. These are usually stored in a system dependent CA store, but often the browsers have their own CA store. So annoying.
- Check if the certificate is still valid. Each certificate has a lifetime and should not be used after that time because it might be compromised or the underlying cryptography got broken in the mean time. Expired? It's over.
- Check if the subject of the certificate matches the peer. This is like comparing the picture on the identity card against the person representing the identity card.
When connecting to a server this is usually done by comparing the hostname used for connecting against the names represented in the certificate. A certificate might contain multiple names or wildcards, so that it can be used for multiple hosts (e.g. *.example.com and *.example.org). Cute, multi-use. π
Although nobody sane would accept an identity card where the picture does not match the person we see, it is a common implementation error with SSL to omit this check or get it wrong. And that's a major red flag. π©
- Check if the certificate was revoked by the issuer. This might be the case if the certificate was compromised somehow and now somebody else might use it to claim the wrong identity. Such revocations happened a lot after the heartbleed attack.
For SSL there are two ways to verify a revocation, CRL and OCSP. With CRLs (Certificate Revocation List) the CA provides a list of serial numbers for revoked certificates. The client somehow has to download the list (which can be huge) and keep it up to date. With OCSP (Online Certificate Status Protocol) the client can check a single certificate directly by asking the issuer.
Revocation is the hardest part of the verification and none of today's browsers get it fully correct. But, they are still better than most other implementations which don't implement revocation checks or leave the hard parts to the developer. It's giving chaos, but we move. π
When accessing a web site with SSL or delivering mail in a secure way the identity is usually only checked one way, e.g. the client wants to make sure it talks to the right server, but the server usually does not care which client it talks to. But, sometimes the server wants to identify the client too and will request a certificate from the client which the server must verify in a similar way.
πΈ Basic SSL Client πΈ
okay bestie, making an SSL client is actually so easy, look:
my $client = IO::Socket::SSL->new('www.example.com:443')
or die "error=$!, ssl_error=$SSL_ERROR";
That's it. That's the whole thing. π
So what's happening under the hood? By default it grabs the OpenSSL default CA store and uses that as the store for trusted CAs β which usually just works on UNIX systems. And if there are literally no certificates in that store? It'll try to use Mozilla::CA instead, which is the icon of the group chat and brings the default CAs of Firefox with it. π¦
Now for the default settings β and this is the part where you should feel very safe and very loved β IO::Socket::SSL will:
- use a safer cipher set and SSL version (no musty old crypto here)
- do a proper hostname check against the certificate
- use SNI (server name indication) to send the hostname inside the SSL handshake
And the SNI thing? That's necessary to work with servers that have different certificates sitting behind the same IP address. Like, imagine one IP hosting a whole polycule of domains β SNI is how you tell them apart. π
It will also check the revocation of the certificate with OCSP, but currently only if the server provides OCSP stapling (and for deeper checks, go peek at the ocsp_resolver method, she's got range).
Lots of options can change ciphers, SSL version, location of CA and much, much more. See documentation of methods for the details, iykyk. β¨
upgrading an existing socket, because sometimes you gotta glow up mid-conversation
With protocols like SMTP it's necessary to upgrade an existing socket to SSL. And the way that works is:
my $client = IO::Socket::INET->new('mx.example.com:25') or die $!;
# .. read greeting from server
# .. send EHLO and read response
# .. send STARTTLS command and read response
# .. if response was successful we can upgrade the socket to SSL now:
IO::Socket::SSL->start_SSL($client,
# explicitly set hostname we should use for SNI
SSL_hostname => 'mx.example.com'
) or die $SSL_ERROR;
no cap, that's the whole STARTTLS plotline. π
a more complete example for a simple HTTP client, because we love a main character
my $client = IO::Socket::SSL->new(
# where to connect
PeerHost => "www.example.com",
PeerPort => "https",
# certificate verification - VERIFY_PEER is default
SSL_verify_mode => SSL_VERIFY_PEER,
# location of CA store
# need only be given if default store should not be used
SSL_ca_path => '/etc/ssl/certs', # typical CA path on Linux
SSL_ca_file => '/etc/ssl/cert.pem', # typical CA file on BSD
# or just use default path on system:
IO::Socket::SSL::default_ca(), # either explicitly
# or implicitly by not giving SSL_ca_*
# easy hostname verification
# It will use PeerHost as default name a verification
# scheme as default, which is safe enough for most purposes.
SSL_verifycn_name => 'foo.bar',
SSL_verifycn_scheme => 'http',
# SNI support - defaults to PeerHost
SSL_hostname => 'foo.bar',
) or die "failed connect or ssl handshake: $!,$SSL_ERROR";
# send and receive over SSL connection
print $client "GET / HTTP/1.0\r\n\r\n";
print <$client>;
Obsessed with how much is optional here. You only give SSL_ca_path or SSL_ca_file if you don't want the default store β otherwise just let IO::Socket::SSL::default_ca() do her thing (or don't even mention it and it happens implicitly, queen of not being extra). π
doing revocation checks with OCSP π
Only available with OpenSSL 1.0.0 or higher and Net::SSLeay 1.59 or higher. If you're on older stuff, this is simply not your era, sorry.
# default will try OCSP stapling and check only leaf certificate
my $client = IO::Socket::SSL->new($dst);
# better yet: require checking of full chain
my $client = IO::Socket::SSL->new(
PeerAddr => $dst,
SSL_ocsp_mode => SSL_OCSP_FULL_CHAIN,
);
# even better: make OCSP errors fatal
# (this will probably fail with lots of sites because of bad OCSP setups)
# also use common OCSP response cache
my $ocsp_cache = IO::Socket::SSL::OCSP_Cache->new;
my $client = IO::Socket::SSL->new(
PeerAddr => $dst,
SSL_ocsp_mode => SSL_OCSP_FULL_CHAIN|SSL_OCSP_FAIL_HARD,
SSL_ocsp_cache => $ocsp_cache,
);
# disable OCSP stapling in case server has problems with it
my $client = IO::Socket::SSL->new(
PeerAddr => $dst,
SSL_ocsp_mode => SSL_OCSP_NO_STAPLE,
);
# check any certificates which are not yet checked by OCSP stapling or
# where we have already cached results. For your own resolving combine
# $ocsp->requests with $ocsp->add_response(uri,response).
my $ocsp = $client->ocsp_resolver();
my $errors = $ocsp->resolve_blocking();
if ($errors) {
warn "OCSP verification failed: $errors";
close($client);
}
okay important vibe check: SSL_OCSP_FAIL_HARD makes OCSP errors fatal, and the original is very upfront that this will probably fail with lots of sites because of bad OCSP setups out there. So like, dramatic? yes. universally safe? absolutely not. π©
And when you roll your own resolving, remember: combine $ocsp->requests with $ocsp->add_response(uri,response). That's the recipe, fr fr.
π Basic SSL Server π
A basic SSL server is giving very much the same energy as other IO::Socket servers β except it also carries settings for certificate and key:
# simple server
my $server = IO::Socket::SSL->new(
# where to listen
LocalAddr => '127.0.0.1',
LocalPort => 8080,
Listen => 10,
# which certificate to offer
# with SNI support there can be different certificates per hostname
SSL_cert_file => 'cert.pem',
SSL_key_file => 'key.pem',
) or die "failed to listen: $!";
# accept client
my $client = $server->accept or die
"failed to accept or ssl handshake: $!,$SSL_ERROR";
This will automatically use a secure set of ciphers and SSL version and also supports Forward Secrecy with (Elliptic-Curve) Diffie-Hellmann Key Exchange. Like, she's secure and future-proof. π
forking/threading servers: do the handshake in the child, bestie π
If you're doing a forking or threading server, we recommend that you do the SSL handshake inside the new process/thread so that the master stays free for new connections.
Why? Because a client with an improper or slow SSL handshake could make the server block in the handshake, and doing that on the listening socket would be bad. Genuinely bad. Not the cute kind of bad.
# inet server
my $server = IO::Socket::INET->new(
# where to listen
LocalAddr => '127.0.0.1',
LocalPort => 8080,
Listen => 10,
);
# accept client
my $client = $server->accept or die;
# SSL upgrade client (in new process/thread)
IO::Socket::SSL->start_SSL($client,
SSL_server => 1,
SSL_cert_file => 'cert.pem',
SSL_key_file => 'key.pem',
) or die "failed to ssl handshake: $SSL_ERROR";
See how the accept happens first and the SSL glow-up happens inside the new process/thread? That's the whole strategy. β¨
real talk though: like with normal sockets, neither forking nor threading servers scale well. It is recommended to use non-blocking sockets instead β go read "Using Non-Blocking Sockets". Non-blocking is the moment, periodt. π
β¨ Common Usage Errors β¨
Okay bestie, gather round π this is the list of typical errors seen with the use of IO::Socket::SSL: no cap
- Disabling verification with
SSL_verify_mode. β major yikes π©
So like, as we said in Essential Information About SSL/TLS, properly IDing the peer is essential, and if you don't verify, Man-In-The-Middle attacks become possible. fr fr
But nevertheless, tons of scripts β even public modules and apps β disable verification because it's probably the easiest way to make stuff work, and usually nobody notices any security problems anyway. iykyk
If verification doesn't succeed with the default settings, you can do these things: β¨
- Make sure the needed CAs are in the store. Maybe use
SSL_ca_fileorSSL_ca_pathto specify a different CA store. π - If validation fails because the certificate is self-signed and that's what you expect, you can use the
SSL_fingerprintoption to accept specific leaf certificates by their certificate or pubkey fingerprint. π - If validation failed because the hostname doesn't match and you can't access the host with the name given in the certificate, you can use
SSL_verifycn_nameto specify the hostname you expect in the certificate. π¦
A common error pattern is also to disable verification if they found no CA store β different modules look at different "default" places. Because IO::Socket::SSL is now able to provide a usable CA store on most platforms (UNIX, Mac OSX and Windows), it's better to use the defaults provided by IO::Socket::SSL. If necessary, these can be checked with the default_ca method. periodt
- Polling of SSL sockets (e.g.
select,polland other event loops). β the way that... this trips people up π
If you sysread one byte on a normal socket, it results in a syscall to read one byte. So if more than one byte is available on the socket, it'll be kept in the network stack of your OS, and the next select or poll call will return the socket as readable. slay
But with SSL you don't deliver single bytes. Multiple data bytes are packaged and encrypted together in an SSL frame. Decryption can only be done on the whole frame, so a sysread for one byte actually reads the complete SSL frame from the socket, decrypts it, and returns the first decrypted byte. Further sysreads will return more bytes from the same frame until all bytes are returned, and the next SSL frame will be read from the socket. β¨
So to decide if you can read more data (like, if sysread will block), you must check if there are still data in the current SSL frame by calling pending. And if there are no data pending, you might check the underlying socket with select or poll. Another way: try to sysread at least 16kByte all the time. 16kByte is the maximum size of an SSL frame, and because sysread returns data from only a single SSL frame, you can guarantee that there are no pending data. π
Additionally, contrary to plain sockets, the data delivered on the socket are not necessarily application payload. It might be a TLS handshake, it might just be the beginning of a TLS record, or it might be TLS session tickets which are send after the TLS handshake in TLS 1.3. In such situations select will return that data are available for read since it only looks at the plain socket. A sysread on the IO::Socket::SSL socket will not return any data though, since it's an abstraction which only returns application data. This causes the sysread to hang if the socket was blocking, or to return an error with EAGAIN on non-blocking sockets. Applications using select or similar should therefore set the socket to non-blocking and also expect that the sysread might temporarily fail with EAGAIN. β οΈ
See also "Using Non-Blocking Sockets". π«Ά
- Expecting exactly the same behavior as plain sockets. β bestie... it's giving "why won't it act normal" π
IO::Socket::SSL tries to emulate the usual socket behavior as good as possible, but full emulation can not be done. Specifically, a read on the SSL socket might also result in a write on the TCP socket, or a write on the SSL socket might result in a read on the TCP socket. Also accept and close on the SSL socket will result in writing and reading data to the TCP socket too. no cap
Especially the hidden writes might result in a connection reset if the underlying TCP socket is already closed by the peer. Unless signal PIPE is explicitly handled by the application, this will usually result in the application crashing. It is thus recommended to explicitly IGNORE signal PIPE so that the errors get propagated as EPIPE instead of causing a crash of the application. π¨
- Set
'SSL_version'or'SSL_cipher_list'to a "better" value. β the audacity π
IO::Socket::SSL tries to set these values to reasonable, secure values which are compatible with the rest of the world. But there are some scripts or modules out there which tried to be smart and get more secure or compatible settings. Unfortunately, they did this years ago and never updated these values, so they're still forced to do only 'TLSv1' (instead of also using TLSv12 or TLSv11). Or they set 'HIGH' as the cipher list and thought they were secure, but did not notice that 'HIGH' includes anonymous ciphers, e.g. without identification of the peer. π
So it's recommended to leave the settings at the secure defaults which IO::Socket::SSL sets and which get updated from time to time to better fit the real world. periodt
- Make SSL settings inaccessible by the user, together with bad builtin settings. β not the bad builtin settings π
Some modules use IO::Socket::SSL, but don't make the SSL settings available to the user. This is often combined with bad builtin settings or defaults (like switching verification off). π©
Thus the user needs to hack around these restrictions by using set_args_filter_hack or similar. iykyk
- Use of constants as strings. β bestie no π
Constants like SSL_VERIFY_PEER or SSL_WANT_READ should be used as constants and not be put inside quotes, because they represent numerical values. β¨
- Forking and handling the socket in parent and child. β fork around and find out π
A fork of the process will duplicate the internal user space SSL state of the socket. If both master and child interact with the socket by using their own SSL state, strange error messages will happen. Such interaction includes explicit or implicit close of the SSL socket. To avoid this, the socket should be explicitly closed with SSL_no_shutdown. β οΈ
- Forking and executing a new process. β exec said bye to your SSL state π
Since the SSL state is stored in user space, it will be duplicated by a fork but it will be lost when doing exec. This means it's not possible to simply redirect stdin and stdout for the new process to the SSL socket by duplicating the relevant file handles. Instead, explicitly exchanging plain data between child-process and SSL socket are needed. periodt
πΈ Common Problems with SSL πΈ
okay bestie, real talk: SSL is a complex protocol with multiple implementations, and each one has its own little quirks. Most of them work together, but it often gets problematic with older versions, minimal versions in load balancers, or just plain wrong setups.
ngl these problems are hard to debug. What actually helps? Knowing SSL internals, wireshark, and using the debug settings of IO::Socket::SSL and Net::SSLeay β both can be set with $IO::Socket::SSL::DEBUG. Here are the debug levels defined, but they're used not in any consistent way:
0β No debugging (default).1β Print out errors fromIO::Socket::SSLand ciphers fromNet::SSLeay.2β Print also information about call flow fromIO::Socket::SSL, progress information fromNet::SSLeayand state information from OpenSSL.3β Print also some data dumps fromIO::Socket::SSLand fromNet::SSLeay.
Also, analyze-ssl.pl from the ssl-tools repository at https://github.com/noxxi/p5-ssl-tools might be a helpful tool when debugging SSL problems, as do the openssl command line tool and a check with a different SSL implementation (e.g. a web browser).
The following problems are not uncommon:
- Bad server setup: missing intermediate certificates.
It is a regular problem that administrators fail to include all necessary certificates into their server setup, e.g. everything needed to build the trust chain from the trusted root. If they check the setup with the browser everything looks ok, because browsers work around these problems by caching any intermediate certificates and apply them to new connections if certificates are missing.
But, fresh browser profiles which have never seen these intermediates cannot fill in the missing certificates and fail to verify; the same is true with IO::Socket::SSL.
- Old versions of servers or load balancers which do not understand specific TLS versions or croak on specific data.
From time to time one encounters an SSL peer, which just closes the connection inside the SSL handshake. This can usually be worked around by downgrading the SSL version, e.g. by setting SSL_version. Modern Browsers usually deal with such servers by automatically downgrading the SSL version and repeat the connection attempt until they succeed.
Worse servers do not close the underlying TCP connection but instead just drop the relevant packet. This is harder to detect because it looks like a stalled connection. But downgrading the SSL version often works here too.
A cause of such problems are often load balancers or security devices, which have hardware acceleration and only a minimal (and less robust) SSL stack. They can often be detected because they support much fewer ciphers than other implementations.
- Bad or old OpenSSL versions.
IO::Socket::SSL uses OpenSSL with the help of the Net::SSLeay library. It is recommend to have a recent version of this library, because it has more features and usually fewer known bugs.
- Validation of client certificates fail.
Make sure that the purpose of the certificate allows use as ssl client (check with openssl x509 -purpose, that the necessary root certificate is in the path specified by SSL_ca* (or the default path) and that any intermediate certificates needed to build the trust chain are sent by the client.
- Validation of self-signed certificate fails even if it is given with
SSL_ca*argument.
The SSL_ca* arguments do not give a general trust store for arbitrary certificates but only specify a store for CA certificates which then can be used to verify other certificates. This especially means that certificates which are not a CA get simply ignored, notably self-signed certificates which do not also have the CA-flag set.
This behavior of OpenSSL differs from the more general trust-store concept which can be found in browsers and where it is possible to simply added arbitrary certificates (CA or not) as trusted.
π¦ Using Non-Blocking Sockets π¦
If you have a non-blocking socket, the expected behavior on read, write, accept or connect is to set $! to EWOULDBLOCK if the operation cannot be completed immediately. Note that EWOULDBLOCK is the same as EAGAIN on UNIX systems, but is different on Windows.
With SSL, handshakes might occur at any time, even within an established connection. In these cases it is necessary to finish the handshake before you can read or write data. This might result in situations where you want to read but must first finish the write of a handshake or where you want to write but must first finish a read. In these cases $! is set to EAGAIN like expected, and additionally $SSL_ERROR is set to either SSL_WANT_READ or SSL_WANT_WRITE. Thus if you get EWOULDBLOCK on a SSL socket you must check $SSL_ERROR for SSL_WANT_* and adapt your event mask accordingly.
Using readline on non-blocking sockets does not make much sense and I would advise against using it. And, while the behavior is not documented for other IO::Socket classes, it will try to emulate the behavior seen there, e.g. to return the received data instead of blocking, even if the line is not complete. If an unrecoverable error occurs it will return nothing, even if it already received some data.
Also, I would advise against using accept with a non-blocking SSL object because it might block and this is not what most would expect. The reason for this is that accept on a non-blocking TCP socket (e.g. IO::Socket::IP, IO::Socket::INET..) results in a new TCP socket which does not inherit the non-blocking behavior of the master socket. And thus, the initial SSL handshake on the new socket inside IO::Socket::SSL::accept will be done in a blocking way. To work around this you are safer by doing a TCP accept and later upgrade the TCP socket in a non-blocking way with start_SSL and accept_SSL.
my $cl = IO::Socket::SSL->new($dst);
$cl->blocking(0);
my $sel = IO::Select->new($cl);
while (1) {
# with SSL a call for reading n bytes does not result in reading of n
# bytes from the socket, but instead it must read at least one full SSL
# frame. If the socket has no new bytes, but there are unprocessed data
# from the SSL frame can_read will block!
# wait for data on socket
$sel->can_read();
# new data on socket or eof
READ:
# this does not read only 1 byte from socket, but reads the complete SSL
# frame and then just returns one byte. On subsequent calls it than
# returns more byte of the same SSL frame until it needs to read the
# next frame.
my $n = sysread( $cl,my $buf,1);
if ( ! defined $n ) {
die $! if not $!{EWOULDBLOCK};
next if $SSL_ERROR == SSL_WANT_READ;
if ( $SSL_ERROR == SSL_WANT_WRITE ) {
# need to write data on renegotiation
$sel->can_write;
next;
}
die "something went wrong: $SSL_ERROR";
} elsif ( ! $n ) {
last; # eof
} else {
# read next bytes
# we might have still data within the current SSL frame
# thus first process these data instead of waiting on the underlying
# socket object
goto READ if $cl->pending; # goto sysread
next; # goto $sel->can_read
}
}
Additionally there are differences to plain sockets when using select, poll, kqueue or similar technologies to get notified if data are available. Relying only on these calls is not sufficient in all cases since unread data might be internally buffered in the SSL stack. To detect such buffering pending() need to be used. Alternatively the buffering can be avoided by using sysread with the maximum size of an SSL frame. See "Common Usage Errors" for details.
β¨ Advanced Usage β¨
π SNI Support π
okay so bestie, SNI = Server Name Indication, and it's literally the glow-up that lets one single IP address host multiple hostnames. iconic behavior tbh π
Client-side SNI showed up somewhere in the OpenSSL 0.9.8 series, but OpenSSL 1.0 fixed a bug where the server couldn't figure out its own hostname π so in IO::Socket::SSL, client side SNI is only supported with OpenSSL 1.0 or higher. With a supported version, SNI just happens automatically on the client side if it can determine the hostname from PeerAddr or PeerHost (these are synonyms in the underlying IO::Socket:: classes, so likeβ¦ never set both, or at the very least not to different values π). On unsupported OpenSSL versions it will silently not use SNI β no drama, no error, just vibes. You can also hand over the hostname explicitly with SSL_hostname, but in this case it will throw an error if SNI isn't supported. Wanna check for support? Call IO::Socket::SSL->can_client_sni() π«Ά
On the server side, earlier versions of OpenSSL are supported, but only together with Net::SSLeay version >= 1.50. To check for support you might call IO::Socket::SSL->can_server_sni(). And if server side SNI is supported? You can specify different certificates per host with SSL_cert* and SSL_key*, and check the requested name using get_servername π
π¦ Talk Plain and SSL With The Same Socket π¦
Sometimes you gotta do the two-outfit thing: first exchange some plain data, then upgrade the socket to SSL after some kind of STARTTLS command. Protocols like FTPS even need a way to downgrade the socket back to plain again. main character energy, honestly π
The common way to do this would be to create a normal socket and use start_SSL to upgrade and stop_SSL to downgrade:
my $sock = IO::Socket::INET->new(...) or die $!;
... exchange plain data on $sock until starttls command ...
IO::Socket::SSL->start_SSL($sock,%sslargs) or die $SSL_ERROR;
... now $sock is an IO::Socket::SSL object ...
... exchange data with SSL on $sock until stoptls command ...
$sock->stop_SSL or die $SSL_ERROR;
... now $sock is again an IO::Socket::INET object ...
But β and this is the plot twist β lots of modules just derive directly from IO::Socket::INET. While this base class can be replaced with IO::Socket::SSL, these modules cannot easily support different base classes for SSL and plain data and switch between these classes on a starttls command. it's giving π©
To help in this case, IO::Socket::SSL can be reduced to a plain socket on startup, and connect_SSL/accept_SSL/start_SSL can be used to enable SSL and stop_SSL to talk plain again:
my $sock = IO::Socket::SSL->new(
PeerAddr => ...
SSL_startHandshake => 0,
%sslargs
) or die $!;
... exchange plain data on $sock until starttls command ...
$sock->connect_SSL or die $SSL_ERROR;
... now $sock is an IO::Socket::SSL object ...
... exchange data with SSL on $sock until stoptls command ...
$sock->stop_SSL or die $SSL_ERROR;
... $sock is still an IO::Socket::SSL object ...
... but data exchanged again in plain ...
slay. two modes, one socket, no cap π
π§ Integration Into Own Modules π§
IO::Socket::SSL behaves similarly to other IO::Socket modules and thus could be integrated in the same way, but you have to take special care when using non-blocking I/O (like for handling timeouts) or using select or poll. Please study the documentation on how to deal with these differences π
Also, it is recommended to not set or touch most of the SSL_* options, so that they keep their secure defaults. It is also recommended to let the user override these SSL specific settings without the need of global settings or hacks like set_args_filter_hack. let the people choose their own destiny π«
The notable exception is SSL_verifycn_scheme. This should be set to the hostname verification scheme required by the module or protocol. that one's on you, bestie πΈ
π Description Of Methods π
IO::Socket::SSL inherits from another IO::Socket module. The choice of the super class depends on the installed modules:
- If IO::Socket::IP with at least version
0.20is installed it will use this module as super class, transparently providing IPv6 and IPv4 support. - If IO::Socket::INET6 is installed it will use this module as super class, transparently providing IPv6 and IPv4 support.
- Otherwise it will fall back to IO::Socket::INET, which is a perl core module. With IO::Socket::INET you only get IPv4 support.
Please be aware that with the IPv6 capable super classes, it will look first for the IPv6 address of a given hostname. If the resolver provides an IPv6 address, but the host cannot be reached by IPv6, there will be no automatic fallback to IPv4 π To avoid these problems you can enforce IPv4 for a specific socket by using the Domain or Family option with the value AF_INET as described in IO::Socket::IP. Alternatively you can enforce IPv4 globally by loading IO::Socket::SSL with the option 'inet4', in which case it will use the IPv4 only class IO::Socket::INET as the super class.
IO::Socket::SSL will provide all of the methods of its super class, but sometimes it will override them to match the behavior expected from SSL or to provide additional arguments.
The new or changed methods are described below, but please also read the section about SSL specific error handling.
π Error Handling π
If an SSL specific error occurs, the global variable $SSL_ERROR will be set. If the error occurred on an existing SSL socket, the method errstr will give access to the latest socket specific error. Both $SSL_ERROR and the errstr method give a dualvar similar to $!, e.g. providing an error number in numeric context or an error description in string context. two moods, one variable π
π new(...) π
Creates a new IO::Socket::SSL object. You may use all the friendly options that came bundled with the super class (e.g. IO::Socket::IP, IO::Socket::INET, ...) plus (optionally) the ones described below. If you don't specify any SSL related options it will do its best in using secure defaults, e.g. choosing good ciphers, enabling proper verification, etc. it's looking out for you fr fr π«Ά
β SSL_server
Set this option to a true value if the socket should be used as a server. If this is not explicitly set it is assumed if the Listen parameter is given when creating the socket.
β SSL_hostname
This can be given to specify the hostname used for SNI, which is needed if you have multiple SSL hostnames on the same IP address. If not given it will try to determine the hostname from PeerAddr, which will fail if only an IP was given or if this argument is used within start_SSL π
If you want to disable SNI, set this argument to ''.
Currently only supported for the client side and will be ignored for the server side.
See section SNI Support for details of SNI the support.
β SSL_startHandshake
If this option is set to false (defaults to true) it will not start the SSL handshake yet. This has to be done later with accept_SSL or connect_SSL. Before the handshake is started read/write/etc. can be used to exchange plain data.
β SSL_keepSocketOnError
If this option is set to true (defaults to false) it will not close the underlying TCP socket on errors. In most cases there is no real use for this behavior since both sides of the TCP connection will probably have a different idea of the current state of the connection. so likeβ¦ it exists, but it's giving chaos π
β SSL_ca | SSL_ca_file | SSL_ca_path
Usually you want to verify that the peer certificate has been signed by a trusted certificate authority. In this case you should use this option to specify the file (SSL_ca_file) or directory (SSL_ca_path) containing the certificate(s) of the trusted certificate authorities.
SSL_ca_path can also be an array or a string containing multiple path, where the path are separated by the platform specific separator. This separator is ; on DOS, Windows, Netware, , on VMS and : for all the other systems. If multiple path are given at least one of these must be accessible.
You can also give a list of X509* certificate handles (like you get from Net::SSLeay or IO::Socket::SSL::Utils::PEM_xxx2cert) with SSL_ca. These will be added to the CA store before path and file and thus take precedence. If neither SSL_ca, nor SSL_ca_file or SSL_ca_path are set it will use default_ca() to determine the user-set or system defaults. If you really don't want to set a CA set SSL_ca_file or SSL_ca_path to "\undef" or SSL_ca to an empty list. (unfortunately '' is used by some modules using IO::Socket::SSL when CA is not explicitly given). pick your fighter, bestie π₯
β SSL_client_ca | SSL_client_ca_file
If verify_mode is VERIFY_PEER on the server side these options can be used to set the list of acceptable CAs for the client. This way the client can select they required certificate from a list of certificates. The value for these options is similar to SSL_ca and SSL_ca_file. shopping for certs, but make it secure ποΈ
β SSL_fingerprint
Sometimes you have a self-signed certificate or a certificate issued by an unknown CA and you really want to accept it, but don't want to disable verification at all. In this case you can specify the fingerprint of the certificate as 'algo$hex_fingerprint'. algo is a fingerprint algorithm supported by OpenSSL, e.g. 'sha1','sha256'... and hex_fingerprint is the hexadecimal representation of the binary fingerprint. Any colons inside the hex string will be ignored.
If you want to use the fingerprint of the pubkey inside the certificate instead of the certificate use the syntax 'algo$pub$hex_fingerprint' instead. To get the fingerprint of an established connection you can use get_fingerprint.
It is also possible to skip algo$, i.e. only specify the fingerprint. In this case the likely algorithms will be automatically detected based on the length of the digest string.
Examples:
sha1$pub$f0f0c49b8a04a2dd2110e10f7806c97d87d0b26f # pubkey SHA-1
sha1$f0f0c49b8a04a2dd2110e10f7806c97d87d0b26f # certificate SHA-1
f0f0c49b8a04a2dd2110e10f7806c97d87d0b26f # certificate SHA-1
You can specify a list of fingerprints in case you have several acceptable certificates. If a fingerprint matches the topmost (i.e. leaf) certificate no additional validations can make the verification fail. periodt π
ok so real talk β the default behavior of SSL_fingerprint is that it's an alternative to your normal validation, not a replacement. A fingerprint that doesn't match will not override a successful certificate validation, but a fingerprint that does match can override an otherwise failed validation. If you want to actually enforce a fingerprint, go look at SSL_force_fingerprint. π
SSL_force_fingerprintβ set this to true if you want a failed fingerprint validation to override an otherwise successful certificate validation. Basically: the fingerprint is the boss now. πSSL_cert_file|SSL_cert|SSL_key_file|SSL_keyβ bestie, if you're making a server you usually need to hand it a server certificate that the client can verify. Same energy for client certificates, which the server verifies. You can pass the cert as a file withSSL_cert_file, or as an internalX509*object withSSL_cert(like the ones you get from Net::SSLeay orIO::Socket::SSL::Utils::PEM_xxx2cert). If you give it as a file, it auto-detects the format. Supported formats are PEM, DER and PKCS#12 β PEM and PKCS#12 can hold the certificate and the chain to use, while DER can only hold a single certificate. β¨
If you hand it a list of X509*, heads up: all the chain certificates (i.e. all except the first) will be "consumed" by openssl and will be freed if the SSL context gets destroyed β so you should never free them yourself. But the server's certificate (the first one) will not be consumed by openssl and thus must be freed by the application. Not me being dramatic, that's just the rules. π
Every certificate needs a key, and that key can either be a file via SSL_key_file or an internal EVP_PKEY* object via SSL_key (like what you get from Net::SSLeay or IO::Socket::SSL::Utils::PEM_xxx2key). If a key was already given inside the PKCS#12 file specified by SSL_cert_file, it will ignore any SSL_key or SSL_key_file. And if no SSL_key or SSL_key_file was given, it will try to reuse the PEM file given with SSL_cert_file again β maybe it contains the key too, iykyk. π
If your SSL server should be able to use different certificates on the same IP address depending on the name the client gives via SNI, you can use a hash reference instead of a file, like "<hostname =" cert_file>>. π¦
If your SSL server should be able to use both RSA and ECDSA certificates for the same domain/IP, you give a similar hash reference to the SNI one. The domain names used to specify the additional certificates should be "hostname%whatever", i.e. "hostname%ecc" or similar. This needs at least OpenSSL 1.0.2. To let the server pick the certificate based on the client's cipher preference, SSL_honor_cipher_order should be set to false. πΈ
In case certs and keys are needed but not given, it might fall back to builtin defaults β see "Defaults for Cert, Key and CA".
Examples:
SSL_cert_file => 'mycert.pem',
SSL_key_file => 'mykey.pem',
SSL_cert_file => {
"foo.example.org" => 'foo-cert.pem',
"foo.example.org%ecc" => 'foo-ecc-cert.pem',
"bar.example.org" => 'bar-cert.pem',
# used when nothing matches or client does not support SNI
'' => 'default-cert.pem',
'%ecc' => 'default-ecc-cert.pem',
},
SSL_key_file => {
"foo.example.org" => 'foo-key.pem',
"foo.example.org%ecc" => 'foo-ecc-key.pem',
"bar.example.org" => 'bar-key.pem',
# used when nothing matches or client does not support SNI
'' => 'default-key.pem',
'%ecc' => 'default-ecc-key.pem',
}
SSL_passwd_cbβ if your private key is encrypted, maybe you don't want the default password prompt from Net::SSLeay (mood). This option takes a reference to a subroutine that should return the password needed to decrypt your private key. πSSL_use_certβ if this is true, it forces IO::Socket::SSL to use a certificate and key, even if you're setting up an SSL client. If it's set to0(which is the default), then you only need a certificate and key if you're setting up a server. π
SSL_use_cert will implicitly be set if SSL_server is set. And for convenience it's also set if it wasn't given but a cert was given for use (SSL_cert_file or similar).
SSL_versionβ sets the version of the SSL protocol used to transmit data.'SSLv23'uses a handshake compatible with SSL2.0, SSL3.0 and TLS1.x, while'SSLv2','SSLv3','TLSv1','TLSv1_1','TLSv1_2', or'TLSv1_3'restrict the handshake and protocol to the specified version. All values are case-insensitive. Instead of'TLSv1_1','TLSv1_2', and'TLSv1_3'you can also use'TLSv11','TLSv12', and'TLSv13'. Which protocol versions are actually supported depends on the versions of OpenSSL and Net::SSLeay you have installed, but modern protocols like TLS 1.3 have been supported by these for many years now. The defaultSSL_versionis defined by the underlying cryptographic library. β¨
Independent from the handshake format, you can limit the set of accepted SSL versions by adding !version separated by :. π«Ά
For example, 'SSLv23:!TLSv1:!TLSv1_1:!SSLv3:!SSLv2' means the handshake format is compatible with SSL2.0 and higher, but the successful handshake is limited to TLS1.2 and higher β that is, no SSL2.0, SSL3.0, TLS 1.0 or TLS 1.1, because these versions have serious security issues and should not be used anymore. Periodt.
You can also use !TLSv1_1 and !TLSv1_2 to disable TLS versions 1.1 and 1.2 while still allowing TLS version 1.0. Setting the version instead to 'TLSv1' might break interaction with very old or broken clients, which expect an SSL2.0 compatible handshake. On the other side, some broken clients just close the connection when they receive a TLS version 1.1 request. In this case, setting the version to 'SSLv23:!SSLv2:!SSLv3:!TLSv1_1:!TLSv1_2' might help. π
SSL_cipher_listβ if this option is set, the cipher list for the connection will be set to the given value, e.g. something like'ALL:!LOW:!EXP:!aNULL'. This will only affect ciphers for TLS 1.2 and lower. See the OpenSSL documentation (https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-STRINGS) for more details. π
Unless you fail to contact your peer because of no shared ciphers, it is recommended to leave this option at the default setting, which honors the system-wide PROFILE=SYSTEM cipher list. π
In case different cipher lists are needed for different SNI hosts, a hash can be given with the host as key and the cipher suite as value, similar to SSL_cert*.
SSL_ciphersuitesβ if this option is set, the TLS 1.3 ciphersuites for the connection will be set to the given value. This is similar toSSL_cipher_list, but only for TLS 1.3 ciphers. See argument-ciphersuitesin the OpenSSL documentation (https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html) for details. π
Unless you fail to contact your peer because of no shared ciphers, it is recommended to leave this option at the default setting, which uses the system default. πΈ
In case different cipher lists are needed for different SNI hosts, a hash can be given with the host as key and the cipher suite as value, similar to SSL_cert*.
SSL_honor_cipher_orderβ if this option is true, the cipher order the server specified is used instead of the order proposed by the client. This option defaults to true so we can make use of our secure cipher list setting. πSSL_dh_fileβ to create a server that provides forward secrecy you need to either give the DH parameters or (better, because faster) the ECDH curve. This setting cares about DH parameters. π¦
To support non-elliptic Diffie-Hellman key exchange, a suitable file needs to be given here, or SSL_dh should be used with an appropriate value. See the dhparam command in openssl for more information.
If neither "SSL_dh_file" nor "SSL_dh" are set, a builtin DH parameter with a length of 2048 bit is used to offer DH key exchange by default. If you don't want this (e.g. you want to disable DH key exchange), explicitly set this or the "SSL_dh" parameter to undef.
SSL_dhβ likeSSL_dh_file, but instead of giving a file you use a preloaded or generatedDH*. β¨SSL_ecdh_curveβ to create a server that provides forward secrecy you need to either give the DH parameters or (better, because faster) the ECDH curve. This setting cares about the ECDH curve(s). π
To support Elliptic Curve Diffie-Hellmann key exchange, the OID or NID of at least one suitable curve needs to be provided here.
With OpenSSL 1.1.0+ this parameter defaults to "auto", which means it lets OpenSSL pick the best settings. If support for CTX_set_ecdh_auto is implemented in Net::SSLeay (needs at least version 1.86) it will use this to implement the same default. Otherwise it will default to "prime256v1" (builtin of OpenSSL) in order to offer ECDH key exchange by default. πΈ
If setting groups or curves is supported by Net::SSLeay (needs at least version 1.86) then multiple curves can be given here in the order of preference, i.e. "P-521:P-384:P-256". When used at the client side, this will include the supported curves as an extension in the TLS handshake. π«Ά
If you don't want to have ECDH key exchange, this could be set to undef or set "SSL_ciphers" to exclude all of these ciphers.
You can check if ECDH support is available by calling IO::Socket::SSL->can_ecdh. π
SSL_verify_modeβ this option sets the verification mode for the peer certificate. You may combineSSL_VERIFY_PEER(verify_peer),SSL_VERIFY_FAIL_IF_NO_PEER_CERT(fail verification if no peer certificate exists; ignored for clients), andSSL_VERIFY_CLIENT_ONCE(verify client once; ignored for clients). Note thatSSL_VERIFY_FAIL_IF_NO_PEER_CERTandSSL_VERIFY_CLIENT_ONCEmust be used together withSSL_VERIFY_PEER. See the OpenSSL man page forSSL_CTX_set_verifyfor more information. π
The default is SSL_VERIFY_NONE for server (e.g. no check for client certificate) and SSL_VERIFY_PEER for client (check server certificate). there it is bestie, the whole vibe of that one π
SSL_verify_callbackβ okay so if you're the type of girl who wants to verify certificates herself, you can pass a sub reference along with this parameter and do exactly that. When the callback gets called, it gets handed these:- a true/false value that indicates what OpenSSL thinks of the certificate,
- a C-style memory address of the certificate store,
- a string containing the certificate's issuer attributes and owner attributes, and
- a string containing any errors encountered (
0if no errors). - a C-style memory address of the peer's own certificate (convertible to PEM form with
Net::SSLeay::PEM_get_string_X509()). - The depth of the certificate in the chain. Depth
0is the leaf certificate.
Your function should return 1 or 0, depending on whether it thinks the certificate is valid or invalid. The default is to let OpenSSL do all of the busy work (slay, honestly). The callback will be called for each element in the certificate chain. See the OpenSSL documentation for SSL_CTX_set_verify for more information.
SSL_verifycn_schemeβ this scheme is used to correctly verify the identity inside the certificate by using the hostname of the peer. See the information about the verification schemes inverify_hostname.
If you don't specify a scheme it will use 'default', but only complain loudly if the name verification fails instead of letting the whole certificate verification fail. THIS WILL CHANGE, e.g. it will let the certificate verification fail in the future if the hostname does not match the certificate !!!! To override the name used in verification use SSL_verifycn_name.
The scheme 'default' is a superset of the usual schemes, which will accept the hostname in common name and subjectAltName and allow wildcards everywhere. While using this scheme is way more secure than no name verification at all you better should use the scheme specific to your application protocol, e.g. 'http', 'ftp'... πΈ
If you are really sure that you don't want to verify the identity using the hostname you can use 'none' as a scheme. In this case you'd better have alternative forms of verification, like a certificate fingerprint or do a manual verification later by calling verify_hostname yourself.
SSL_verifycn_publicsuffixβ this option sets the behavior when checking wildcards certificates for public suffixes, e.g. no wildcard certificates for*.comor*.co.ukshould be accepted, while*.example.comor*.example.co.ukis ok. very slay, very correct
If not specified it will simply use the builtin default of IO::Socket::SSL::PublicSuffix, you can create another object with from_string or from_file of this module. To disable verification of public suffix set this option to ''.
SSL_verifycn_nameβ set the name which is used in verification of hostname. IfSSL_verifycn_schemeis set and noSSL_verifycn_nameis given it will try to useSSL_hostnameorPeerHostandPeerAddrsettings and fail if no name can be determined. IfSSL_verifycn_schemeis not set it will use a default scheme and warn if it cannot determine a hostname, but it will not fail.
Using PeerHost or PeerAddr works only if you create the connection directly with IO::Socket::SSL->new, if an IO::Socket::INET object is upgraded with start_SSL the name has to be given in SSL_verifycn_name or SSL_hostname. iykyk β¨
SSL_check_crlβ if you want to verify that the peer certificate has not been revoked by the signing authority, set this value to true. OpenSSL will search for the CRL in yourSSL_ca_path, or use the file specified bySSL_crl_file. See the Net::SSLeay documentation for more details.SSL_crl_fileβ if you want to specify the CRL file to be used, set this value to the pathname to be used. This must be used in addition to settingSSL_check_crl.SSL_ocsp_modeβ defines how certificate revocation is done using OCSP (Online Status Revocation Protocol). The default is to send a request for OCSP stapling to the server and if the server sends an OCSP response back the result will be used.
Any other OCSP checking needs to be done manually with ocsp_resolver.
The following flags can be combined with |:
SSL_OCSP_NO_STAPLEβ Don't ask for OCSP stapling. This is the default ifSSL_verify_modeisVERIFY_NONE.SSL_OCSP_TRY_STAPLEβ Try OCSP stapling, but don't complain if it gets no stapled response back. This is the default ifSSL_verify_modeisVERIFY_PEER(the default).SSL_OCSP_MUST_STAPLEβ Consider it a hard error, if the server does not send a stapled OCSP response back. Most servers currently send no stapled OCSP response back. ngl, most of them are just out here ghosting youSSL_OCSP_FAIL_HARDβ Fail hard on response errors, default is to fail soft like the browsers do. Soft errors mean that the OCSP response is not usable, e.g. no response, error response, no valid signature etc. Certificate revocations inside a verified response are considered hard errors in any case.
Soft errors inside a stapled response are never considered hard, e.g. it is expected that in this case an OCSP request will be send to the responsible OCSP responder.
SSL_OCSP_FULL_CHAINβ This will set up theocsp_resolverso that all certificates from the peer chain will be checked, otherwise only the leaf certificate will be checked against revocation.
SSL_ocsp_staple_callbackβ if this callback is defined, it will be called with the SSL object and the OCSP response handle obtained from the peer, e.g.<$cb->($ssl,$resp)>. If the peer did not provide a stapled OCSP response the function will be called with$resp=undef. Because the OCSP response handle is no longer valid after leaving this function it should not by copied or freed. If access to the response is necessary after leaving this function it can be serialized withNet::SSLeay::i2d_OCSP_RESPONSE.
If no such callback is provided, it will use the default one, which verifies the response and uses it to check if the certificate(s) of the connection got revoked.
SSL_ocsp_cacheβ with this option a cache can be given for caching OCSP responses, which could be shared between different SSL contexts. If not given a cache specific to the SSL context only will be used.
You can either create a new cache with IO::Socket::SSL::OCSP_Cache->new([size]) or implement your own cache, which needs to have methods put($key,\%entry) and get($key) (returning \%entry) where entry is the hash representation of the OCSP response with fields like nextUpdate. The default implementation of the cache will consider responses valid as long as nextUpdate is less then the current time.
SSL_pskβ PSK to use instead of certificate. Requires the peer to use the same PSK.
On the client side the identity and psk need to be provided as array-ref with [identity,psk]. Alternatively only the psk might be provided, in which case io_socket_ssl is used as identity. On the server side a single psk might be given which will then be use no matter which identity hint was given by the client. Alternatively a hash-ref can be provided with identity as key and psk as value to serve clients with different psk based on the identity hint. The special identity '' is used to set a default psk.
To use PSK make sure to have the relevant ciphers enabled. With TLS 1.3 this is implicit, but with TLS 1.2 and lower explicitly add PSK to SSL_cipher_list since it is not enabled by default.
Note that the given psk is expected to be binary and not hexadecimal as some other tools do. To convert hex to binary use pack("H*",hexstring). Also note that the error messages one gets if either identity or psk don't match the configuration in the peer can be useless ("handshake failure") or misleading ("bad mac"). π love that for us
PSK support needs respective API functionality in Net::SSLeay, which was only fully included in 1.94. IO::Socket::SSL->can_psk() returns undef if functionality is not available and a hash-ref with details otherwise: key client in the hash signals support for using PSK in a SSL client (available since Net::SSLeay 1.82) while key server for support of PSK in SSL server (since Net::SSLeay 1.94).
SSL_reuse_ctxβ if you have already set the above options for a previous instance of IO::Socket::SSL, then you can reuse the SSL context of that instance by passing it as the value for theSSL_reuse_ctxparameter. You may also create a new instance of theIO::Socket::SSL::SSL_Contextclass, using any context options that you desire without specifying connection options, and pass that here instead. recycling era β»οΈπ
If you use this option, all other context-related options that you pass in the same call to new() will be ignored unless the context supplied was invalid. Note that, contrary to versions of IO::Socket::SSL below v0.90, a global SSL context will not be implicitly used unless you use the set_default_context() function.
SSL_create_ctx_callbackβ with this callback you can make individual settings to the context after it got created and the default setup was done. The callback will be called with the CTX object from Net::SSLeay as the single argument.
Example for limiting the server session cache size:
SSL_create_ctx_callback => sub {
my $ctx = shift;
Net::SSLeay::CTX_sess_set_cache_size($ctx,128);
}
okay that's the whole options buffet and every single one of them is here, no skips, no crumbs left behind π«Ά
SSL_session_cache_size
okay so if you're making repeated connections to the same host/port and the SSL renegotiation time is giving you a headache, bestie, you can turn on client-side session caching with this option by giving it a positive cache size. π
For successive connections, pass the SSL_reuse_ctx option to the new() calls (or use set_default_context()) to actually make use of those cached sessions, fr fr. The session cache size is the number of unique host/port pairs that can be stored at one time; the oldest sessions in the cache get yeeted if new ones show up. β¨
Heads up: this option does not affect the session cache a server has for its clients β like, it does not affect SSL objects with SSL_server set. π
Note that session caching with TLS 1.3 needs at least Net::SSLeay 1.86. no cap.
SSL_session_cache
This one lets you specify a session cache object to use instead of creating a new one. It overrules SSL_session_cache_size. Super useful if you wanna reuse the cache but not the rest of the context. π
You can create a session cache object with:
"IO::Socket::SSL::Session_Cache->new( cachesize )"
And use set_default_session_cache() to set a global cache object. slay.
SSL_session_key
Specifies a key to use for lookups and inserts into the client-side session cache. By default ip:port of the destination is used, but sometimes you want to share the same session over multiple ports on the same server (like with FTPS). iykyk. π¦
SSL_session_id_context
Gives an id for the server's session cache. It's necessary if you want clients to connect with a client certificate. If you don't give it but SSL_verify_mode specifies the need for a client certificate, a context unique id will be picked for you. π
SSL_error_trap
When you're using the accept() or connect() methods, it may be the case that the actual socket connection works but the SSL negotiation fails β like when an HTTP client connects to an HTTPS server. π Passing a subroutine ref attached to this parameter lets you gain control of that orphaned socket instead of having it be closed forcibly. The subroutine, if called, gets passed two parameters: a reference to the socket on which the SSL negotiation failed, and the full text of the error message. π«Ά
SSL_npn_protocols
On the server side, this specifies the list of protocols advertised by the SSL server as an array ref, e.g. ['spdy/2','http1.1']. On the client side it specifies the protocols offered by the client for NPN as an array ref. See also the method next_proto_negotiated. β¨
Next Protocol Negotiation (NPN) is available with Net::SSLeay 1.46+ and openssl-1.0.1+. NPN is unavailable in TLSv1.3 protocol. To check support you might call IO::Socket::SSL->can_npn(). If you use this option with an unsupported Net::SSLeay/OpenSSL it will throw an error. π
SSL_alpn_protocols
On the server side, this specifies the list of protocols supported by the SSL server as an array ref, e.g. ['http/2.0', 'spdy/3.1','http/1.1']. On the client side it specifies the protocols advertised by the client for ALPN as an array ref. See also the method alpn_selected. πΈ
Application-Layer Protocol Negotiation (ALPN) is available with Net::SSLeay 1.56+ and openssl-1.0.2+. More details about the extension live in RFC7301. To check support you might call IO::Socket::SSL->can_alpn(). If you use this option with an unsupported Net::SSLeay/OpenSSL it will throw an error. π
Note that some client implementations may encounter problems if both NPN and ALPN are specified. Since ALPN is intended as a replacement for NPN, try providing ALPN protocols then fall back to NPN if that fails. π
SSL_ticket_keycb => [$sub,$data] | $sub
This is a callback used for stateless session reuse (Session Tickets, RFC 5077). π
This callback will be called as "$sub->($data,[$key_name])" where $data is the argument given to SSL_ticket_keycb (or undef) and $key_name depends on the mode:
- encrypt ticket β if a ticket needs to be encrypted the callback will be called without
$key_name. In this case it should return"($current_key,$current_key_name")where$current_keyis the current key (32 byte random data) and$current_key_namethe name associated with this key (exactly 16 byte). This$current_key_namewill be incorporated into the ticket. - decrypt ticket β if a ticket needs to be decrypted the callback will be called with
$key_nameas found in the ticket. It should return"($key,$current_key_name")where$keyis the key associated with the given$key_nameand$current_key_namethe name associated with the currently active key. If$current_key_nameis different from the given$key_namethe callback will be called again to re-encrypt the ticket with the currently active key.- If no key can be found which matches the given
$key_namethen this function should return nothing (empty list).
- If no key can be found which matches the given
This mechanism should be used to limit the life time for each key encrypting the ticket. Compromise of a ticket encryption key might lead to decryption of SSL sessions which used session tickets protected by this key. π scary but real.
Example:
Net::SSLeay::RAND_bytes(my $oldkey,32);
Net::SSLeay::RAND_bytes(my $newkey,32);
my $oldkey_name = pack("a16",'oldsecret');
my $newkey_name = pack("a16",'newsecret');
my @keys = (
[ $newkey_name, $newkey ], # current active key
[ $oldkey_name, $oldkey ], # already expired
);
my $keycb = [ sub {
my ($mykeys,$name) = @_;
# return (current_key, current_key_name) if no name given
return ($mykeys->[0][1],$mykeys->[0][0]) if ! $name;
# return (matching_key, current_key_name) if we find a key matching
# the given name
for(my $i = 0; $i<@$mykeys; $i++) {
next if $name ne $mykeys->[$i][0];
return ($mykeys->[$i][1],$mykeys->[0][0]);
}
# no matching key found
return;
},\@keys ];
my $srv = IO::Socket::SSL->new(..., SSL_ticket_keycb => $keycb);
SSL_on_peer_shutdown CODE
Defines a callback which gets called on receiving SSL shutdown (close notify) from the peer. You can use this to override the default behavior β see "stop_SSL" for more. π¦
SSL_mode_release_buffers 1|0
Enables or disables the SSL_MODE_RELEASE_BUFFERS option on the SSL object. With this option the read buffer will be released after each SSL_read but will need to be reallocated for each new SSL_read. If memory usage is a concern this might save lots of memory in the mean time though β about 34k per idle SSL connection according to the documentation in SSL_CTX_set_mode(3ssl). π
SSL_usebio 1|0
If this option is used with "start_SSL" (not supported somewhere else, okay??) it will not upgrade the given IO handle but instead wrap it inside a new IO object and use openssl memory BIO's to manage the exchange between the TLS layer and the socket layer. While this adds some overhead, it makes it possible to stack TLS layers β like, first create an outer TLS connection (without or with SSL_usebio) and then create the inner TLS layer with SSL_usebio, using the outer TLS connection as the IO handle in "start_SSL". π§β¨
Example:
# create TLS connection to TLS enabled http proxy
my $outer = IO::Socket::SSL->new('proxy.test:3128');
# send proxy request
print $outer "CONNECT real-target.test:443 HTTP/1.0\r\n\r\n";
... # read and check response from proxy on $outer
# create an inner TLS connection to the server inside $outer
my $inner = IO::Socket::SSL->start_SSL($outer,
SSL_usebio => 1,
SSL_hostname => 'real-target.test', # SNI
);
# send request to server through proxy using $inner
print $inner "GET / HTTP/1.0\r\nHost: real-target.test\r\n\r\n";
... # read response from server on $inner
accept
This behaves similar to the accept function of the underlying socket class, but additionally does the initial SSL handshake. π But because the underlying socket class returns a blocking file handle even when accept is called on a non-blocking socket, the SSL handshake on the new file object will be done in a blocking way. Please see the section about non-blocking I/O for details. If you don't like this behavior you should do accept on the TCP socket and then upgrade it with "start_SSL" later. π
connect(...)
This behaves similar to the connect function but also does an SSL handshake. Because you cannot give SSL specific arguments to this function, you should better either use "new" to create a connect SSL socket or "start_SSL" to upgrade an established TCP socket to SSL. π
close(...)
Contrary to a close for a simple INET socket, a close in SSL also mandates a proper shutdown of the SSL part. This is done by sending a close notify message by both peers. π€
A naive implementation would thus wait until it receives the close notify message from the peer β which conflicts with the commonly expected semantic that a close will not block. The default behavior is thus to only send a close notify but not wait for the close notify of the peer. If it should instead wait for a close notify from the peer then SSL_fast_shutdown must be explicitly set to false:
$self->close(SSL_fast_shutdown => 0);
β
Okay so there are ALSO times when you straight-up should not do an SSL shutdown at all. π Like when you fork so a child process can deal with the socket and you close the socket in the parent process. A naive explicit close β or even just an implicit close when the socket gets destroyed in the parent β would yeet a close notify at the peer, which would make the SSL socket in the client process unusable. Not the vibe. So in the parent process you do an explicit close with SSL_no_shutdown set to true:
$self->close(SSL_no_shutdown => 1);
For more deets and other arguments, go peek at stop_SSL β that's the one close calls to shut down the SSL state of the socket. π«Ά
sysread( BUF, LEN, [ OFFSET ] )
From the outside this behaves exactly like sysread in other IO::Socket objects bestie β like, it returns at most LEN bytes of data. β¨ But actually? It doesn't read just LEN bytes from the underlying socket. It reads a single SSL frame, then returns up to LEN bytes of what it decrypted from that frame. If the frame had more data than you asked for, it returns only LEN, buffers the rest, and hands it over on further read calls. Which means... you might be able to read data even when the underlying socket isn't readable π so using poll or select might not be enough. iykyk.
sysread only ever returns data from a single SSL frame β either the pending data from the already-buffered frame, or it reads a frame from the underlying socket and returns the decrypted data. It will not return data spanning several SSL frames in one single call. Periodt.
Also, calls to sysread might fail, because it has to finish an SSL handshake first. π§
Understanding these behaviors is essential if you're writing applications that use event loops and/or non-blocking sockets. Go read the specific sections in this documentation, fr fr. π
syswrite( BUF, [ LEN, [ OFFSET ]] )
This one behaves from the outside just like syswrite in other IO::Socket objects β it writes at most LEN bytes to the socket, but there is no guarantee that all LEN bytes actually get written. It returns the number of bytes written. And because it basically just calls SSL_write from OpenSSL, syswrite will write at most a single SSL frame. Which means no more than 16.384 bytes β the maximum size of an SSL frame β get written at once. π
For non-blocking sockets, SSL-specific behavior applies. Please read the specific section in this documentation. π«‘
peek( BUF, LEN, [ OFFSET ])
This function has exactly the same syntax as sysread, and does nearly the same task β but it will not advance the read position, so successive calls to peek() with the same arguments will return the same results. β¨
pending()
This function gives you the number of bytes available without reading from the underlying socket object. This function is essential if you work with event loops, so please see the section about polling SSL sockets. π₯
get_fingerprint([algo,certificate,pubkey])
This method returns the fingerprint of the given certificate in the form algo$digest_hex, where algo is the used algorithm, default 'sha256'. If no certificate is given, the peer certificate of the connection is used. If pubkey is true it will not return the fingerprint of the certificate but instead the fingerprint of the pubkey inside the certificate, as algo$pub$digest_hex. π¦
get_fingerprint_bin([algo,certificate,pubkey])
This method returns the binary fingerprint of the given certificate by using the algorithm algo, default 'sha256'. If no certificate is given, the peer certificate of the connection is used. If pubkey is true it will not return the fingerprint of the certificate but instead the fingerprint of the pubkey inside the certificate. π
get_cipher()
Returns the string form of the cipher that the IO::Socket::SSL object is using. πΈ
get_sslversion()
Returns the string representation of the SSL version of an established connection. β
get_sslversion_int()
Returns the integer representation of the SSL version of an established connection. π’
get_session_reused()
This returns true if the session got reused and false otherwise. Note that with a reused session no certificates are send within the handshake and no ciphers are offered, and thus functions which rely on this might not work. π
dump_peer_certificate()
Returns a parsable string with select fields from the peer SSL certificate. This method directly returns the result of the dump_peer_certificate() method of Net::SSLeay. π
peer_certificate($field;[$refresh])
If a peer certificate exists, this function can retrieve values from it. If no field is given, the internal representation of the certificate from Net::SSLeay is returned. If refresh is true it will not use a cached version, but check again in case the certificate of the connection has changed due to renegotiation. π
The following fields can be queried:
authority (alias issuer)
The certificate authority which signed the certificate. βοΈ
owner (alias subject)
The owner of the certificate. π€
commonName (alias cn) - only for Net::SSLeay version >=1.30
The common name, usually the server name for SSL certificates. π·οΈ
subjectAltNames - only for Net::SSLeay version >=1.33
Alternative names for the subject, usually different names for the same server, like example.org, example.com, *.example.com.
It returns a list of (typ,value) with typ GEN_DNS, GEN_IPADD etc (these constants are exported from IO::Socket::SSL). See Net::SSLeay::X509_get_subjectAltNames. π
sock_certificate($field)
This is similar to peer_certificate but will return the site's own certificate. The same arguments for $field can be used. If no $field is given, the certificate handle from the underlying OpenSSL will be returned. This handle will only be valid as long as the SSL connection exists β and if you use it afterwards it might result in strange crashes of the application. π
peer_certificates
This returns all the certificates sent by the peer β first the peer's own certificate and then the rest of the chain. You might use CERT_asHash from IO::Socket::SSL::Utils to inspect each of the certificates. π
This function depends on a version of Net::SSLeay >= 1.58. β οΈ
get_servername
This gives the name requested by the client if Server Name Indication (SNI) was used. π
verify_hostname($hostname,$scheme,$publicsuffix)
This verifies the given hostname against the peer certificate using the given scheme. Hostname is usually what you specify within the PeerAddr. See the SSL_verifycn_publicsuffix parameter for an explanation of suffix checking and for the possible values. β
Verification of hostname against a certificate is different between various applications and RFCs. Some schemes allow wildcards for hostnames, some only in subjectAltNames, and even their different wildcard schemes are possible. RFC 6125 provides a good overview. π
To ease the verification, the following schemes are predefined (both protocol name and rfcXXXX name can be used):
rfc2818,xmpp(rfc3920),ftp(rfc4217) β Extended wildcards in subjectAltNames and common name are possible, e.g.*.example.orgor evenwww*.example.org. The common name will be only checked if no DNS names are given in subjectAltNames.http(aliaswww) β While name checking is defined in rfc2818, the current browsers usually accept also an IP address (w/o wildcards) within the common name as long as no subjectAltNames are defined. Thus this is rfc2818 extended with this feature.smtp(rfc2595),imap,pop3,acap(rfc4642),netconf(rfc5538),syslog(rfc5425),snmp(rfc5953) β Simple wildcards in subjectAltNames are possible, e.g.*.example.orgmatcheswww.example.orgbut notlala.www.example.org. If nothing from subjectAltNames match, it checks against the common name, where wildcards are also allowed to match the full leftmost label.ldap(rfc4513) β Simple wildcards are allowed in subjectAltNames, but not in common name. Common name will be checked even if subjectAltNames exist.sip(rfc5922) β No wildcards are allowed and common name is checked even if subjectAltNames exist.gist(rfc5971) β Simple wildcards are allowed in subjectAltNames and common name, but common name will only be checked if there are no DNS names in subjectAltNames.defaultβ This is a superset of all the rules and is automatically used if no scheme is given but a hostname (instead of IP) is known. Extended wildcards are allowed in subjectAltNames and common name and common name is checked always.noneβ No verification will be done. Actually it does not make any sense to callverify_hostnamein this case. π
The scheme can be given either by specifying the name for one of the above predefined schemes, or by using a hash which can have the following keys and values:
check_cn: 0|'always'|'when_only'
Determines if the common name gets checked. If 'always' it will always be checked (like in ldap), if 'when_only' it will only be checked if no names are given in subjectAltNames (like in http), for any other values the common name will not be checked.
wildcards_in_alt: 0|'full_label'|'anywhere'
Determines if and where wildcards in subjectAltNames are possible. If 'full_label' only cases like *.example.org will be possible (like in ldap), for 'anywhere' www*.example.org is possible too (like http), dangerous things like but www.*.org or even '*' will not be allowed. For compatibility with older versions 'leftmost' can be given instead of 'full_label'.
wildcards_in_cn: 0|'full_label'|'anywhere'
Similar to wildcards_in_alt, but checks the common name. There is no predefined scheme which allows wildcards in common names. π«
ip_in_cn:0|1|4|6β decides whether an IP address is even allowed to show up in the common name (and bestie, no wildcards allowed, none, zero, don't even think about it). Set it to4and only IPv4 addresses get through, set it to6and only IPv6 gets through, and literally any other true value lets both of them in. π«Άcallback:\&coderefβ hand over a subroutine and it gets called for verification with these args:($hostname,$commonName,@subjectAltNames). Sohostnameis the name you asked to verify,commonNameis whateverpeer_certificate('cn')gave back, andsubjectAltNamesis whateverpeer_certificate('subjectAltNames')gave back. β¨
Oh and heads up: every other argument for the verification scheme gets ignored in this case. Not "merged", not "considered" β ignored. π
next_proto_negotiated()
Returns the name of the negotiated protocol, like 'http/1.1'. Works on both the client and server side of an SSL connection, so no favorites here. π
NPN support needs Net::SSLeay 1.46+ and openssl-1.0.1+. Wanna check if you've got it? Call IO::Socket::SSL->can_npn(). π¦
alpn_selected()
Gives you back the protocol negotiated via ALPN as a string β think 'http/1.1', 'http/2.0' or 'spdy/3.1'. π
ALPN support needs Net::SSLeay 1.56+ and openssl-1.0.2+. To check support, use IO::Socket::SSL->can_alpn(). π
errstr()
Returns the last error that happened, in string form. And if you don't have an actual object to run this method on, no worries, just call IO::Socket::SSL::errstr() instead. π
For read and write errors on non-blocking sockets, this method might contain the string "SSL wants a read first!" or "SSL wants a write first!" β which is basically the other side saying "hey I'm expecting to read from / write to the socket and I need that handled before you do literally anything else." π
But ngl, with version 0.98 you're way better off comparing the global exported variable$SSL_ERRORagainst the exported symbolsSSL_WANT_READandSSL_WANT_WRITE. Do that instead, fr fr.
opened()
This one's giving very much traffic-light energy:
- returns false if the socket couldn't be opened at all
- returns 1 if the socket opened up and the SSL handshake went off without a hitch
- returns -1 if the underlying
IO::Handleis open but the SSL handshake failed π
is_SSL()
Returns undefined if there's no SSL object attached to the socket at all. Otherwise:
"rw"β the SSL object has SSL active in both directions, we're so back β¨"r"β there was a locally initiated SSL shutdown (close notify)"w"β a remote SSL shutdown was received""β that's the empty string, but still defined! β meaning a bidirectional SSL shutdown was done. π
IO::Socket::SSL->start_SSL($socket, ... )
This one converts a glob reference or a socket you hand it into an IO::Socket::SSL object. Iconic behaviour honestly. You can also pass parameters to specify context or connection options, exactly like you would in a call to new(). π«Ά
If you're running this on an accept()ed socket you must set the parameter SSL_server to 1, like:
IO::Socket::SSL->start_SSL($socket, SSL_server => 1)
And if you've got a class that inherits from IO::Socket::SSL and you want $socket blessed into your class instead of the default one, use MyClass->start_SSL($socket) to get exactly that effect. β¨
Okay so this next bit matters. Ifstart_SSL()fails β wrong arguments, error in SSL negotiation, whatever β it will try to bless the socket back to its original class. But that fails if the socket you gave it wasn't blessed in the first place, because there is no builtin"unbless". So do yourself a favor and useIO::Socket(or otherIO::Handle) objects as$socketinstead of creating unblessed sockets withsocketor similar. Learn from my mistakes bestie. π
For non-blocking sockets you're better off just upgrading the socket to IO::Socket::SSL and calling accept_SSL or connect_SSL on the upgraded object. To just upgrade the socket, set SSL_startHandshake explicitly to 0. And if you call start_SSL without that parameter, it'll revert to blocking behavior for accept_SSL and connect_SSL. No cap. π
If you give it the parameter Timeout, it'll stop if no SSL connection got established after that timeout. And note: this parameter is only used for blocking sockets β if you don't give it, the default Timeout from the underlying IO::Socket gets used instead. π¦
stop_SSL(...)
The exact opposite of start_SSL(), connect_SSL() and accept_SSL() β it shuts down the SSL connection and returns to the class from before start_SSL(). It takes the same arguments as close(), and in fact close() calls stop_SSL() (just without downgrading the class). π
Returns true if it succeeded and undef if it failed. That failure can totally happen with non-blocking sockets, in which case $! is set to EWOULDBLOCK and the ssl error is SSL_WANT_READ or SSL_WANT_WRITE. When that happens, retry the call with the same arguments once the socket is ready. π₯
When calling from "stop_SSL", "SSL_fast_shutdown" defaults to false β meaning it waits for the close_notify of the peer. This is necessary if you want to downgrade the socket and keep using it as a plain socket. If "SSL_fast_shutdown" is set to true, only the write direction gets shut down for SSL and there can still be SSL data read. The read direction then gets closed either automatically when a shutdown from the peer is received during read, or by explicitly calling "stop_SSL" with "SSL_fast_shutdown" false. π
After a complete stop_SSL the socket can be used to exchange plain data again. And even if the SSL shutdown was only done for writing ("SSL_fast_shutdown"), plain data can be written immediately. β¨
If the SSL shutdown was initiated by the peer, it'll lead to an implicit SSL shutdown for reading and sysread will return with 0 in this case. It'll also SSL shutdown the local side. After this, the socket is ready to receive plain data from the peer, and locally sent data will also be transmitted in plain. To prevent accidental sending/receiving of plain data after such an implicit SSL shutdown, the read and write functions will return undef with $ERRNO set to EPERM until an explicit stop_SSL was done. Though if the peer directly closes the TCP connection ater the SSL shutdown without sending plain data, this will still be detected. π¦
If you don't want this default behavior, a callback can be set up using "SSL_on_peer_shutdown" which gets $self as its first argument. The result from the callback will then be returned instead of 0, and no local SSL shutdown will be automatically initiated. Similarly, no explicit stop_SSL is needed before receiving plain data, since the callback is considered explicit action enough. π
connect_SSL, accept_SSL
Use these to do the relevant handshake if the socket was created with "new" or upgraded with "start_SSL" and "SSL_startHandshake" was set to false. They'll return undef until the handshake succeeds or an error gets thrown. And as long as the function returns undef and $! is set to EWOULDBLOCK, you can retry the call once the socket becomes readable (SSL_WANT_READ) or writeable (SSL_WANT_WRITE). πΈ
set_msg_callback
This adds/removes a user defined callback for each message, internally using the openssl SSL_set_msg_callback API. To make sure the callback is active before the handshake starts, combine it with "SSL_startHandshake => 0" in the preceding setup of the SSL object. And to remove the callback explicitly, just call it with an empty callback function. π
Example:
$sock = IO::Socket::SSL->new( .... , SSL_startHandshake => 0);
# set callback
$sock->set_msg_callback(\&cb, $cbarg1, $cbarg2);
$sock->connect_SSL();
sub cb {
my ($sock,
# see SSL_set_msg_callback for the following args
$direction, $ssl_ver, $content_type, $buf, $len, $ssl,
$cbarg1, $cbarg2)
= @_;
...
if (no_longer_need_cb) {
# disable callback
$sock->set_msg_callback(undef);
}
}
ocsp_resolver
This creates an OCSP resolver object, which you can use to create OCSP requests for the certificates of the SSL connection. Which certificates get verified depends on the setting of "SSL_ocsp_mode" β by default only the leaf certificate gets checked, but with SSL_OCSP_FULL_CHAIN all chain certificates get checked. π
And because creating an OCSP request requires knowing the certificate and its issuer certificate, it's just not possible to check certificates when the trust chain is incomplete or if the certificate is self-signed. Not my rules, that's just how it is. π
The OCSP resolver gets created by calling "$ssl->ocsp_resolver" and provides the following methods:
hard_error
Returns the hard error when checking the OCSP response. Hard errors are certificate revocations. And with the "SSL_ocsp_mode" of SSL_OCSP_FAIL_HARD, any soft error (like failures to get signed information about the certificates) gets considered a hard error too. π
The OCSP resolving stops on the first hard error.
The method returns undef as long as no hard errors occurred and there are still requests to be resolved. But if all requests got resolved and no hard errors occurred, the method returns ''. β¨
soft_error
Returns the soft error(s) that occurred when asking the OCSP responders. πΈ
requests
Returns a hash made of (url,request)-tuples β so like, which contain the OCSP request string and the URL where it should be sent too. The usual way to send such a request is as an HTTP POST request with a content-type of application/ocsp-request, or as a GET request with the base64 and url-encoded request added to the path of the URL. π¦
After you've handled all these requests and added the response with "add_response", you should better call this method again to make sure no more requests are outstanding. IO::Socket::SSL will combine multiple OCSP requests for the same server inside a single request, but some server don't give a response to all these requests, so one has to ask again with the remaining requests. π
add_response($uri,$response)β bestie, this one feeds in the HTTP body of the response that came back when the OCSP request went out to$uri. If nothing came back, or something exploded, you either retry or just treat$responseas empty β and an empty one triggers a soft error. The method hands you back the current value ofhard_error, i.e. a defined value once there are no more requests left to do. πresolve_blocking(%args)β this is the lazy-girl combo move: it marriesrequestsandadd_responsetogether with HTTP::Tiny so all the necessary requests happen in a blocking way. Everything in%argsgets passed along to HTTP::Tiny, so proxy settings and that whole vibe go in right here. HTTP::Tiny gets called withverify_SSLset to false, because the OCSP responses carry their own signatures so no extra SSL verification is needed. β¨
If you do not want to do blocking requests, you gotta roll your own user agent usingrequestsandadd_response. No shortcuts, babe. π
IO::Socket::SSL->new_from_fd($fd, [mode], %sslargs)
This converts a socket that's identified by a file descriptor into an SSL socket. Heads up: the argument list does not include a MODE argument β and if you supply one anyway, it gets thoughtfully ignored (for compatibility with IO::Socket::INET, bless). Instead, a mode of '+<' is assumed, and the file descriptor you pass has to be able to handle that kind of I/O, because the initial SSL handshake needs bidirectional communication. π¦
Internally, the $fd you hand over gets upgraded into a socket object using the new_from_fd method of the super class (IO::Socket::INET or similar), and then start_SSL gets called with the %sslargs you gave. Lowkey important: if $fd is already an IO::Socket object, you should really just call start_SSL directly instead. π
IO::Socket::SSL::default_ca([ path|dir| SSL_ca_file = ..., SSL_ca_path => ... ])
This one determines or sets the default CA path. Let's break it down:
- Give it an existing path, or a dir, or a hash β it sets the default CA path to that value and never tries to detect it automatically.
- Give it
undefβ it forgets any stored defaults and carries on with detection of system defaults. - Give it no arguments at all β it starts detection of system defaults, unless it has already stored user-set or previously detected values.
The detection of system defaults works similar to OpenSSL: it checks the directory named in the environment variable SSL_CERT_DIR, or the path OPENSSLDIR/certs (SSLCERTS: on VMS), plus the file named in the environment variable SSL_CERT_FILE, or the path OPENSSLDIR/cert.pem (SSLCERTS:cert.pem on VMS). But contrary to OpenSSL, it also checks whether the SSL_ca_path contains PEM files with the hash as file name, and whether the SSL_ca_file looks like PEM. πΈ If no usable system default can be found, it tries to load and use Mozilla::CA, and if that's not available it gives up detection. Whatever it detects gets saved to speed up future calls. π
The function returns the saved default CA as a hash with SSL_ca_file and SSL_ca_path.
IO::Socket::SSL::set_default_context(...)
Use this to make IO::Socket::SSL automatically re-use a given context (unless it's specifically overridden in a call to new()). It takes one argument, which should be either an IO::Socket::SSL object or an IO::Socket::SSL::SSL_Context object. Peep the SSL_reuse_ctx option of new() for more details.
Careful bestie β this sets the default context globally, so use with caution (especially in mod_perl scripts). π
IO::Socket::SSL::set_default_session_cache(...)
Same energy, but for the session cache: this makes IO::Socket::SSL automatically re-use a given session cache (unless specifically overridden in a call to new()). It takes one argument, which should be an IO::Socket::SSL::Session_Cache object or something similar β like anything that implements get_session, add_session and del_session the way IO::Socket::SSL::Session_Cache does. See the SSL_session_cache option of new() for more. And yeah, this sets the default cache globally too, so caution again. π
IO::Socket::SSL::set_defaults(%args)
With this function you can set defaults for all SSL_* parameters used for creation of the context, like the SSL_verify* parameters. Any SSL_* parameter can be given, or these short versions:
modeβSSL_verify_modecallbackβSSL_verify_callbackschemeβSSL_verifycn_schemenameβSSL_verifycn_name
IO::Socket::SSL::set_client_defaults(%args)
Similar to set_defaults, but only sets the defaults for client mode. π
IO::Socket::SSL::set_server_defaults(%args)
Similar to set_defaults, but only sets the defaults for server mode. π
IO::Socket::SSL::set_args_filter_hack(\&code|'use_defaults')
Okay so sometimes you're forced to use code that passes unwanted or invalid arguments for SSL β typically disabling SSL verification, or setting wrong ciphers or SSL versions. With this hack you can override those settings and restore sanity. Periodt. Example:
IO::Socket::SSL::set_args_filter_hack( sub {
my ($is_server,$args) = @_;
if ( ! $is_server ) {
# client settings - enable verification with default CA
# and fallback hostname verification etc
delete @{$args}{qw(
SSL_verify_mode
SSL_ca_file
SSL_ca_path
SSL_verifycn_scheme
SSL_version
)};
# and add some fingerprints for known certs which are signed by
# unknown CAs or are self-signed
$args->{SSL_fingerprint} = ...
}
});
With the short setting set_args_filter_hack('use_defaults') it will prefer the default settings in all cases. Those default settings can be modified with set_defaults, set_client_defaults and set_server_defaults. π
The following methods are unsupported (not to mention futile!) and IO::Socket::SSL will emit a large CROAK() if you are silly enough to use them:
truncatestatungetcsetbufsetvbuffdopensend/recv
Not me warning you twice, but:send()andrecv()cannot be reliably trapped by a tied filehandle (such as the one used by IO::Socket::SSL), and so they may send unencrypted data over the socket. π± Object-oriented calls to these functions will fail, telling you to use theprintf/syswriteandread/sysreadfamilies instead.
π ACCESS TO INTERNALS π
IO::Socket::SSL uses internally Net::SSLeay, which provides a lower level API to OpenSSL and gives you functions that work directly with OpenSSL SSL and CTX handles. Sometimes you genuinely need direct access to those handles from IO::Socket::SSL so you can apply functionality that's only available with Net::SSLeay. π§
For this, _get_ssl_object can be used on the IO::Socket::SSL object to get access to the OpenSSL SSL handle, and _get_ctx_object can be used on IO::Socket::SSL and IO::Socket::SSL_Context objects to access the OpenSSL CTX handle.
Use very carefully β OpenSSL memory/reference management has to be done manually with Net::SSLeay. This is main character energy with real consequences, bestie. π
π DEPRECATIONS π
The following functions are deprecated and are only retained for compatibility:
context_init()β use theSSL_reuse_ctxoption if you want to re-use a contextsocketToSSL()andsocket_to_SSL()β useIO::Socket::SSL->start_SSL()insteadkill_socket()β useclose()insteadget_peer_certificate()β use thepeer_certificate()function instead. Used to returnX509_Certificatewith methodssubject_nameandissuer_name. Now simply returns$selfwhich has these methods (although deprecated).issuer_name()β usepeer_certificate( 'issuer' )insteadsubject_name()β usepeer_certificate( 'subject' )instead
β¨ EXAMPLES β¨
See the 'example' directory, the tests in 't' and also the tools in 'util'. Go look, they're giving tutorial, they're giving reference material. π
π BUGS π
If you use IO::Socket::SSL together with threads you should load it (e.g. use or require) inside the main thread before creating any other threads which use it. This way it's much faster because it will be initialized only once. Also, there are reports that it might crash the other way. π
Creating an IO::Socket::SSL object in one thread and closing it in another thread will not work. Nope. Not happening.
IO::Socket::SSL does not work together with Storable::fd_retrieve/fd_store. See the BUGS file for more information and how to work around the problem.
If you have a server and it looks like you have a memory leak, you might check the size of your session cache. Default for Net::SSLeay seems to be 20480, see the example for SSL_create_ctx_callback for how to limit it. π
TLS 1.3 support regarding session reuse is incomplete. Just so you know. π
π SEE ALSO π
IO::Socket::INET, IO::Socket::INET6, IO::Socket::IP, Net::SSLeay.
π«Ά THANKS π«Ά
Many thanks to all who added patches or reported bugs or helped IO::Socket::SSL another way. Please keep reporting bugs and help with patches, even if they just fix the documentation. (Yes, doc fixes count. They eat, actually. π)
Special thanks to the team of Net::SSLeay for the good cooperation. π
π AUTHORS π
Steffen Ullrich, <sullr at cpan.org> is the current maintainer.
Peter Behroozi, <behrooz at fas.harvard.edu> (Note the lack of an "i" at the end of "behrooz") β iconic detail, do not skip it bestie. πΈ
Marko Asplund, <marko.asplund at kronodoc.fi>, was the original author of IO::Socket::SSL.
Patches incorporated from various people, see file Changes.
π COPYRIGHT π
The original versions of this module are Copyright (C) 1999-2002 Marko Asplund.
The rewrite of this module is Copyright (C) 2002-2005 Peter Behroozi.
Versions 0.98 and newer are Copyright (C) 2006-2014 Steffen Ullrich.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
And that's a wrap on the whole page, bestie! π This rendering comes from perl v5.42.0 and it's dated 2026-01-17 β the IO::Socket::SSL(3) era, and honestly? We ate. π
β¨ Go forth and encrypt responsibly. π¦
π¦ where this page comes from
- fedora 44: perl-IO-Socket-SSL 2.098-2.fc44 Β· (GPL-1.0-or-later OR Artistic-1.0-Perl) AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms