ssl

MODULE

ssl

MODULE SUMMARY

Interface Functions for Secure Socket Layer

DESCRIPTION

This module contains interface functions to the Secure Socket Layer.

SSL

  • ssl requires the crypto an public_key applications.
  • Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0
  • For security reasons sslv2 is not supported.
  • Ephemeral Diffie-Hellman cipher suites are supported but not Diffie Hellman Certificates cipher suites.
  • Export cipher suites are not supported as the U.S. lifted its export restrictions in early 2000.
  • CRL and policy certificate extensions are not supported yet.

COMMON DATA TYPES

The following data types are used in the functions below:

boolean() = true | false

property() = atom()

option() = socketoption() | ssloption() | transportoption()

socketoption() = [{property(), term()}] - defaults to [{mode,list},{packet, 0},{header, 0},{active, true}].

For valid options see inet(3) and gen_tcp(3) .

ssloption() = {verify, verify_type()} | {verify_fun, {fun(), term()}} | {fail_if_no_peer_cert, boolean()} {depth, integer()} | {cert, der_bin()}| {certfile, path()} | {key, der_bin()} | {keyfile, path()} | {password, string()} | {cacerts, [der_bin()]} | {cacertfile, path()} | |{dh, der_bin()} | {dhfile, path()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}

transportoption() = {CallbackModule, DataTag, ClosedTag} - defaults to {gen_tcp, tcp, tcp_closed}. Ssl may be run over any reliable transport protocol that has an equivalent API to gen_tcp's.

      CallbackModule = atom()

      DataTag = atom() - tag used in socket data message.

      ClosedTag = atom() - tag used in socket close message.

verify_type() = verify_none | verify_peer

path() = string() - representing a file path.

der_bin() = binary() -Asn1 DER encoded entity as an erlang binary.

host() = hostname() | ipaddress()

hostname() = string()

ip_address() = {N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6

sslsocket() - opaque to the user.

protocol() = sslv3 | tlsv1

ciphers() = [ciphersuite()] | string() (according to old API)

ciphersuite() = {key_exchange(), cipher(), hash()}

key_exchange() = rsa | dhe_dss | dhe_rsa

cipher() = rc4_128 | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc

hash() = md5 | sha

ssl_imp() = new | old - default is new.

SSL OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT

Options described here are options that are have the same meaning in the client and the server.

{cert, der_bin()}
The DER encoded users certificate. If this option is supplied it will override the certfile option.
{certfile, path()}
Path to a file containing the user's certificate.
{key, der_bin()}
The DER encoded users private key. If this option is supplied it will override the keyfile option.
{keyfile, path()}
Path to file containing user's private PEM encoded key. As PEM-files may contain several entries this option defaults to the same file as given by certfile option.
{password, string()}
String containing the user's password. Only used if the private keyfile is password protected.
{cacerts, [der_bin()]}
The DER encoded trusted certificates. If this option is supplied it will override the cacertfile option.
{cacertfile, path()}
Path to file containing PEM encoded CA certificates (trusted certificates used for verifying a peer certificate). May be omitted if you do not want to verify the peer.
{ciphers, ciphers()}
The cipher suites that should be supported. The function ciphers_suites/0 can be used to find all available ciphers.
{ssl_imp, ssl_imp()}
Specify which ssl implementation you want to use. Defaults to new.
{secure_renegotiate, boolean()}
Specifies if to reject renegotiation attempt that does not live up to RFC 5746. By default secure_renegotiate is set to false i.e. secure renegotiation will be used if possible but it will fallback to unsecure renegotiation if the peer does not support RFC 5746.
{depth, integer()}
Specifies the maximum verification depth, i.e. how far in a chain of certificates the verification process can proceed before the verification is considered to fail. Peer certificate = 0, CA certificate = 1, higher level CA certificate = 2, etc. The value 2 thus means that a chain can at most contain peer cert, CA cert, next CA cert, and an additional CA cert. The default value is 1.
{verify_fun, {Verifyfun :: fun(), InitialUserState :: term()}}

The verification fun should be defined as:

fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
	     {extension, #'Extension'{}}, InitialUserState :: term()) ->
	{valid, UserState :: term()} | {fail, Reason :: term()} |
	{unknown, UserState :: term()}.
	

The verify fun will be called during the X509-path validation when an error or an extension unknown to the ssl application is encountered. Additionally it will be called when a certificate is considered valid by the path validation to allow access to each certificate in the path to the user application. See public_key(3) for definition of #'OtpCertificate'{} and #'Extension'{}.

If the verify callback fun returns {fail, Reason}, the verification process is immediately stopped and an alert is sent to the peer and the TLS/SSL handshake is terminated. If the verify callback fun returns {valid, UserState}, the verification process is continued. If the verify callback fun always returns {valid, UserState}, the TLS/SSL handshake will not be terminated with respect to verification failures and the connection will be established. If called with an extension unknown to the user application the return value {unknown, UserState} should be used.

The default verify_fun option in verify_peer mode:

{fun(_,{bad_cert, _} = Reason, _) ->
	 {fail, Reason};
    (_,{extension, _}, UserState) ->
	 {unknown, UserState};
    (_, valid, UserState) ->
	 {valid, UserState}
 end, []}
      

The default verify_fun option in verify_none mode:

{fun(_,{bad_cert, unknown_ca}, UserState) ->
	 {valid, UserState};
    (_,{bad_cert, _} = Reason, _) ->
	 {fail, Reason};
    (_,{extension, _}, UserState) ->
	 {unknown, UserState};
    (_, valid, UserState) ->
	 {valid, UserState}
 end, []}
      

Possible path validation errors:

{bad_cert, cert_expired}, {bad_cert, invalid_issuer}, {bad_cert, invalid_signature}, {bad_cert, unknown_ca}, {bad_cert, name_not_permitted}, {bad_cert, missing_basic_constraint}, {bad_cert, invalid_key_usage}

SSL OPTION DESCRIPTIONS - CLIENT SIDE

Option described here are client specific or has a slightly different meaning in the client than in the server.

{verify, verify_type()}
In verify_none mode the x509-path validation error {bad_cert, unknown_ca} will automatically be accepted. See also the verify_fun option.
{reuse_sessions, boolean()}
Specifies if client should try to reuse sessions when possible.

SSL OPTION DESCRIPTIONS - SERVER SIDE

Option described here are server specific or has a slightly different meaning in the server than in the client.

{dh, der_bin()}
The DER encoded Diffie Hellman parameters. If this option is supplied it will override the dhfile option.
{dhfile, path()}
Path to file containing PEM encoded Diffie Hellman parameters, for the server to use if a cipher suite using Diffie Hellman key exchange is negotiated. If not specified default parameters will be used.
{verify, verify_type()}
Servers only do the x509-path validation in verify_peer mode, as it then will send a certificate request to the client (this message is not sent if the verify option is verify_none) and you may then also want to specify the option fail_if_no_peer_cert.
{fail_if_no_peer_cert, boolean()}
Used together with {verify, verify_peer} by a ssl server. If set to true, the server will fail if the client does not have a certificate to send, i.e. sends a empty certificate, if set to false it will only fail if the client sends a invalid certificate (an empty certificate is considered valid).
{reuse_sessions, boolean()}
Specifies if the server should agree to reuse sessions when the clients request to do so. See also the reuse_session option.
{reuse_session, fun(SuggestedSessionId, PeerCert, Compression, CipherSuite) -> boolean()}
Enables the ssl server to have a local policy for deciding if a session should be reused or not, only meaning full if reuse_sessions is set to true. SuggestedSessionId is a binary(), PeerCert is a DER encoded certificate, Compression is an enumeration integer and CipherSuite of type ciphersuite().

General

When a ssl socket is in active mode (the default), data from the socket is delivered to the owner of the socket in the form of messages:

  • {ssl, Socket, Data}
  • {ssl_closed, Socket}
  • {ssl_error, Socket, Reason}

A Timeout argument specifies a timeout in milliseconds. The default value for a Timeout argument is infinity.

EXPORTS

cipher_suites() ->
cipher_suites(Type) -> ciphers()

Types:

Type = erlang | openssl

Returns a list of supported cipher suites. cipher_suites() is equivalent to cipher_suites(erlang). Type openssl is provided for backwards compatibility with old ssl that used openssl.

connect(Socket, SslOptions) ->
connect(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {error, Reason}

Types:

Socket = socket()
SslOptions = [ssloption()]
Timeout = integer() | infinity
SslSocket = sslsocket()
Reason = term()

Upgrades a gen_tcp, or equivalent, connected socket to a ssl socket i.e. performs the client-side ssl handshake.

connect(Host, Port, Options) ->
connect(Host, Port, Options, Timeout) -> {ok, SslSocket} | {error, Reason}

Types:

Host = host()
Port = integer()
Options = [option()]
Timeout = integer() | infinity
SslSocket = sslsocket()
Reason = term()

Opens an ssl connection to Host, Port.

close(SslSocket) -> ok | {error, Reason}

Types:

SslSocket = sslsocket()
Reason = term()

Close a ssl connection.

controlling_process(SslSocket, NewOwner) -> ok | {error, Reason}

Types:

SslSocket = sslsocket()
NewOwner = pid()
Reason = term()

Assigns a new controlling process to the ssl-socket. A controlling process is the owner of a ssl-socket, and receives all messages from the socket.

connection_info(SslSocket) -> {ok, {ProtocolVersion, CipherSuite}} | {error, Reason}

Types:

CipherSuite = ciphersuite()
ProtocolVersion = protocol()

Returns the negotiated protocol version and cipher suite.

format_error(Reason) -> string()

Types:

Reason = term()

Presents the error returned by an ssl function as a printable string.

getopts(Socket) ->
getopts(Socket, OptionNames) -> {ok, [socketoption()]} | {error, Reason}

Types:

Socket = sslsocket()
OptionNames = [property()]

Get the value of the specified socket options, if no options are specified all options are returned.

listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}

Types:

Port = integer()
Options = options()
ListenSocket = sslsocket()

Creates a ssl listen socket.

peercert(Socket) -> {ok, Cert} | {error, Reason}

Types:

Socket = sslsocket()
Cert = binary()

The peer certificate is returned as a DER encoded binary. The certificate can be decoded with public_key:pkix_decode_cert/2.

peername(Socket) -> {ok, {Address, Port}} | {error, Reason}

Types:

Socket = sslsocket()
Address = ipaddress()
Port = integer()

Returns the address and port number of the peer.

recv(Socket, Length) ->
recv(Socket, Length, Timeout) -> {ok, Data} | {error, Reason}

Types:

Socket = sslsocket()
Length = integer()
Timeout = integer()
Data = [char()] | binary()

This function receives a packet from a socket in passive mode. A closed socket is indicated by a return value {error, closed}.

The Length argument is only meaningful when the socket is in raw mode and denotes the number of bytes to read. If Length = 0, all available bytes are returned. If Length > 0, exactly Length bytes are returned, or an error; possibly discarding less than Length bytes of data when the socket gets closed from the other side.

The optional Timeout parameter specifies a timeout in milliseconds. The default value is infinity.

renegotiate(Socket) -> ok | {error, Reason}

Types:

Socket = sslsocket()

Initiates a new handshake. A notable return value is {error, renegotiation_rejected} indicating that the peer refused to go through with the renegotiation but the connection is still active using the previously negotiated session.

send(Socket, Data) -> ok | {error, Reason}

Types:

Socket = sslsocket()
Data = iolist() | binary()

Writes Data to Socket.

A notable return value is {error, closed} indicating that the socket is closed.

setopts(Socket, Options) -> ok | {error, Reason}

Types:

Socket = sslsocket()
Options = [socketoption]()

Sets options according to Options for the socket Socket.

shutdown(Socket, How) -> ok | {error, Reason}

Types:

Socket = sslsocket()
How = read | write | read_write
Reason = reason()

Immediately close a socket in one or two directions.

How == write means closing the socket for writing, reading from it is still possible.

To be able to handle that the peer has done a shutdown on the write side, the {exit_on_close, false} option is useful.

ssl_accept(ListenSocket) ->
ssl_accept(ListenSocket, Timeout) -> ok | {error, Reason}

Types:

ListenSocket = sslsocket()
Timeout = integer()
Reason = term()

The ssl_accept function establish the SSL connection on the server side. It should be called directly after transport_accept, in the spawned server-loop.

ssl_accept(ListenSocket, SslOptions) ->
ssl_accept(ListenSocket, SslOptions, Timeout) -> {ok, Socket} | {error, Reason}

Types:

ListenSocket = socket()
SslOptions = ssloptions()
Timeout = integer()
Reason = term()

Upgrades a gen_tcp, or equivalent, socket to a ssl socket i.e. performs the ssl server-side handshake.

Warning

Note that the listen socket should be in {active, false} mode before telling the client that the server is ready to upgrade and calling this function, otherwise the upgrade may or may not succeed depending on timing.

sockname(Socket) -> {ok, {Address, Port}} | {error, Reason}

Types:

Socket = sslsocket()
Address = ipaddress()
Port = integer()

Returns the local address and port number of the socket Socket.

start() ->
start(Type) -> ok | {error, Reason}

Types:

Type = permanent | transient | temporary

Starts the Ssl application. Default type is temporary. application(3)

stop() -> ok

Stops the Ssl application. application(3)

transport_accept(Socket) ->
transport_accept(Socket, Timeout) -> {ok, NewSocket} | {error, Reason}

Types:

Socket = NewSocket = sslsocket()
Timeout = integer()
Reason = reason()

Accepts an incoming connection request on a listen socket. ListenSocket must be a socket returned from listen/2. The socket returned should be passed to ssl_accept to complete ssl handshaking and establishing the connection.

Warning

The socket returned can only be used with ssl_accept, no traffic can be sent or received before that call.

The accepted socket inherits the options set for ListenSocket in listen/2.

The default value for Timeout is infinity. If Timeout is specified, and no connection is accepted within the given time, {error, timeout} is returned.

versions() -> [{SslAppVer, SupportedSslVer, AvailableSslVsn}]

Types:

SslAppVer = string()
SupportedSslVer = [protocol()]
AvailableSslVsn = [protocol()]

Returns version information relevant for the ssl application.

SEE ALSO