diff options
Diffstat (limited to 'lib/ssl')
33 files changed, 4422 insertions, 5730 deletions
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index 49bbd5d27d..299850333d 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2012</year> + <year>1999</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -22,15 +22,121 @@ </legalnotice> <title>SSL Release Notes</title> - <prepared>Peter Högfeldt</prepared> - <docno></docno> - <date>2003-08-03</date> - <rev>G</rev> <file>notes.xml</file> </header> <p>This document describes the changes made to the SSL application.</p> - <section><title>SSL 5.1.2</title> + <section><title>SSL 5.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + SSL: TLS 1.2, advertise sha224 support, thanks to Andreas + Schultz.</p> + <p> + Own Id: OTP-10586</p> + </item> + <item> + <p> + If an ssl server is restarted with new options and a + client tries to reuse a session the server must make sure + that it complies to the new options before agreeing to + reuse it.</p> + <p> + Own Id: OTP-10595</p> + </item> + <item> + <p> + Now handles cleaning of CA-certificate database correctly + so that there will be no memory leek, bug was introduced + in ssl- 5.1 when changing implementation to increase + parallel execution.</p> + <p> + Impact: Improved memory usage, especially if you have + many different certificates and upgrade tcp-connections + to TLS-connections.</p> + <p> + Own Id: OTP-10710</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Support Next Protocol Negotiation in TLS, thanks to Ben + Murphy for the contribution.</p> + <p> + Impact: Could give performance benefit if used as it + saves a round trip.</p> + <p> + Own Id: OTP-10361 Aux Id: kunagi-214 [125] </p> + </item> + <item> + <p> + TLS 1.2 will now be the default TLS version if sufficient + crypto support is available otherwise TLS 1.1 will be + default.</p> + <p> + Impact: A default TLS connection will have higher + security and hence it may be perceived as slower then + before.</p> + <p> + Own Id: OTP-10425 Aux Id: kunagi-275 [186] </p> + </item> + <item> + <p> + It is now possible to call controlling_process on a + listen socket, same as in gen_tcp.</p> + <p> + Own Id: OTP-10447</p> + </item> + <item> + <p> + Remove filter mechanisms that made error messages + backwards compatible with old ssl but hid information + about what actually happened.</p> + <p> + This does not break the documented API however other + reason terms may be returned, so code that matches on the + reason part of {error, Reason} may fail.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-10451 Aux Id: kunagi-270 [181] </p> + </item> + <item> + <p> + Added missing dependencies to Makefile</p> + <p> + Own Id: OTP-10594</p> + </item> + <item> + <p> + Removed deprecated function ssl:pid/0, it has been + pointless since R14 but has been keep for backwards + compatibility.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-10613 Aux Id: kunagi-331 [242] </p> + </item> + <item> + <p> + Refactor to simplify addition of key exchange methods, + thanks to Andreas Schultz.</p> + <p> + Own Id: OTP-10709</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 5.1.2</title> <section><title>Fixed Bugs and Malfunctions</title> <list> @@ -605,1285 +711,7 @@ </item> </list> </section> - </section> - - - <section><title>SSL 3.11.1</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixed handling of several ssl/tls packets arriving at the - same time. This was broken during a refactoring of the - code.</p> - <p> - Own Id: OTP-8679</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - Added missing checks for padding and Mac value. Removed - code for export ciphers and DH certificates as we decided - not to support them.</p> - <p> - Own Id: OTP-7047</p> - </item> - <item> - <p> - New ssl will no longer return esslerrssl to be backwards - compatible with old ssl as this hids infomation from the - user. format_error/1 has been updated to support new ssl.</p> - <p> - *** POTENTIAL INCOMPATIBILITY ***</p> - <p> - Own Id: OTP-7049</p> - </item> - <item> - <p> - New ssl now supports secure renegotiation as described by - RFC 5746.</p> - <p> - Own Id: OTP-8568</p> - </item> - <item> - <p> - Alert handling has been improved to better handle - unexpected but valid messages and the implementation is - also changed to avoid timing related issues that could - cause different error messages depending on network - latency. Packet handling was sort of broken but would - mostly work as expected when socket was in binary mode. - This has now been fixed.</p> - <p> - Own Id: OTP-8588</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.11</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixes handling of the option fail_if_no_peer_cert and - some undocumented options. Thanks to Rory Byrne.</p> - <p> - Own Id: OTP-8557</p> - </item> - </list> - </section> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - Support for Diffie-Hellman. ssl-3.11 requires - public_key-0.6.</p> - <p> - Own Id: OTP-7046</p> - </item> - <item> - <p> - New ssl now properly handles ssl renegotiation, and - initiates a renegotiation if ssl/ltls-sequence numbers - comes close to the max value. However RFC-5746 is not yet - supported, but will be in an upcoming release.</p> - <p> - Own Id: OTP-8517</p> - </item> - <item> - <p> - When gen_tcp is configured with the {packet,http} option, - it automatically switches to expect HTTP Headers after a - HTTP Request/Response line has been received. This update - fixes ssl to behave in the same way. Thanks to Rory - Byrne.</p> - <p> - Own Id: OTP-8545</p> - </item> - <item> - <p> - Ssl now correctly verifies the extended_key_usage - extension and also allows the user to verify application - specific extensions by supplying an appropriate fun.</p> - <p> - Own Id: OTP-8554 Aux Id: OTP-8553 </p> - </item> - <item> - <p> - Fixed ssl:transport_accept/2 to return properly when - socket is closed. Thanks to Rory Byrne.</p> - <p> - Own Id: OTP-8560</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.9</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixed a crash in the certificate certification part.</p> - <p> - Own Id: OTP-8510 Aux Id: seq11525 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.8</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p><c>ssl:send/2</c> ignored packet option, fix provided - by YAMASHINA Hio.</p> - <p>Fixed a file cache bug which caused problems when the - same file was used for both cert and cacert.</p> - <p>Allow <c>ssl:listen/2</c> to be called with option - {ssl_imp, old}.</p> - <p> Fixed ssl:setopts(Socket, binary) which didn't work - for 'new' ssl.</p>. - <p> - Own Id: OTP-8441</p> - </item> - <item> - <p> - Do a controlled shutdown if a non ssl packet arrives as - the first packet.</p> - <p> - Own Id: OTP-8459 Aux Id: seq11505 </p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>Fixed session reuse (in new_ssl), thanks Wil Tan.</p> - <p>Send CA list during Certificate Request (in new_ssl) , - thanks Wil Tan.</p> <p><c>NOTE</c>: SSL (new_ssl) - requires public_key-0.5.</p> - <p> - Own Id: OTP-8372</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.7</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - A ticker process could potentially be blocked - indefinitely trying to send a tick to a node not - responding. If this happened, the connection would not be - brought down as it should.</p> - <p> This requires erts-5.7.4 and kernel-2.13.4 or later - to be able to get the erlang distribution over ssl to work.</p> - <p> - Own Id: OTP-8218</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The documentation is now built with open source tools - (xsltproc and fop) that exists on most platforms. One - visible change is that the frames are removed.</p> - <p> - Own Id: OTP-8250</p> - </item> - <item> - <p> - Code cleanup from Kostis.</p> - <p> - Own Id: OTP-8260</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.6</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - The ssl:ssl_accept/3 issue was not properly fixed in the - previous patch, see OTP-8244.</p> - <p> - Own Id: OTP-8275 Aux Id: seq11451 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.5</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Allow clients to not send certificates if option - <c>fail_if_no_peer_cert</c> was not set.</p> - <p> - Own Id: OTP-8224</p> - </item> - <item> - <p>An ssl:ssl_accept/3 could crash a connection if the - timing was wrong.</p> <p>Removed info message if the - socket closed without a proper disconnect from the ssl - layer. </p> <p>ssl:send/2 is now blocking until the - message is sent.</p> - <p> - Own Id: OTP-8244 Aux Id: seq11420 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.4</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - A client could avoid a certificate check if the client - code didn't send the requested certificate.</p> - <p> - Own Id: OTP-8137</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.3</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>Packet handling was not implemented correctly.</p> - <p>Inet option handling support have been improved.</p> - <p>The <c>verify_fun</c> is now invoked even if - verify_peer is used, that implies that by default - {bad_cert,unknown_ca} is an accepted fault during the - client connection phase. The check can still be done by - suppling another verify_fun.</p> - <p> - Own Id: OTP-8011 Aux Id: seq11287 </p> - </item> - </list> - </section> - -</section> - - -<section><title>SSL 3.10.2</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - A "new_ssl" socket was not closed if the controlling - process died without calling ssl:close/1.</p> - <p> - Own Id: OTP-7963 Aux Id: seq11276 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.1</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixed bug that caused the ssl handshake finished message - to be calculated wrongly under the circumstances that the - server did not send the trusted cert and that the - previous cert did not have the extension telling us the - trusted certs name. This manifested it self as - bad_record_mac alert from the server.</p> - <p> - Own Id: OTP-7878</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The cacertsfile option is now optional for ssl servers.</p> - <p> - Own Id: OTP-7656</p> - </item> - <item> - <p> - For the ssl client the options cacertfile, certfile and - keyfile are now optional as they are not always needed - depending on configuration of the client itself and the - configuration of the server. Also as PEM-files may - contain more than one entry the keyfile option will - default to the same file as given by the certfile option.</p> - <p> - Own Id: OTP-7870</p> - </item> - <item> - <p> - Added new ssl client option verify_fun.</p> - <p> - Own Id: OTP-7871</p> - </item> - </list> - </section> - -</section> - - <section><title>SSL 3.10</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Error log entries are now formatted correctly.</p> - <p> - Own Id: OTP-7258</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - All handling of X509-certificates and public keys have - been moved to the new application public_key.</p> - <p> - Own Id: OTP-6894</p> - </item> - <item> - <p> - New ssl now supports SSL-3.0 and TLS-1.0</p> - <p> - Own Id: OTP-7037</p> - </item> - <item> - <p> - New ssl now supports all inet-packet types.</p> - <p> - Own Id: OTP-7039</p> - </item> - <item> - <p> - The new ssl-server is now able to send a certificate - request to the client. However new options may be - introduced later to fully support all features regarding - certificate requests.</p> - <p> - Own Id: OTP-7150</p> - </item> - </list> - </section> - - - <section><title>Known Bugs and Problems</title> - <list> - <item> - <p> - Running erlang distribution over ssl don't work as - described in the documentation.</p> - <p> - Own Id: OTP-7536</p> - </item> - </list> - </section> - - </section> - - - <section><title>SSL 3.9</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - ssl_prim.erl was passing an FD rather than an #sslsocket - to ssl_broker:ssl_accept_prim. This could cause problems - in the deprecated accept function, this will not cause - any more problems however this function is deprecated!</p> - <p> - Own Id: OTP-6926</p> - </item> - <item> - <p> - Erlang distribution over ssl was broken after R11B-0, - this has now been fixed.</p> - <p> - Own Id: OTP-7004</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - All inet options are available in the new ssl - implementation that is released as a alfa in ssl-3.9 and - will replace the old implementation in ssl-4.0. This will - not be fixed in the old implementation.</p> - <p> - Own Id: OTP-4677</p> - </item> - <item> - <p> - The new ssl implementation released as a alfa in this - version supports upgrading of a tcp connection to an ssl - connection so that http client and servers may implement - RFC 2817.</p> - <p> - Own Id: OTP-5510</p> - </item> - <item> - <p>A new implementation of ssl is released as a alfa - version in ssl-3.9 it will later replace the old - implementation in ssl-4.0. The new implementation can be - accessed by providing the option {ssl_imp, new} to the - ssl:connect and ssl:listen functions.</p> - <p>The new implementation is Erlang based and all logic - is in Erlang and only payload encryption calculations are - done in C via the crypto application. The main reason for - making a new implementation is that the old solution was - very crippled as the control of the ssl-socket was deep - down in openssl making it hard if not impossible to - support all inet options, ipv6 and upgrade of a tcp - connection to an ssl connection. The alfa version has a - few limitations that will be removed before the ssl-4.0 - release. Main differences and limitations in the alfa are - listed below.</p> - - <list type="bulleted"> <item>New ssl requires the crypto - application.</item> <item>The option reuseaddr is - supported and the default value is false as in gen_tcp. - Old ssl is patched to accept that the option is set to - true to provide a smoother migration between the - versions. In old ssl the option is hard coded to - true.</item> <item>ssl:version/0 is replaced by - ssl:versions/0</item> <item>ssl:ciphers/0 is replaced by - ssl:cipher_suites/0</item> <item>ssl:pid/1 is a - meaningless function in new ssl and will be deprecated in - ssl-4.0 until it is removed it will return a valid but - meaningless pid.</item> <item>New API functions are - ssl:shutdown/2, ssl:cipher_suites/[0,1] and - ssl:versions/0</item> <item>Diffie-Hellman keyexchange is - not supported.</item> <item>Not all inet packet types are - supported.</item> <item>CRL and policy certificate - extensions are not supported.</item> <item>In this alfa - only sslv3 is enabled, although tlsv1 and tlsv1.1 - versions are implemented and will be supported in future - versions.</item> <item>For security reasons sslv2 is not - supported.</item> </list> - <p> - Own Id: OTP-6619</p> - </item> - <item> - <p> - New ssl implementation, released as alfa in ssl-3.9, - supports ipv6. It will not be supported in the old - implementation.</p> - <p> - Own Id: OTP-6637 Aux Id: OTP-6636 </p> - </item> - </list> - </section> - - </section> - - <section> - <title>SSL 3.1.1.1</title> - - <section> - <title>Minor Makefile changes</title> - <list type="bulleted"> - <item> - <p>Removed use of <c>erl_flags</c> from Makefile.</p> - <p>Own Id: OTP-6689</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.1.1</title> - - <section> - <title>Crash on error in ssl_accept</title> - <list type="bulleted"> - <item> - <p>A bug in ssl_accept could cause all ssl - connections to hang when a connection - attempt was closed by the client while - the server was in <c>ssl_accept</c>.</p> - <p>Own Id: OTP-6612 Aux Id: seq10599</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>SSL now uses a two-phase accept, with a separate accept - calls for the socket and the ssl protocol. This avoids - timeouts when a client doesn't initiate ssl handshake.</p> - <p>With the old implementation of accept, the server - was locked by a client, if the client didn't do - proper ssl handshake.</p> - <p>Own Id: OTP-6418 Aux Id: seq10105</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.12</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>An integer array pointing to a struct pollfd array, is - now reset before file descriptors are collected to be - included in a call to poll(). This is to prevent file - descriptors to be mixed up.</p> - <p>Own Id: OTP-6084</p> - </item> - <item> - <p>The generation of the module ssl_pkix_oid contained - multiple identifiers, which made the mapping between - atoms and identifiers not one-to-one.</p> - <p>Own Id: OTP-6085</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.11</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The state of a connection in active mode could be in a - restrictive state, so that an internal tcp_closed message - was incorrectly considered illegal, resulting in a - premature termination of the connection process.</p> - <p>Own Id: OTP-5972 Aux Id: seq10188 </p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.10</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Erlang distribution over SSL was broken. Corrected. - (Thanks to Fredrik Thulin.)</p> - <p>Own Id: OTP-5863</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.9</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The port program for the ssl application could waste huge - amounts of CPU time if a write could not be completed - directly and was put in the write queue. (Only on platforms - where poll() is used, such as Solaris and Linux.)</p> - <p>Own Id: OTP-5784</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.8</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>A process reading only a portion of a sufficiently large - amount of data from an accepted socket, and then quering - the ssl library (e.g. ssl:getpeername()), would cause a - global deadlock in the esock port program.</p> - <p>Own Id: OTP-5702</p> - </item> - <item> - <p>A spelling error in the module <c>ssl_pkix</c> caused the - call to <c>ssl:peercert/2</c> to fail when the option - <c>subject</c> was used.</p> - <p>Own Id: OTP-5708</p> - </item> - <item> - <p>Because fopen() on Solaris 8 can't handle file - descriptor numbers above 255, reading of certificate - files would fail if all file descriptors below 256 were - in use (typically, if many connections were open). This - problem has been worked around.</p> - <p>The ssl application's port program used to use - select(), which meant that it could not handle more than - FD_SETSIZE file descriptors (usually 1024). To eliminate - that limitation, poll() is now used on all platforms that - support it.</p> - <p>Solaris/Sparc, 64-bit emulator: The SO_REUSEADDR - option was not set for listen sockets, which essentially - made the ssl application unusable. Corrected.</p> - <p>The default listen queue size for ssl port program was - changed to 128 (from 5).</p> - <p>Own Id: OTP-5755 Aux Id: seq10068 </p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.7</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The R/W buffer length i esock.c was too small. It has - been increased from 4k to 32k.</p> - <p>Own Id: OTP-5620</p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.6</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>A configuration option for choosing protocol versions has - been added (<c>sslv2</c>, <c>sslv3</c>, and - <c>tlsv1</c>).</p> - <p>Own Id: OTP-5429 Aux Id: seq9755 </p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.5</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Linked in drivers in the crypto, and asn1 applications - are now compiled with the -D_THREAD_SAFE and -D_REENTRANT - switches on unix when the emulator has thread support - enabled.</p> - <p>Linked in drivers on MacOSX are not compiled with the - undocumented -lbundle1.o switch anymore. Thanks to Sean - Hinde who sent us a patch.</p> - <p>Linked in driver in crypto, and port programs in ssl, now - compiles on OSF1.</p> - <p>Minor makefile improvements in runtime_tools.</p> - <p>Own Id: OTP-5346</p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.4</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p><c>ssl:recv/3</c> with finite timeout value, closed the - connection at timeout.</p> - <p>Own Id: OTP-4882</p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.3</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>When a file descriptor was marked for closing, and - end-of-file condition had already been detected, the file - descriptor was never closed.</p> - <p>Own Id: OTP-5093 Aux Id: seq8806 </p> - </item> - <item> - <p>When the number of open file descriptors reached - FD_SETSIZE, the SSL port program entered a busy loop.</p> - <p>Own Id: OTP-5094 Aux Id: seq8806 </p> - </item> - </list> - </section> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The SSL application now supports SSL sessions for - servers, which typically speeds up HTTP requests from - browsers.</p> - <p>Own Id: OTP-5095</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.2</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The UTF8String type is now defined in asn1-1.4.4.2 and - later. Therefore the definitions of UTF8String has been - removed from the ASN.1 modules PKIX1Explicit88.asn1 and - PKIXAttributeCertificate.asn1. The SSL application can now - only be built using asn-1.4.4.2 or later.</p> - <p>OwnId: OTP-4971.</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL-3.0. - </p> - </section> - </section> - - <section> - <title>SSL 3.0.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>An unexpected object identifier would crash <c>ssl:peercert</c>. </p> - <p>OwnId: OTP-4771.</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL-3.0. - </p> - </section> - </section> - - <section> - <title>SSL 3.0</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The <c>cache_timout</c> option was silently ignored. It had - to do with SSL sessions, where multiple connections can occur. - Since the Erlang SSL application does not support sessions the - option is still ignored, and consequently the documentation - about it has been removed.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>The Erlang SSL application is now based on OpenSSL version - 0.9.7a. OpenSSL 0.9.6 should also work.</p> - <p>OwnId: OTP-4002</p> - </item> - <item> - <p>When connecting it is now possible to bind to a local address - and local port. </p> - <p>OwnId: OTP-4675</p> - </item> - <item> - <p>The <c>ssl_esock</c> port program is now part of the - distribution and thus does not have to be created - explicitly. It is dynamically linked to OpenSSL - libraries in a "standard" location (typically - <c>/usr/local/lib</c> on UNIX; in the path on Win32).</p> - <p>OwnId: - OTP-4676</p> - </item> - <item> - <p>The new functions <c>ssl:peercert/1/2</c> provide information - from the certificate of a peer of a connection.</p> - <p>OwnId: OTP-4680 - <br></br> -Aux Id: seq7688</p> - </item> - <item> - <p>The function <c>ssl:port/1</c> has been removed from the - documentation, but not from the <c>ssl</c> interface module. - The recommendation is to use <c>ssl:peername/1</c> - instead, which provides both address and port of the peer.</p> - <p>OwnId: OTP-4681 </p> - </item> - <item> - <p>New User's Guide documentation has been added.</p> - <p>OwnId: OTP-4682 </p> - </item> - <item> - <p>The old <c>ssl_socket</c> interface has been removed and also - the documentation of it. </p> - <p>OwnId: OTP-4683 </p> - </item> - <item> - <p>The use of ephemeral RSA keys is now supported. It is - a global configuration option (see the ssl(6) manual page).</p> - <p>OwnId: OTP-4691.</p> - </item> - </list> - </section> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The option <c>cacertfile</c> is now in effect, and can - therefore no longer be set with the OS environment - variable SSL_CERT_FILE (which did set the same value for - all connections). </p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>There was a synchronization error at closing of an SSL - connection. </p> - <p>OwnId: OTP-4435 - <br></br> -Aux Id: seq7534</p> - </item> - <item> - <p>C macros in <c>debuglog.c</c> were not ANSI C compliant.</p> - <p>OwnId: OTP-4674</p> - </item> - <item> - <p>The <c>binary</c> option was not properly handled.</p> - <p>OwnId: OTP-4678</p> - </item> - <item> - <p>The <c>ssl:format_error/1</c> did not consider <c>inet</c> - error codes, nor did it have a catch all for unknown error - codes.</p> - <p>OwnId: OTP-4679</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Change of controlling process in not OTP compliant. </p> - <p>OwnId; OTP-4712</p> - </item> - <item> - <p>There is still no way to restrict the cipher sizes. </p> - <p>OwnId: OTP-4712</p> - </item> - <item> - <p>The <c>keep_alive</c> and <c>reuse_addr</c> options will be - added in a future release. </p> - <p>OwnId: OTP-4677</p> - </item> - <item> - <p>There is currently no way to restrict the SSL/TLS - protocol versions to use. In a future release this will be - supported as a configuration option, and as an option for - each connection as well. </p> - <p>OwnId: OTP-4711.</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.6</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>There was a synchronization error at closing, which could - result in that an SSL socket was removed prematurely, resulting - in that a user process referring to it received an unexpected - exit.</p> - <p>OwnId: OTP-4435 - <br></br> -Aux Id: seq7600</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL 2.2 . </p> - </section> - </section> - - <section> - <title>SSL 2.3.5</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Setting of the option `nodelay' caused the SSL port program - to dump core.</p> - <p>OwnId: OTP-4380 - <br></br> -Aux Id: -</p> - </item> - <item> - <p>Setting of the option '{active, once}' in <c>setopts</c> was - wrong, causing a correct socket message to be regarded as - erroneous. </p> - <p>OwnId: OTP-4380 - <br></br> -Aux Id: -</p> - </item> - <item> - <p>A self-signed peer certificate was always rejected with the - error `eselfsignedcert', irrespective of the `depth' value. </p> - <p>OwnId: OTP-4374 - <br></br> -Aux Id: seq7417</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL 2.2 . </p> - </section> - </section> - - <section> - <title>SSL 2.3.4</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>All TCP options allowed in gen_tcp, are now also allowed in - SSL, except the option <c>{reuseaddr, Boolean}</c>. A new - function <c>getopts</c> has been added to the SSL interface - module <c>ssl</c>. </p> - <p>OwnId: OTP-4305, OTP-4159</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.3</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The roles of the SSLeay and OpenSSL packages has been - clarified in the ssl(6) application manual page. Also - the URLs from which to download SSLeay has been updated.</p> - <p>OwnId: OTP-4002 - <br></br> -Aux Id: seq5269</p> - </item> - <item> - <p>A call to <c>ssl:listen(Port, Options)</c> with - <c>Options = []</c> resulted in the cryptic <c>{error, ebadf}</c> return value. The return value has been changed - to <c>{error, enooptions}</c>, and the behaviour has been - documented in the <c>listen/2</c> function.</p> - <p>OwnId: OTP-4016 - <br></br> -Aux Id: seq7006</p> - </item> - <item> - <p>Use of the option <c>{nodelay, boolean()}</c> crashed - the <c>ssl_server</c>.</p> - <p>OwnId: OTP-4070 - <br></br> -Aux Id:</p> - </item> - <item> - <p>A bug caused the Erlang distribution over ssl to fail. - This bug has now been fixed.</p> - <p>OwnId: OTP-4072 - <br></br> -Aux Id:</p> - </item> - <item> - <p>On Windows when the SSL port program encountered an - error code not anticipated it crashed. </p> - <p>OwnId: OTP-4132 - <br></br> -Aux Id:</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.2</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The <c>ssl:accept/1-2</c> function sometimes returned - <c>{error, {What, Where}}</c> instead of <c>{error, What}</c>, where <c>What</c> is an atom. </p> - <p>OwnId: OTP-3775 - <br></br> -Aux Id: seq4991</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Sometimes the SSL portprogram would loop in an accept - loop, without terminating even when the SSL application - was stopped.. </p> - <p>OwnId: OTP-3691</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3</title> - <p>Functions have been added to SSL to experimentally support - Erlang distribution. - </p> - </section> - - <section> - <title>SSL 2.2.1</title> - <p>The 2.2.1 version of SSL provides code replacement in runtime - by upgrading from, or downgrading to, versions 2.1 and 2.2. - </p> - </section> - - <section> - <title>SSL 2.2</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The restriction that only the creator of an SSL socket can - read from and write to the socket has been lifted.</p> - <p>OwnId: OTP-3301</p> - </item> - <item> - <p>The option <c>{packet, cdr}</c> for SSL sockets has been added, - which means that SSL sockets also supports CDR encoded packets.</p> - <p>OwnId: OTP-3302</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Setting of a CA certificate file with the <c>cacertfile</c> - option (in calls to <c>ssl:accept/1/2</c> or - <c>ssl:connect/3/4</c>) does not work due to weaknesses - in the SSLeay package. </p> - <p>A work-around is to set the OS environment variable - <c>SSL_CERT_FILE</c> before SSL is started. However, then - the CA certificate file will be global for all connections.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>When changing controlling process of an SSL socket, a - temporary process is started, which is not gen_server - compliant.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>Although there is a <c>cache</c> timeout option, it is - silently ignored.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>There is currently no way to restrict the cipher sizes.</p> - <p>OwnId: OTP-3146</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.1</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The set of possible error reasons has been extended to - contain diagnostics on erroneous certificates and failures - to verify certificates.</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>The maximum number of simultaneous SSL connections on - Windows has been increased from 31 to 127.</p> - <p>OwnId: OTP-3145</p> - </item> - </list> - </section> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>A dead-lock occurring when write queues are not empty has - been removed. </p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>Error reasons have been unified and changed.</p> - <p>(** POTENTIAL INCOMPATIBILITY **)</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>On Windows a check of the existence of the environment - variable <c>ERLSRV_SERVICE_NAME</c> has been added. If - that variable is defined, the port program of the SSL - application will not terminated when a user logs off.</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>An error in the setting of the <c>nodelay</c> option - has been corrected.</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>The confounded notions of verify mode and verify depth has - been corrected. The option <c>verifydepth</c> has been - removed, and the two separate options <c>verify</c> and - <c>depth</c> has been added.</p> - <p>(** POTENTIAL INCOMPATIBILITY **)</p> - <p>OwnId: OTP-3145</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Setting of a CA certificate file with the <c>cacertfile</c> - option (in calls to <c>ssl:accept/1/2</c> or - <c>ssl:connect/3/4</c>) does not work due to weaknesses - in the SSLeay package. </p> - <p>A work-around is to set the OS environment variable - <c>SSL_CERT_FILE</c> before SSL is started. However, then - the CA certificate file will be global for all connections.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>When changing controlling process of an SSL socket, a - temporary process is started, which is not gen_server - compliant.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>Although there is a <c>cache</c> timeout option, it is - silently ignored.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>There is currently no way to restrict the cipher sizes.</p> - <p>OwnId: OTP-3146</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.0</title> - <p>A complete new version of SSL with separate I/O channels - for all connections with non-blocking I/O multiplexing.</p> - </section> </chapter> diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 5098d26a3a..e45a4c774f 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -36,8 +36,8 @@ <list type="bulleted"> <item>ssl requires the crypto and public_key applications.</item> - <item>Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0, experimental - support for TLS-1.1 and TLS-1.2 is also available (no support for elliptic curve cipher suites yet).</item> + <item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0, + TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item> <item>For security reasons sslv2 is not supported.</item> <item>Ephemeral Diffie-Hellman cipher suites are supported but not Diffie Hellman Certificates cipher suites.</item> @@ -79,7 +79,9 @@ {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} | {cacertfile, path()} | |{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} | - {ssl_imp, ssl_imp()}| {reuse_sessions, boolean()} | {reuse_session, fun()} + {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} + {next_protocols_advertised, list(binary()} | + {client_preferred_next_protocols, binary(), client | server, list(binary())} </c></p> <p><c>transportoption() = {CallbackModule, DataTag, ClosedTag} @@ -301,8 +303,29 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | when possible. </item> + <tag>{client_preferred_next_protocols, Precedence:: server | client, ClientPrefs::[binary()]} + {client_preferred_next_protocols, Precedence:: server | client, ClientPrefs::[binary()] , Default :: binary()}}</tag> + + <item> <p>Indicates the client will try to perform Next Protocol + Negotiation.</p> + + <p>If precedence is server the negaotiated protocol will be the + first protocol that appears on the server advertised list that is + also on the clients preference list.</p> + + <p>If the precedence is client the negaotiated protocol will be the + first protocol that appears on the clients preference list that is + also on the server advertised list.</p> + + <p> If the client does not support any of the servers advertised + protocols or the server does not advertise any protocols the + client will fallback to the first protocol in its list or if a + default is supplied it will fallback to that instead. If the + server does not support next protocol renegotiation the + connection will be aborted if no default protocol is supplied.</p> + </item> </taglist> - </section> + </section> <section> <title>SSL OPTION DESCRIPTIONS - SERVER SIDE</title> @@ -353,6 +376,14 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | SuggestedSessionId is a binary(), PeerCert is a DER encoded certificate, Compression is an enumeration integer and CipherSuite is of type ciphersuite(). + </item> + + <tag>{next_protocols_advertised, Protocols :: list(binary())}</tag> + <item>The list of protocols to send to the client if the client indicates + it supports the Next Protocol extension. The client may select a protocol + that is not on this list. The list of protocols must not contain an empty + binary. If the server negotiates a Next Protocol it can be accessed + using <c>negotiated_next_protocol/1</c> method. </item> </taglist> @@ -766,8 +797,23 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | ssl application.</p> </desc> </func> + <func> + <name>negotiated_next_protocol(Socket) -> {ok, Protocol} | {error, next_protocol_not_negotiated}</name> + <fsummary>Returns the Next Protocol negotiated.</fsummary> + <type> + <v>Socket = sslsocket()</v> + <v>Protocol = binary()</v> + </type> + <desc> + <p> + Returns the Next Protocol negotiated. + </p> + </desc> + </func> + + </funcs> - + <section> <title>SEE ALSO</title> <p><seealso marker="kernel:inet">inet(3) </seealso> and diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml index 2ba6f48611..84ad483617 100644 --- a/lib/ssl/doc/src/ssl_app.xml +++ b/lib/ssl/doc/src/ssl_app.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE appref SYSTEM "appref.dtd"> <appref> <header> <copyright> - <year>1999</year><year>2010</year> + <year>1999</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,7 +29,17 @@ sockets.</appsummary> <section> - <title>Environment</title> + <title>DEPENDENCIES</title> + <p>The ssl application uses the Erlang applications public_key and + crypto to handle public keys and encryption, hence these + applications needs to be loaded for the ssl application to work. In + an embedded environment that means they need to be started with + application:start/[1,2] before the ssl application is started. + </p> + </section> + + <section> + <title>ENVIRONMENT</title> <p>The following application environment configuration parameters are defined for the SSL application. Refer to application(3) for more information about configuration parameters. diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml index 17268a634d..f540dc999b 100644 --- a/lib/ssl/doc/src/ssl_protocol.xml +++ b/lib/ssl/doc/src/ssl_protocol.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2011</year> + <year>2003</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -25,9 +25,8 @@ <file>ssl_protocol.xml</file> </header> - <p>The erlang SSL application currently supports SSL 3.0 and TLS 1.0 - RFC 2246, and will in the future also support later versions of TLS. - SSL 2.0 is not supported. + <p>The erlang SSL application currently implements the protocol SSL/TLS + for currently supported versions see <seealso marker="ssl">ssl(3)</seealso> </p> <p>By default erlang SSL is run over the TCP/IP protocol even diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index c5c5bf593a..043645be41 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -108,10 +108,10 @@ clean: rm -f errs core *~ $(APP_TARGET): $(APP_SRC) ../vsn.mk - sed -e 's;%VSN%;$(VSN);' $< > $@ + $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk - sed -e 's;%VSN%;$(VSN);' $< > $@ + $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ docs: @@ -130,3 +130,23 @@ release_spec: opt release_docs_spec: +# ---------------------------------------------------- +# Dependencies +# ---------------------------------------------------- +$(EBIN)/inet_tls_dist.$(EMULATOR): ../../kernel/include/net_address.hrl ../../kernel/include/dist.hrl ../../kernel/include/dist_util.hrl +$(EBIN)/ssl.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl +$(EBIN)/ssl_alert.$(EMULATOR): ssl_alert.hrl ssl_record.hrl +$(EBIN)/ssl_certificate.$(EMULATOR): ssl_internal.hrl ssl_alert.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl +$(EBIN)/ssl_certificate_db.$(EMULATOR): ssl_internal.hrl ../../public_key/include/public_key.hrl ../../kernel/include/file.hrl +$(EBIN)/ssl_cipher.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl +$(EBIN)/ssl_connection.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl +$(EBIN)/ssl_handshake.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl +$(EBIN)/ssl_manager.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl ../../kernel/include/file.hrl +$(EBIN)/ssl_record.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl +$(EBIN)/ssl_session.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl +$(EBIN)/ssl_session_cache.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl +$(EBIN)/ssl_session_cache_api.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl +$(EBIN)/ssl_ssl3.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl +$(EBIN)/ssl_tls1.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl + + diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 9b1227fa7f..76e14860ec 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,24 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ - {"5.1.1", [{restart_application, ssl}] - }, - {"5.1", [ - {load_module, ssl_connection, soft_purge, soft_purge, []} - ] - }, + {<<"5.1\\*">>, [{restart_application, ssl}]}, {<<"5.0\\*">>, [{restart_application, ssl}]}, {<<"4\\.*">>, [{restart_application, ssl}]}, {<<"3\\.*">>, [{restart_application, ssl}]} ], [ - {"5.1.1", [{restart_application, ssl}] - }, - {"5.1", [ - {load_module, ssl_connection, soft_purge, soft_purge, []} - ] - }, - {"5.1", [{restart_application, ssl}]}, + {<<"5.1\\*">>, [{restart_application, ssl}]}, {<<"5.0\\*">>, [{restart_application, ssl}]}, {<<"4\\.*">>, [{restart_application, ssl}]}, {<<"3\\.*">>, [{restart_application, ssl}]} diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 66ceb2a591..09f2819ca8 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -28,16 +28,15 @@ cipher_suites/0, cipher_suites/1, suite_definition/1, close/1, shutdown/2, connect/3, connect/2, connect/4, connection_info/1, - controlling_process/2, listen/2, pid/1, peername/1, peercert/1, + controlling_process/2, listen/2, peername/1, peercert/1, recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1, versions/0, session_info/1, format_error/1, - renegotiate/1, prf/5, clear_pem_cache/0, random_bytes/1]). - --deprecated({pid, 1, next_major_release}). + renegotiate/1, prf/5, clear_pem_cache/0, random_bytes/1, negotiated_next_protocol/1]). -include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). +-include("ssl_handshake.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -67,7 +66,9 @@ {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} | {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | - {reuse_session, fun()} | {hibernate_after, integer()|undefined}. + {reuse_session, fun()} | {hibernate_after, integer()|undefined} | + {next_protocols_advertised, list(binary())} | + {client_preferred_next_protocols, binary(), client | server, list(binary())}. -type verify_type() :: verify_none | verify_peer. -type path() :: string(). @@ -163,7 +164,7 @@ listen(Port, Options0) -> #config{cb={CbModule, _, _, _},inet_user=Options} = Config, case CbModule:listen(Port, Options) of {ok, ListenSocket} -> - {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}}; + {ok, #sslsocket{pid = {ListenSocket, Config}}}; Err = {error, _} -> Err end @@ -243,18 +244,20 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> %% %% Description: Close an ssl connection %%-------------------------------------------------------------------- +close(#sslsocket{pid = Pid}) when is_pid(Pid) -> + ssl_connection:close(Pid); close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}) -> - CbMod:close(ListenSocket); -close(#sslsocket{pid = Pid}) -> - ssl_connection:close(Pid). + CbMod:close(ListenSocket). %%-------------------------------------------------------------------- -spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}. %% %% Description: Sends data over the ssl connection %%-------------------------------------------------------------------- -send(#sslsocket{pid = Pid}, Data) -> - ssl_connection:send(Pid, Data). +send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) -> + ssl_connection:send(Pid, Data); +send(#sslsocket{pid = {ListenSocket, #config{cb={CbModule, _, _, _}}}}, Data) -> + CbModule:send(ListenSocket, Data). %% {error,enotconn} %%-------------------------------------------------------------------- -spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}. @@ -264,8 +267,10 @@ send(#sslsocket{pid = Pid}, Data) -> %%-------------------------------------------------------------------- recv(Socket, Length) -> recv(Socket, Length, infinity). -recv(#sslsocket{pid = Pid, fd = new_ssl}, Length, Timeout) -> - ssl_connection:recv(Pid, Length, Timeout). +recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) -> + ssl_connection:recv(Pid, Length, Timeout); +recv(#sslsocket{pid = {Listen, #config{cb={CbModule, _, _, _}}}}, _,_) when is_port(Listen)-> + CbModule:recv(Listen, 0). %% {error,enotconn} %%-------------------------------------------------------------------- -spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}. @@ -273,8 +278,12 @@ recv(#sslsocket{pid = Pid, fd = new_ssl}, Length, Timeout) -> %% Description: Changes process that receives the messages when active = true %% or once. %%-------------------------------------------------------------------- -controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid) -> - ssl_connection:new_user(Pid, NewOwner). +controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) -> + ssl_connection:new_user(Pid, NewOwner); +controlling_process(#sslsocket{pid = {Listen, + #config{cb={CbModule, _, _, _}}}}, NewOwner) when is_port(Listen), + is_pid(NewOwner) -> + CbModule:controlling_process(Listen, NewOwner). %%-------------------------------------------------------------------- -spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} | @@ -282,29 +291,35 @@ controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid) -> %% %% Description: Returns ssl protocol and cipher used for the connection %%-------------------------------------------------------------------- -connection_info(#sslsocket{pid = Pid}) -> - ssl_connection:info(Pid). +connection_info(#sslsocket{pid = Pid}) when is_pid(Pid) -> + ssl_connection:info(Pid); +connection_info(#sslsocket{pid = {Listen, _}}) when is_port(Listen) -> + {error, enotconn}. %%-------------------------------------------------------------------- -spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}. %% %% Description: same as inet:peername/1. %%-------------------------------------------------------------------- -peername(#sslsocket{pid = Pid}) -> - ssl_connection:peername(Pid). +peername(#sslsocket{pid = Pid, fd = Socket}) when is_pid(Pid)-> + inet:peername(Socket); +peername(#sslsocket{pid = {ListenSocket, _}}) -> + inet:peername(ListenSocket). %% Will return {error, enotconn} %%-------------------------------------------------------------------- -spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}. %% %% Description: Returns the peercert. %%-------------------------------------------------------------------- -peercert(#sslsocket{pid = Pid}) -> +peercert(#sslsocket{pid = Pid}) when is_pid(Pid) -> case ssl_connection:peer_certificate(Pid) of {ok, undefined} -> {error, no_peercert}; Result -> Result - end. + end; +peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) -> + {error, enotconn}. %%-------------------------------------------------------------------- -spec suite_definition(cipher_suite()) -> erl_cipher_suite(). @@ -316,6 +331,14 @@ suite_definition(S) -> {KeyExchange, Cipher, Hash}. %%-------------------------------------------------------------------- +-spec negotiated_next_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}. +%% +%% Description: Returns the next protocol that has been negotiated. If no +%% protocol has been negotiated will return {error, next_protocol_not_negotiated} +%%-------------------------------------------------------------------- +negotiated_next_protocol(#sslsocket{pid = Pid}) -> + ssl_connection:negotiated_next_protocol(Pid). + -spec cipher_suites() -> [erl_cipher_suite()]. -spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()]. @@ -386,8 +409,9 @@ setopts(#sslsocket{}, Options) -> %% %% Description: Same as gen_tcp:shutdown/2 %%-------------------------------------------------------------------- -shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}, How) -> - CbMod:shutdown(ListenSocket, How); +shutdown(#sslsocket{pid = {Listen, #config{cb={CbMod,_, _, _}}}}, + How) when is_port(Listen) -> + CbMod:shutdown(Listen, How); shutdown(#sslsocket{pid = Pid}, How) -> ssl_connection:shutdown(Pid, How). @@ -396,11 +420,11 @@ shutdown(#sslsocket{pid = Pid}, How) -> %% %% Description: Same as inet:sockname/1 %%-------------------------------------------------------------------- -sockname(#sslsocket{pid = {ListenSocket, _}}) -> - inet:sockname(ListenSocket); +sockname(#sslsocket{pid = {Listen, _}}) when is_port(Listen) -> + inet:sockname(Listen); -sockname(#sslsocket{pid = Pid}) -> - ssl_connection:sockname(Pid). +sockname(#sslsocket{pid = Pid, fd = Socket}) when is_pid(Pid) -> + inet:sockname(Socket). %%--------------------------------------------------------------- -spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}. @@ -408,12 +432,14 @@ sockname(#sslsocket{pid = Pid}) -> %% Description: Returns list of session info currently [{session_id, session_id(), %% {cipher_suite, cipher_suite()}] %%-------------------------------------------------------------------- -session_info(#sslsocket{pid = Pid, fd = new_ssl}) -> - ssl_connection:session_info(Pid). +session_info(#sslsocket{pid = Pid}) when is_pid(Pid) -> + ssl_connection:session_info(Pid); +session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) -> + {error, enotconn}. %%--------------------------------------------------------------- -spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} | - {available, [tls_atom_version()]}]. + {available, [tls_atom_version()]}]. %% %% Description: Returns a list of relevant versions. %%-------------------------------------------------------------------- @@ -429,8 +455,10 @@ versions() -> %% %% Description: Initiates a renegotiation. %%-------------------------------------------------------------------- -renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) -> - ssl_connection:renegotiation(Pid). +renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) -> + ssl_connection:renegotiation(Pid); +renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) -> + {error, enotconn}. %%-------------------------------------------------------------------- -spec prf(#sslsocket{}, binary() | 'master_secret', binary(), @@ -439,10 +467,11 @@ renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) -> %% %% Description: use a ssl sessions TLS PRF to generate key material %%-------------------------------------------------------------------- -prf(#sslsocket{pid = Pid, fd = new_ssl}, - Secret, Label, Seed, WantedLength) -> - ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength). - +prf(#sslsocket{pid = Pid}, + Secret, Label, Seed, WantedLength) when is_pid(Pid) -> + ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength); +prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) -> + {error, enotconn}. %%-------------------------------------------------------------------- -spec clear_pem_cache() -> ok. @@ -596,7 +625,9 @@ handle_options(Opts0, _Role) -> renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT), debug = handle_option(debug, Opts, []), hibernate_after = handle_option(hibernate_after, Opts, undefined), - erl_dist = handle_option(erl_dist, Opts, false) + erl_dist = handle_option(erl_dist, Opts, false), + next_protocols_advertised = handle_option(next_protocols_advertised, Opts, undefined), + next_protocol_selector = make_next_protocol_selector(handle_option(client_preferred_next_protocols, Opts, undefined)) }, CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}), @@ -605,7 +636,8 @@ handle_options(Opts0, _Role) -> depth, cert, certfile, key, keyfile, password, cacerts, cacertfile, dh, dhfile, ciphers, debug, reuse_session, reuse_sessions, ssl_imp, - cb_info, renegotiate_at, secure_renegotiate, hibernate_after, erl_dist], + cb_info, renegotiate_at, secure_renegotiate, hibernate_after, erl_dist, next_protocols_advertised, + client_preferred_next_protocols], SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) @@ -730,12 +762,64 @@ validate_option(hibernate_after, undefined) -> undefined; validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 -> Value; -validate_option(erl_dist,Value) when Value == true; +validate_option(erl_dist,Value) when Value == true; Value == false -> Value; +validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols} = Value) + when is_list(PreferredProtocols) -> + case ssl_record:highest_protocol_version([]) of + {3,0} -> + throw({error, {eoptions, {not_supported_in_sslv3, {Opt, Value}}}}); + _ -> + validate_binary_list(client_preferred_next_protocols, PreferredProtocols), + validate_npn_ordering(Precedence), + {Precedence, PreferredProtocols, ?NO_PROTOCOL} + end; +validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols, Default} = Value) + when is_list(PreferredProtocols), is_binary(Default), + byte_size(Default) > 0, byte_size(Default) < 256 -> + case ssl_record:highest_protocol_version([]) of + {3,0} -> + throw({error, {eoptions, {not_supported_in_sslv3, {Opt, Value}}}}); + _ -> + validate_binary_list(client_preferred_next_protocols, PreferredProtocols), + validate_npn_ordering(Precedence), + Value + end; + +validate_option(client_preferred_next_protocols, undefined) -> + undefined; +validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) -> + case ssl_record:highest_protocol_version([]) of + {3,0} -> + throw({error, {eoptions, {not_supported_in_sslv3, {Opt, Value}}}}); + _ -> + validate_binary_list(next_protocols_advertised, Value), + Value + end; + +validate_option(next_protocols_advertised, undefined) -> + undefined; validate_option(Opt, Value) -> throw({error, {eoptions, {Opt, Value}}}). - + +validate_npn_ordering(client) -> + ok; +validate_npn_ordering(server) -> + ok; +validate_npn_ordering(Value) -> + throw({error, {eoptions, {client_preferred_next_protocols, {invalid_precedence, Value}}}}). + +validate_binary_list(Opt, List) -> + lists:foreach( + fun(Bin) when is_binary(Bin), + byte_size(Bin) > 0, + byte_size(Bin) < 256 -> + ok; + (Bin) -> + throw({error, {eoptions, {Opt, {invalid_protocol, Bin}}}}) + end, List). + validate_versions([], Versions) -> Versions; validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2'; @@ -841,14 +925,31 @@ cipher_suites(Version, Ciphers0) -> no_format(Error) -> lists:flatten(io_lib:format("No format string for error: \"~p\" available.", [Error])). - -%% Only used to remove exit messages from old ssl -%% First is a nonsense clause to provide some -%% backward compatibility for orber that uses this -%% function in a none recommended way, but will -%% work correctly if a valid pid is returned. -%% Deprcated to be removed in r16 -pid(#sslsocket{fd = new_ssl}) -> - whereis(ssl_connection_sup); -pid(#sslsocket{pid = Pid}) -> - Pid. + +detect(_Pred, []) -> + undefined; +detect(Pred, [H|T]) -> + case Pred(H) of + true -> + H; + _ -> + detect(Pred, T) + end. + +make_next_protocol_selector(undefined) -> + undefined; +make_next_protocol_selector({client, AllProtocols, DefaultProtocol}) -> + fun(AdvertisedProtocols) -> + case detect(fun(PreferredProtocol) -> lists:member(PreferredProtocol, AdvertisedProtocols) end, AllProtocols) of + undefined -> DefaultProtocol; + PreferredProtocol -> PreferredProtocol + end + end; + +make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) -> + fun(AdvertisedProtocols) -> + case detect(fun(PreferredProtocol) -> lists:member(PreferredProtocol, AllProtocols) end, AdvertisedProtocols) of + undefined -> DefaultProtocol; + PreferredProtocol -> PreferredProtocol + end + end. diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index 222b3f1ad7..f94a1136a0 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -36,8 +36,7 @@ %% Internal application API %%==================================================================== %%-------------------------------------------------------------------- --spec reason_code(#alert{}, client | server) -> closed | esslconnect | - esslaccept | string(). +-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}. %% %% Description: Returns the error reason that will be returned to the %% user. @@ -45,12 +44,8 @@ reason_code(#alert{description = ?CLOSE_NOTIFY}, _) -> closed; -reason_code(#alert{description = ?HANDSHAKE_FAILURE}, client) -> - esslconnect; -reason_code(#alert{description = ?HANDSHAKE_FAILURE}, server) -> - esslaccept; reason_code(#alert{description = Description}, _) -> - description_txt(Description). + {essl, description_txt(Description)}. %%-------------------------------------------------------------------- -spec alert_txt(#alert{}) -> string(). diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index 67d00f0da7..ff36b5ee26 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,10 +18,11 @@ %% %%---------------------------------------------------------------------- -%% Purpose: Storage for trused certificats +%% Purpose: Storage for trusted certificates %%---------------------------------------------------------------------- -module(ssl_certificate_db). + -include("ssl_internal.hrl"). -include_lib("public_key/include/public_key.hrl"). -include_lib("kernel/include/file.hrl"). @@ -37,7 +38,7 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec create() -> [db_handle()]. +-spec create() -> [db_handle(),...]. %% %% Description: Creates a new certificate db. %% Note: lookup_trusted_cert/4 may be called from any process but only @@ -54,7 +55,7 @@ create() -> ]. %%-------------------------------------------------------------------- --spec remove([db_handle()]) -> term(). +-spec remove([db_handle()]) -> ok. %% %% Description: Removes database db %%-------------------------------------------------------------------- @@ -114,8 +115,8 @@ add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) -> new_trusted_cert_entry({MD5, File}, Db) end. %%-------------------------------------------------------------------- --spec cache_pem_file({binary(), binary()}, [db_handle()]) -> term(). --spec cache_pem_file(reference(), {binary(), binary()}, [db_handle()]) -> term(). +-spec cache_pem_file({binary(), binary()}, [db_handle()]) -> {ok, term()}. +-spec cache_pem_file(reference(), {binary(), binary()}, [db_handle()]) -> {ok, term()}. %% %% Description: Cache file as binary in DB %%-------------------------------------------------------------------- @@ -131,19 +132,25 @@ cache_pem_file(Ref, {MD5, File}, [_CertsDb, _RefDb, PemChache]) -> insert(MD5, {Content, Ref}, PemChache), {ok, Content}. +%%-------------------------------------------------------------------- +-spec remove_trusted_certs(reference(), db_handle()) -> ok. +%% +%% Description: Removes all trusted certificates refernced by <Ref>. +%%-------------------------------------------------------------------- remove_trusted_certs(Ref, CertsDb) -> remove_certs(Ref, CertsDb). %%-------------------------------------------------------------------- --spec remove(term(), db_handle()) -> term(). +-spec remove(term(), db_handle()) -> ok. %% %% Description: Removes an element in a <Db>. %%-------------------------------------------------------------------- remove(Key, Db) -> - _ = ets:delete(Db, Key). + ets:delete(Db, Key), + ok. %%-------------------------------------------------------------------- --spec lookup(term(), db_handle()) -> term() | undefined. +-spec lookup(term(), db_handle()) -> [term()] | undefined. %% %% Description: Looks up an element in a <Db>. %%-------------------------------------------------------------------- @@ -158,7 +165,7 @@ lookup(Key, Db) -> [Pick(Data) || Data <- Contents] end. %%-------------------------------------------------------------------- --spec foldl(fun(), term(), db_handle()) -> term(). +-spec foldl(fun((_,_) -> term()), term(), db_handle()) -> term(). %% %% Description: Calls Fun(Elem, AccIn) on successive elements of the %% cache, starting with AccIn == Acc0. Fun/2 must return a new @@ -178,12 +185,13 @@ ref_count(Key, Db, N) -> ets:update_counter(Db,Key,N). %%-------------------------------------------------------------------- --spec clear(db_handle()) -> term(). +-spec clear(db_handle()) -> ok. %% %% Description: Clears the cache %%-------------------------------------------------------------------- clear(Db) -> - ets:delete_all_objects(Db). + true = ets:delete_all_objects(Db), + ok. %%-------------------------------------------------------------------- -spec db_size(db_handle()) -> integer(). @@ -194,30 +202,35 @@ db_size(Db) -> ets:info(Db, size). %%-------------------------------------------------------------------- -%%-spec insert(Key::term(), Data::term(), Db::db_handle()) -> no_return(). +-spec insert(Key::term(), Data::term(), Db::db_handle()) -> ok. %% %% Description: Inserts data into <Db> %%-------------------------------------------------------------------- insert(Key, Data, Db) -> - true = ets:insert(Db, {Key, Data}). + true = ets:insert(Db, {Key, Data}), + ok. %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- update_counter(Key, Count, Db) -> - true = ets:insert(Db, {Key, Count}). + true = ets:insert(Db, {Key, Count}), + ok. remove_certs(Ref, CertsDb) -> - ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}). + true = ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}), + ok. add_certs_from_der(DerList, Ref, CertsDb) -> Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, - [Add(Cert) || Cert <- DerList]. + [Add(Cert) || Cert <- DerList], + ok. add_certs_from_pem(PemEntries, Ref, CertsDb) -> Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, - [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries]. - + [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries], + ok. + add_certs(Cert, Ref, CertsDb) -> try ErlCert = public_key:pkix_decode_cert(Cert, otp), TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index d4784604fd..e5a6181a88 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -40,8 +40,7 @@ -export([send/2, recv/3, connect/7, ssl_accept/6, handshake/2, socket_control/3, close/1, shutdown/2, new_user/2, get_opts/2, set_opts/2, info/1, session_info/1, - peer_certificate/1, sockname/1, peername/1, renegotiation/1, - prf/5]). + peer_certificate/1, renegotiation/1, negotiated_next_protocol/1, prf/5]). %% Called by ssl_connection_sup -export([start_link/7]). @@ -93,7 +92,9 @@ timer, % start_or_recv_timer send_queue, % queue() terminated = false, % - allow_renegotiate = true + allow_renegotiate = true, + expecting_next_protocol_negotiation = false :: boolean(), + next_protocol = undefined :: undefined | binary() }). -define(DEFAULT_DIFFIE_HELLMAN_PARAMS, @@ -180,7 +181,7 @@ handshake(#sslsocket{pid = Pid}, Timeout) -> socket_control(Socket, Pid, CbModule) -> case CbModule:controlling_process(Socket, Pid) of ok -> - {ok, sslsocket(Pid)}; + {ok, sslsocket(Pid, Socket)}; {error, Reason} -> {error, Reason} end. @@ -214,20 +215,15 @@ shutdown(ConnectionPid, How) -> %%-------------------------------------------------------------------- new_user(ConnectionPid, User) -> sync_send_all_state_event(ConnectionPid, {new_user, User}). + %%-------------------------------------------------------------------- --spec sockname(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}. -%% -%% Description: Same as inet:sockname/1 -%%-------------------------------------------------------------------- -sockname(ConnectionPid) -> - sync_send_all_state_event(ConnectionPid, sockname). -%%-------------------------------------------------------------------- --spec peername(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}. +-spec negotiated_next_protocol(pid()) -> {ok, binary()} | {error, reason()}. %% -%% Description: Same as inet:peername/1 +%% Description: Returns the negotiated protocol %%-------------------------------------------------------------------- -peername(ConnectionPid) -> - sync_send_all_state_event(ConnectionPid, peername). +negotiated_next_protocol(ConnectionPid) -> + sync_send_all_state_event(ConnectionPid, negotiated_next_protocol). + %%-------------------------------------------------------------------- -spec get_opts(pid(), list()) -> {ok, list()} | {error, reason()}. %% @@ -375,16 +371,28 @@ hello(#server_hello{cipher_suite = CipherSuite, renegotiation = {Renegotiation, _}, ssl_options = SslOptions} = State0) -> case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of - {Version, NewId, ConnectionStates} -> + #alert{} = Alert -> + handle_own_alert(Alert, ReqVersion, hello, State0); + {Version, NewId, ConnectionStates, NextProtocol} -> {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite), - + PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), + + NewNextProtocol = case NextProtocol of + undefined -> + State0#state.next_protocol; + _ -> + NextProtocol + end, + State = State0#state{key_algorithm = KeyAlgorithm, hashsign_algorithm = default_hashsign(Version, KeyAlgorithm), negotiated_version = Version, connection_states = ConnectionStates, - premaster_secret = PremasterSecret}, + premaster_secret = PremasterSecret, + expecting_next_protocol_negotiation = NextProtocol =/= undefined, + next_protocol = NewNextProtocol}, case ssl_session:is_new(OldId, NewId) of true -> @@ -392,13 +400,10 @@ hello(#server_hello{cipher_suite = CipherSuite, State#state{connection_states = ConnectionStates}); false -> handle_resumed_session(NewId, State#state{connection_states = ConnectionStates}) - end; - #alert{} = Alert -> - handle_own_alert(Alert, ReqVersion, hello, State0), - {stop, {shutdown, own_alert}, State0} + end end; -hello(Hello = #client_hello{client_version = ClientVersion}, +hello(Hello = #client_hello{client_version = ClientVersion}, State = #state{connection_states = ConnectionStates0, port = Port, session = #session{own_certificate = Cert} = Session0, renegotiation = {Renegotiation, _}, @@ -407,8 +412,8 @@ hello(Hello = #client_hello{client_version = ClientVersion}, ssl_options = SslOpts}) -> case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) of - {Version, {Type, Session}, ConnectionStates} -> - do_server_hello(Type, State#state{connection_states = + {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} -> + do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states = ConnectionStates, negotiated_version = Version, session = Session}); @@ -584,6 +589,7 @@ certify(#client_key_exchange{exchange_keys = Keys}, handle_own_alert(Alert, Version, certify, State) end; + certify(timeout, State) -> { next_state, certify, State, hibernate }; @@ -650,6 +656,12 @@ cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashS handle_own_alert(Alert, Version, cipher, State0) end; +% client must send a next protocol message if we are expecting it +cipher(#finished{}, #state{role = server, expecting_next_protocol_negotiation = true, + next_protocol = undefined, negotiated_version = Version} = State0) -> + handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, cipher, State0), + {stop, normal, State0}; + cipher(#finished{verify_data = Data} = Finished, #state{negotiated_version = Version, host = Host, @@ -670,6 +682,13 @@ cipher(#finished{verify_data = Data} = Finished, handle_own_alert(Alert, Version, cipher, State) end; +% only allowed to send next_protocol message after change cipher spec +% & before finished message and it is not allowed during renegotiation +cipher(#next_protocol{selected_protocol = SelectedProtocol}, + #state{role = server, expecting_next_protocol_negotiation = true} = State0) -> + {Record, State} = next_record(State0#state{next_protocol = SelectedProtocol}), + next_state(cipher, cipher, Record, State); + cipher(timeout, State) -> { next_state, cipher, State, hibernate }; @@ -833,15 +852,10 @@ handle_sync_event({get_opts, OptTags}, _From, StateName, OptsReply = get_socket_opts(Socket, OptTags, SockOpts, []), {reply, OptsReply, StateName, State, get_timeout(State)}; -handle_sync_event(sockname, _From, StateName, - #state{socket = Socket} = State) -> - SockNameReply = inet:sockname(Socket), - {reply, SockNameReply, StateName, State, get_timeout(State)}; - -handle_sync_event(peername, _From, StateName, - #state{socket = Socket} = State) -> - PeerNameReply = inet:peername(Socket), - {reply, PeerNameReply, StateName, State, get_timeout(State)}; +handle_sync_event(negotiated_next_protocol, _From, StateName, #state{next_protocol = undefined} = State) -> + {reply, {error, next_protocol_not_negotiated}, StateName, State, get_timeout(State)}; +handle_sync_event(negotiated_next_protocol, _From, StateName, #state{next_protocol = NextProtocol} = State) -> + {reply, {ok, NextProtocol}, StateName, State, get_timeout(State)}; handle_sync_event({set_opts, Opts0}, _From, StateName, #state{socket_options = Opts1, @@ -970,7 +984,7 @@ handle_info({CloseTag, Socket}, StateName, handle_info({ErrorTag, Socket, econnaborted}, StateName, #state{socket = Socket, start_or_recv_from = StartFrom, role = Role, error_tag = ErrorTag} = State) when StateName =/= connection -> - alert_user(StartFrom, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role), + alert_user(Socket, StartFrom, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role), {stop, normal, State}; handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket, @@ -1120,7 +1134,7 @@ init_certificates(#ssl_options{cacerts = CaCerts, {ok, _, _, _, _, _} = ssl_manager:connection_init(Certs, Role) catch Error:Reason -> - handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile, + handle_file_error(?LINE, Error, Reason, CACertFile, {ecacertfile, Reason}, erlang:get_stacktrace()) end, init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, Role). @@ -1142,7 +1156,7 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert} catch Error:Reason -> - handle_file_error(?LINE, Error, Reason, CertFile, ecertfile, + handle_file_error(?LINE, Error, Reason, CertFile, {ecertfile, Reason}, erlang:get_stacktrace()) end; init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, _, _) -> @@ -1161,7 +1175,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) -> private_key(public_key:pem_entry_decode(PemEntry, Password)) catch Error:Reason -> - handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile, + handle_file_error(?LINE, Error, Reason, KeyFile, {ekeyfile, Reason}, erlang:get_stacktrace()) end; @@ -1219,7 +1233,7 @@ init_diffie_hellman(DbHandle,_, DHParamFile, server) -> catch Error:Reason -> handle_file_error(?LINE, Error, Reason, - DHParamFile, edhfile, erlang:get_stacktrace()) + DHParamFile, {edhfile, Reason}, erlang:get_stacktrace()) end. sync_send_all_state_event(FsmPid, Event) -> @@ -1291,17 +1305,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, verify_client_cert(#state{client_certificate_requested = false} = State) -> State. -do_server_hello(Type, #state{negotiated_version = Version, - session = #session{session_id = SessId}, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}} - = State0) when is_atom(Type) -> +do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version, + session = #session{session_id = SessId}, + connection_states = ConnectionStates0, + renegotiation = {Renegotiation, _}} + = State0) when is_atom(Type) -> ServerHello = ssl_handshake:server_hello(SessId, Version, - ConnectionStates0, Renegotiation), - State = server_hello(ServerHello, State0), - + ConnectionStates0, Renegotiation, NextProtocolsToSend), + State = server_hello(ServerHello, + State0#state{expecting_next_protocol_negotiation = + NextProtocolsToSend =/= undefined}), case Type of new -> new_server_hello(ServerHello, State); @@ -1551,12 +1566,33 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_none}} = State. finalize_handshake(State, StateName) -> - ConnectionStates0 = cipher_protocol(State), + ConnectionStates0 = cipher_protocol(State), + ConnectionStates = ssl_record:activate_pending_connection_state(ConnectionStates0, write), - finished(State#state{connection_states = ConnectionStates}, StateName). - + + State1 = State#state{connection_states = ConnectionStates}, + State2 = next_protocol(State1), + finished(State2, StateName). + +next_protocol(#state{role = server} = State) -> + State; +next_protocol(#state{next_protocol = undefined} = State) -> + State; +next_protocol(#state{expecting_next_protocol_negotiation = false} = State) -> + State; +next_protocol(#state{transport_cb = Transport, socket = Socket, + negotiated_version = Version, + next_protocol = NextProtocol, + connection_states = ConnectionStates0, + tls_handshake_history = Handshake0} = State) -> + NextProtocolMessage = ssl_handshake:next_protocol(NextProtocol), + {BinMsg, ConnectionStates, Handshake} = encode_handshake(NextProtocolMessage, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}. + cipher_protocol(#state{connection_states = ConnectionStates0, socket = Socket, negotiated_version = Version, @@ -1591,78 +1627,49 @@ save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbrev save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) -> ssl_record:set_server_verify_data(current_write, Data, ConnectionStates). -handle_server_key(#server_key_exchange{params = - #server_dh_params{dh_p = P, - dh_g = G, - dh_y = ServerPublicDhKey}, - signed_params = <<>>}, - #state{key_algorithm = dh_anon} = State) -> - dh_master_secret(P, G, ServerPublicDhKey, undefined, State); - -handle_server_key( - #server_key_exchange{params = - #server_dh_params{dh_p = P, - dh_g = G, - dh_y = ServerPublicDhKey}, - signed_params = Signed, - hashsign = HashSign}, - #state{negotiated_version = Version, - public_key_info = PubKeyInfo, - connection_states = ConnectionStates} = State) -> - - PLen = size(P), - GLen = size(G), - YLen = size(ServerPublicDhKey), - HashAlgo = connection_hash_algo(HashSign, State), +handle_server_key(#server_key_exchange{exchange_keys = Keys}, + #state{key_algorithm = KeyAlg, + negotiated_version = Version} = State) -> + Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version), + HashSign = connection_hashsign(Params#server_key_params.hashsign, State), + case HashSign of + {_, anon} -> + server_master_secret(Params#server_key_params.params, State); + _ -> + verify_server_key(Params, HashSign, State) + end. - ConnectionState = +verify_server_key(#server_key_params{params = Params, + params_bin = EncParams, + signature = Signature}, + HashSign = {HashAlgo, _}, + #state{negotiated_version = Version, + public_key_info = PubKeyInfo, + connection_states = ConnectionStates} = State) -> + ConnectionState = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, Hash = ssl_handshake:server_key_exchange_hash(HashAlgo, - <<ClientRandom/binary, - ServerRandom/binary, - ?UINT16(PLen), P/binary, - ?UINT16(GLen), G/binary, - ?UINT16(YLen), - ServerPublicDhKey/binary>>), - - case verify_dh_params(Version, Signed, Hash, HashAlgo, PubKeyInfo) of + <<ClientRandom/binary, + ServerRandom/binary, + EncParams/binary>>), + case ssl_handshake:verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo) of true -> - dh_master_secret(P, G, ServerPublicDhKey, undefined, State); + server_master_secret(Params, State); false -> ?ALERT_REC(?FATAL, ?DECRYPT_ERROR) end. -verify_dh_params({3, Minor}, Signed, Hashes, HashAlgo, {?rsaEncryption, PubKey, _PubKeyParams}) - when Minor >= 3 -> - public_key:verify({digest, Hashes}, HashAlgo, Signed, PubKey); -verify_dh_params(_Version, Signed, Hashes, _HashAlgo, {?rsaEncryption, PubKey, _PubKeyParams}) -> - case public_key:decrypt_public(Signed, PubKey, - [{rsa_pad, rsa_pkcs1_padding}]) of - Hashes -> - true; - _ -> - false - end; -verify_dh_params(_Version, Signed, Hash, HashAlgo, {?'id-dsa', PublicKey, PublicKeyParams}) -> - public_key:verify({digest, Hash}, HashAlgo, Signed, {PublicKey, PublicKeyParams}). - -dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> - PMpint = mpint_binary(Prime), - GMpint = mpint_binary(Base), - Keys = {_, PrivateDhKey} = - crypto:dh_generate_key([PMpint,GMpint]), - dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); +server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}, + State) -> + dh_master_secret(P, G, ServerPublicDhKey, undefined, State). -dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, - #state{session = Session, - negotiated_version = Version, role = Role, - connection_states = ConnectionStates0} = State) -> - PremasterSecret = - crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, - [PMpint, GMpint]), +master_from_premaster_secret(PremasterSecret, + #state{session = Session, + negotiated_version = Version, role = Role, + connection_states = ConnectionStates0} = State) -> case ssl_handshake:master_secret(Version, PremasterSecret, ConnectionStates0, Role) of {MasterSecret, ConnectionStates} -> @@ -1674,6 +1681,19 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, Alert end. +dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> + PMpint = mpint_binary(Prime), + GMpint = mpint_binary(Base), + Keys = {_, PrivateDhKey} = + crypto:dh_generate_key([PMpint,GMpint]), + dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); + +dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> + PremasterSecret = + crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + [PMpint, GMpint]), + master_from_premaster_secret(PremasterSecret, State). + cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) -> ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0), next_state_connection(cipher, ack_connection(State#state{session = Session, @@ -1741,6 +1761,7 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) -> end. read_application_data(Data, #state{user_application = {_Mon, Pid}, + socket = Socket, socket_options = SOpts, bytes_to_read = BytesToRead, start_or_recv_from = RecvFrom, @@ -1753,7 +1774,7 @@ read_application_data(Data, #state{user_application = {_Mon, Pid}, end, case get_data(SOpts, BytesToRead, Buffer1) of {ok, ClientData, Buffer} -> % Send data - SocketOpt = deliver_app_data(SOpts, ClientData, Pid, RecvFrom), + SocketOpt = deliver_app_data(Socket, SOpts, ClientData, Pid, RecvFrom), cancel_timer(Timer), State = State0#state{user_data_buffer = Buffer, start_or_recv_from = undefined, @@ -1774,7 +1795,7 @@ read_application_data(Data, #state{user_application = {_Mon, Pid}, {passive, Buffer} -> next_record_if_active(State0#state{user_data_buffer = Buffer}); {error,_Reason} -> %% Invalid packet in packet mode - deliver_packet_error(SOpts, Buffer1, Pid, RecvFrom), + deliver_packet_error(Socket, SOpts, Buffer1, Pid, RecvFrom), {stop, normal, State0} end. @@ -1856,9 +1877,9 @@ decode_packet(Type, Buffer, PacketOpts) -> %% Note that if the user has explicitly configured the socket to expect %% HTTP headers using the {packet, httph} option, we don't do any automatic %% switching of states. -deliver_app_data(SOpts = #socket_options{active=Active, packet=Type}, - Data, Pid, From) -> - send_or_reply(Active, Pid, From, format_reply(SOpts, Data)), +deliver_app_data(Socket, SOpts = #socket_options{active=Active, packet=Type}, + Data, Pid, From) -> + send_or_reply(Active, Pid, From, format_reply(Socket, SOpts, Data)), SO = case Data of {P, _, _, _} when ((P =:= http_request) or (P =:= http_response)), ((Type =:= http) or (Type =:= http_bin)) -> @@ -1877,31 +1898,31 @@ deliver_app_data(SOpts = #socket_options{active=Active, packet=Type}, SO end. -format_reply(#socket_options{active = false, mode = Mode, packet = Packet, +format_reply(_,#socket_options{active = false, mode = Mode, packet = Packet, header = Header}, Data) -> - {ok, format_reply(Mode, Packet, Header, Data)}; -format_reply(#socket_options{active = _, mode = Mode, packet = Packet, + {ok, do_format_reply(Mode, Packet, Header, Data)}; +format_reply(Socket, #socket_options{active = _, mode = Mode, packet = Packet, header = Header}, Data) -> - {ssl, sslsocket(), format_reply(Mode, Packet, Header, Data)}. + {ssl, sslsocket(self(), Socket), do_format_reply(Mode, Packet, Header, Data)}. -deliver_packet_error(SO= #socket_options{active = Active}, Data, Pid, From) -> - send_or_reply(Active, Pid, From, format_packet_error(SO, Data)). +deliver_packet_error(Socket, SO= #socket_options{active = Active}, Data, Pid, From) -> + send_or_reply(Active, Pid, From, format_packet_error(Socket, SO, Data)). -format_packet_error(#socket_options{active = false, mode = Mode}, Data) -> - {error, {invalid_packet, format_reply(Mode, raw, 0, Data)}}; -format_packet_error(#socket_options{active = _, mode = Mode}, Data) -> - {ssl_error, sslsocket(), {invalid_packet, format_reply(Mode, raw, 0, Data)}}. +format_packet_error(_,#socket_options{active = false, mode = Mode}, Data) -> + {error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}}; +format_packet_error(Socket, #socket_options{active = _, mode = Mode}, Data) -> + {ssl_error, sslsocket(self(), Socket), {invalid_packet, do_format_reply(Mode, raw, 0, Data)}}. -format_reply(binary, _, N, Data) when N > 0 -> % Header mode +do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode header(N, Data); -format_reply(binary, _, _, Data) -> +do_format_reply(binary, _, _, Data) -> Data; -format_reply(list, Packet, _, Data) +do_format_reply(list, Packet, _, Data) when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers}; Packet == httph; Packet == httph_bin -> Data; -format_reply(list, _,_, Data) -> +do_format_reply(list, _,_, Data) -> binary_to_list(Data). header(0, <<>>) -> @@ -2072,8 +2093,8 @@ next_state_is_connection(_, State = next_state_is_connection(StateName, State0) -> {Record, State} = next_record_if_active(State0), next_state(StateName, connection, Record, State#state{premaster_secret = undefined, - public_key_info = undefined, - tls_handshake_history = ssl_handshake:init_handshake_history()}). + public_key_info = undefined, + tls_handshake_history = ssl_handshake:init_handshake_history()}). register_session(client, Host, Port, #session{is_resumable = new} = Session0) -> Session = Session0#session{is_resumable = true}, @@ -2130,11 +2151,8 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User, send_queue = queue:new() }. -sslsocket(Pid) -> - #sslsocket{pid = Pid, fd = new_ssl}. - -sslsocket() -> - sslsocket(self()). +sslsocket(Pid, Socket) -> + #sslsocket{pid = Pid, fd = Socket}. get_socket_opts(_,[], _, Acc) -> {ok, Acc}; @@ -2230,12 +2248,12 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State, _Timeout}) -> handle_alerts(Alerts, handle_alert(Alert, StateName, State)). handle_alert(#alert{level = ?FATAL} = Alert, StateName, - #state{start_or_recv_from = From, host = Host, port = Port, session = Session, - user_application = {_Mon, Pid}, + #state{socket = Socket, start_or_recv_from = From, host = Host, + port = Port, session = Session, user_application = {_Mon, Pid}, log_alert = Log, role = Role, socket_options = Opts} = State) -> invalidate_session(Role, Host, Port, Session), log_alert(Log, StateName, Alert), - alert_user(StateName, Opts, Pid, From, Alert, Role), + alert_user(Socket, StateName, Opts, Pid, From, Alert, Role), {stop, normal, State}; handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, @@ -2262,28 +2280,28 @@ handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, Sta {Record, State} = next_record(State0), next_state(StateName, StateName, Record, State). -alert_user(connection, Opts, Pid, From, Alert, Role) -> - alert_user(Opts#socket_options.active, Pid, From, Alert, Role); -alert_user(_, _, _, From, Alert, Role) -> - alert_user(From, Alert, Role). +alert_user(Socket, connection, Opts, Pid, From, Alert, Role) -> + alert_user(Socket, Opts#socket_options.active, Pid, From, Alert, Role); +alert_user(Socket,_, _, _, From, Alert, Role) -> + alert_user(Socket, From, Alert, Role). -alert_user(From, Alert, Role) -> - alert_user(false, no_pid, From, Alert, Role). +alert_user(Socket, From, Alert, Role) -> + alert_user(Socket, false, no_pid, From, Alert, Role). -alert_user(false = Active, Pid, From, Alert, Role) -> +alert_user(_Socket, false = Active, Pid, From, Alert, Role) -> %% If there is an outstanding ssl_accept | recv %% From will be defined and send_or_reply will %% send the appropriate error message. ReasonCode = ssl_alert:reason_code(Alert, Role), send_or_reply(Active, Pid, From, {error, ReasonCode}); -alert_user(Active, Pid, From, Alert, Role) -> +alert_user(Socket, Active, Pid, From, Alert, Role) -> case ssl_alert:reason_code(Alert, Role) of closed -> send_or_reply(Active, Pid, From, - {ssl_closed, sslsocket()}); + {ssl_closed, sslsocket(self(), Socket)}); ReasonCode -> send_or_reply(Active, Pid, From, - {ssl_error, sslsocket(), ReasonCode}) + {ssl_error, sslsocket(self(), Socket), ReasonCode}) end. log_alert(true, Info, Alert) -> @@ -2313,13 +2331,16 @@ handle_own_alert(Alert, Version, StateName, end, {stop, {shutdown, own_alert}, State}. -handle_normal_shutdown(Alert, _, #state{start_or_recv_from = StartFrom, role = Role, renegotiation = {false, first}}) -> - alert_user(StartFrom, Alert, Role); +handle_normal_shutdown(Alert, _, #state{socket = Socket, + start_or_recv_from = StartFrom, + role = Role, renegotiation = {false, first}}) -> + alert_user(Socket, StartFrom, Alert, Role); -handle_normal_shutdown(Alert, StateName, #state{socket_options = Opts, +handle_normal_shutdown(Alert, StateName, #state{socket = Socket, + socket_options = Opts, user_application = {_Mon, Pid}, start_or_recv_from = RecvFrom, role = Role}) -> - alert_user(StateName, Opts, Pid, RecvFrom, Alert, Role). + alert_user(Socket, StateName, Opts, Pid, RecvFrom, Alert, Role). handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) -> Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), @@ -2447,10 +2468,10 @@ get_pending_connection_state_prf(CStates, Direction) -> CS = ssl_record:pending_connection_state(CStates, Direction), CS#connection_state.security_parameters#security_parameters.prf_algorithm. -connection_hash_algo({HashAlgo, _}, _State) -> - HashAlgo; -connection_hash_algo(_, #state{hashsign_algorithm = {HashAlgo, _}}) -> - HashAlgo. +connection_hashsign(HashSign = {_, _}, _State) -> + HashSign; +connection_hashsign(_, #state{hashsign_algorithm = HashSign}) -> + HashSign. %% RFC 5246, Sect. 7.4.1.4.1. Signature Algorithms %% If the client does not send the signature_algorithms extension, the @@ -2488,12 +2509,13 @@ default_hashsign(_Version, KeyExchange) start_or_recv_cancel_timer(infinity, _RecvFrom) -> undefined; start_or_recv_cancel_timer(Timeout, RecvFrom) -> - erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}). + erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}). cancel_timer(undefined) -> ok; cancel_timer(Timer) -> - erlang:cancel_timer(Timer). + erlang:cancel_timer(Timer), + ok. handle_unrecv_data(StateName, #state{socket = Socket, transport_cb = Transport} = State) -> inet:setopts(Socket, [{active, false}]), diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index bb26302fff..1929370991 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -30,21 +30,21 @@ -include("ssl_internal.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([master_secret/4, client_hello/8, server_hello/4, hello/4, +-export([master_secret/4, client_hello/8, server_hello/5, hello/4, hello_request/0, certify/7, certificate/4, - client_certificate_verify/6, certificate_verify/6, + client_certificate_verify/6, certificate_verify/6, verify_signature/5, certificate_request/3, key_exchange/3, server_key_exchange_hash/2, finished/5, verify_connection/6, get_tls_handshake/3, - decode_client_key/3, server_hello_done/0, + decode_client_key/3, decode_server_key/3, server_hello_done/0, encode_handshake/2, init_handshake_history/0, update_handshake_history/2, - decrypt_premaster_secret/2, prf/5]). + decrypt_premaster_secret/2, prf/5, next_protocol/1]). -export([dec_hello_extensions/2]). -type tls_handshake() :: #client_hello{} | #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} | #client_key_exchange{} | #finished{} | #certificate_verify{} | - #hello_request{}. + #hello_request{} | #next_protocol{}. %%==================================================================== %% Internal application API @@ -77,18 +77,31 @@ client_hello(Host, Port, ConnectionStates, cipher_suites = cipher_suites(Ciphers, Renegotiation), compression_methods = ssl_record:compressions(), random = SecParams#security_parameters.client_random, + renegotiation_info = renegotiation_info(client, ConnectionStates, Renegotiation), - hash_signs = default_hash_signs() + hash_signs = default_hash_signs(), + next_protocol_negotiation = + encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation) }. +encode_protocol(Protocol, Acc) -> + Len = byte_size(Protocol), + <<Acc/binary, ?BYTE(Len), Protocol/binary>>. + +encode_protocols_advertised_on_server(undefined) -> + undefined; + +encode_protocols_advertised_on_server(Protocols) -> + #next_protocol_negotiation{extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}. + %%-------------------------------------------------------------------- -spec server_hello(session_id(), tls_version(), #connection_states{}, - boolean()) -> #server_hello{}. + boolean(), [binary()] | undefined) -> #server_hello{}. %% %% Description: Creates a server hello message. %%-------------------------------------------------------------------- -server_hello(SessionId, Version, ConnectionStates, Renegotiation) -> +server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) -> Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, #server_hello{server_version = Version, @@ -98,7 +111,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation) -> random = SecParams#security_parameters.server_random, session_id = SessionId, renegotiation_info = - renegotiation_info(server, ConnectionStates, Renegotiation) + renegotiation_info(server, ConnectionStates, Renegotiation), + next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer) }. %%-------------------------------------------------------------------- @@ -113,20 +127,21 @@ hello_request() -> %%-------------------------------------------------------------------- -spec hello(#server_hello{} | #client_hello{}, #ssl_options{}, #connection_states{} | {inet:port_number(), #session{}, db_handle(), - atom(), #connection_states{}, binary()}, - boolean()) -> {tls_version(), session_id(), #connection_states{}}| - {tls_version(), {resumed | new, #session{}}, - #connection_states{}} | #alert{}. + atom(), #connection_states{}, binary()}, + boolean()) -> + {tls_version(), session_id(), #connection_states{}, binary() | undefined}| + {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} | + #alert{}. %% %% Description: Handles a recieved hello message %%-------------------------------------------------------------------- hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, compression_method = Compression, random = Random, session_id = SessionId, renegotiation_info = Info, - hash_signs = _HashSigns}, - #ssl_options{secure_renegotiate = SecureRenegotation}, + hash_signs = _HashSigns} = Hello, + #ssl_options{secure_renegotiate = SecureRenegotation, next_protocol_selector = NextProtocolSelector}, ConnectionStates0, Renegotiation) -> -%%TODO: select hash and signature algorigthm + %%TODO: select hash and signature algorigthm case ssl_record:is_acceptable_version(Version) of true -> case handle_renegotiation_info(client, Info, ConnectionStates0, @@ -135,7 +150,12 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, ConnectionStates = hello_pending_connection_states(client, Version, CipherSuite, Random, Compression, ConnectionStates1), - {Version, SessionId, ConnectionStates}; + case handle_next_protocol(Hello, NextProtocolSelector, Renegotiation) of + #alert{} = Alert -> + Alert; + Protocol -> + {Version, SessionId, ConnectionStates, Protocol} + end; #alert{} = Alert -> Alert end; @@ -145,9 +165,8 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, hello(#client_hello{client_version = ClientVersion, random = Random, cipher_suites = CipherSuites, - renegotiation_info = Info, - hash_signs = _HashSigns} = Hello, - #ssl_options{versions = Versions, + renegotiation_info = Info} = Hello, + #ssl_options{versions = Versions, secure_renegotiate = SecureRenegotation} = SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> %% TODO: select hash and signature algorithm @@ -173,7 +192,12 @@ hello(#client_hello{client_version = ClientVersion, random = Random, Random, Compression, ConnectionStates1), - {Version, {Type, Session}, ConnectionStates}; + case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of + #alert{} = Alert -> + Alert; + ProtocolsToAdvertise -> + {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} + end; #alert{} = Alert -> Alert end @@ -296,25 +320,36 @@ client_certificate_verify(OwnCert, MasterSecret, Version, %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- -certificate_verify(Signature, {?'rsaEncryption', PublicKey, _}, Version, - {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) -> - Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), - case certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, Version) of +certificate_verify(Signature, PublicKeyInfo, Version, + HashSign = {HashAlgo, _}, MasterSecret, {_, Handshake}) -> + Hash = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), + case verify_signature(Version, Hash, HashSign, Signature, PublicKeyInfo) of true -> valid; _ -> - ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) - end; -certificate_verify(Signature, {?'id-dsa', PublicKey, PublicKeyParams}, Version, - {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) -> - Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), - case public_key:verify({digest, Hashes}, sha, Signature, {PublicKey, PublicKeyParams}) of - true -> - valid; - false -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) end. +%%-------------------------------------------------------------------- +-spec verify_signature(tls_version(), binary(), {term(), term()}, binary(), + public_key_info()) -> true | false. +%% +%% Description: Checks that a public_key signature is valid. +%%-------------------------------------------------------------------- +verify_signature(_Version, _Hash, {_HashAlgo, anon}, _Signature, _) -> + true; +verify_signature({3, Minor}, Hash, {HashAlgo, rsa}, Signature, {?rsaEncryption, PubKey, _PubKeyParams}) + when Minor >= 3 -> + public_key:verify({digest, Hash}, HashAlgo, Signature, PubKey); +verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey, _PubKeyParams}) -> + case public_key:decrypt_public(Signature, PubKey, + [{rsa_pad, rsa_pkcs1_padding}]) of + Hash -> true; + _ -> false + end; +verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) -> + public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}). + %%-------------------------------------------------------------------- -spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) -> @@ -358,31 +393,33 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) -> key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _}, #'DHParameter'{prime = P, base = G}, - {HashAlgo, SignAlgo}, ClientRandom, ServerRandom, PrivateKey}) -> + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> <<?UINT32(_), PBin/binary>> = crypto:mpint(P), <<?UINT32(_), GBin/binary>> = crypto:mpint(G), - PLen = byte_size(PBin), - GLen = byte_size(GBin), - YLen = byte_size(PublicKey), ServerDHParams = #server_dh_params{dh_p = PBin, dh_g = GBin, dh_y = PublicKey}, + enc_server_key_exchange(Version, ServerDHParams, HashSign, + ClientRandom, ServerRandom, PrivateKey). +enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo}, + ClientRandom, ServerRandom, PrivateKey) -> + EncParams = enc_server_key(Params), case HashAlgo of null -> - #server_key_exchange{params = ServerDHParams, - signed_params = <<>>, - hashsign = {null, anon}}; + #server_key_params{params = Params, + params_bin = EncParams, + hashsign = {null, anon}, + signature = <<>>}; _ -> Hash = server_key_exchange_hash(HashAlgo, <<ClientRandom/binary, - ServerRandom/binary, - ?UINT16(PLen), PBin/binary, - ?UINT16(GLen), GBin/binary, - ?UINT16(YLen), PublicKey/binary>>), - Signed = digitally_signed(Version, Hash, HashAlgo, PrivateKey), - #server_key_exchange{params = ServerDHParams, - signed_params = Signed, - hashsign = {HashAlgo, SignAlgo}} + ServerRandom/binary, + EncParams/binary>>), + Signature = digitally_signed(Version, Hash, HashAlgo, PrivateKey), + #server_key_params{params = Params, + params_bin = EncParams, + hashsign = {HashAlgo, SignAlgo}, + signature = Signature} end. %%-------------------------------------------------------------------- @@ -427,6 +464,11 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE) end. +-spec next_protocol(binary()) -> #next_protocol{}. + +next_protocol(SelectedProtocol) -> + #next_protocol{selected_protocol = SelectedProtocol}. + %%-------------------------------------------------------------------- -spec finished(tls_version(), client | server, integer(), binary(), tls_handshake_history()) -> #finished{}. @@ -494,6 +536,15 @@ decode_client_key(ClientKey, Type, Version) -> dec_client_key(ClientKey, key_exchange_alg(Type), Version). %%-------------------------------------------------------------------- +-spec decode_server_key(binary(), key_algo(), tls_version()) -> + #server_key_params{}. +%% +%% Description: Decode server_key data and return appropriate type +%%-------------------------------------------------------------------- +decode_server_key(ServerKey, Type, Version) -> + dec_server_key(ServerKey, key_exchange_alg(Type), Version). + +%%-------------------------------------------------------------------- -spec init_handshake_history() -> tls_handshake_history(). %% @@ -660,6 +711,57 @@ renegotiation_info(server, ConnectionStates, true) -> #renegotiation_info{renegotiated_connection = undefined} end. +decode_next_protocols({next_protocol_negotiation, Protocols}) -> + decode_next_protocols(Protocols, []). +decode_next_protocols(<<>>, Acc) -> + lists:reverse(Acc); +decode_next_protocols(<<?BYTE(Len), Protocol:Len/binary, Rest/binary>>, Acc) -> + case Len of + 0 -> + {error, invalid_next_protocols}; + _ -> + decode_next_protocols(Rest, [Protocol|Acc]) + end; +decode_next_protocols(_Bytes, _Acc) -> + {error, invalid_next_protocols}. + +next_protocol_extension_allowed(NextProtocolSelector, Renegotiating) -> + NextProtocolSelector =/= undefined andalso not Renegotiating. + +handle_next_protocol_on_server(#client_hello{next_protocol_negotiation = undefined}, _Renegotiation, _SslOpts) -> + undefined; + +handle_next_protocol_on_server(#client_hello{next_protocol_negotiation = {next_protocol_negotiation, <<>>}}, + false, #ssl_options{next_protocols_advertised = Protocols}) -> + Protocols; + +handle_next_protocol_on_server(_Hello, _Renegotiation, _SSLOpts) -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE). % unexpected next protocol extension + +handle_next_protocol(#server_hello{next_protocol_negotiation = undefined}, + _NextProtocolSelector, _Renegotiating) -> + undefined; + +handle_next_protocol(#server_hello{next_protocol_negotiation = Protocols}, + NextProtocolSelector, Renegotiating) -> + + case next_protocol_extension_allowed(NextProtocolSelector, Renegotiating) of + true -> + select_next_protocol(decode_next_protocols(Protocols), NextProtocolSelector); + false -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE) % unexpected next protocol extension + end. + +select_next_protocol({error, _Reason}, _NextProtocolSelector) -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE); +select_next_protocol(Protocols, NextProtocolSelector) -> + case NextProtocolSelector(Protocols) of + ?NO_PROTOCOL -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE); + Protocol when is_binary(Protocol) -> + Protocol + end. + handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)}, ConnectionStates, false, _, _) -> {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)}; @@ -816,17 +918,21 @@ master_secret(Version, MasterSecret, #security_parameters{ ServerCipherState, Role)}. -dec_hs(_Version, ?HELLO_REQUEST, <<>>) -> +dec_hs(_, ?NEXT_PROTOCOL, <<?BYTE(SelectedProtocolLength), SelectedProtocol:SelectedProtocolLength/binary, + ?BYTE(PaddingLength), _Padding:PaddingLength/binary>>) -> + #next_protocol{selected_protocol = SelectedProtocol}; + +dec_hs(_, ?HELLO_REQUEST, <<>>) -> #hello_request{}; %% Client hello v2. %% The server must be able to receive such messages, from clients that %% are willing to use ssl v3 or higher, but have ssl v2 compatibility. dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), - ?UINT16(CSLength), ?UINT16(0), - ?UINT16(CDLength), - CipherSuites:CSLength/binary, - ChallengeData:CDLength/binary>>) -> + ?UINT16(CSLength), ?UINT16(0), + ?UINT16(CDLength), + CipherSuites:CSLength/binary, + ChallengeData:CDLength/binary>>) -> #client_hello{client_version = {Major, Minor}, random = ssl_ssl2:client_random(ChallengeData, CDLength), session_id = 0, @@ -839,20 +945,22 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?UINT16(Cs_length), CipherSuites:Cs_length/binary, ?BYTE(Cm_length), Comp_methods:Cm_length/binary, Extensions/binary>>) -> - HelloExtensions = dec_hello_extensions(Extensions), - RenegotiationInfo = proplists:get_value(renegotiation_info, HelloExtensions, - undefined), - HashSigns = proplists:get_value(hash_signs, HelloExtensions, - undefined), + + DecodedExtensions = dec_hello_extensions(Extensions), + RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined), + HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined), + NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined), + #client_hello{ - client_version = {Major,Minor}, - random = Random, - session_id = Session_ID, - cipher_suites = from_2bytes(CipherSuites), - compression_methods = Comp_methods, - renegotiation_info = RenegotiationInfo, - hash_signs = HashSigns - }; + client_version = {Major,Minor}, + random = Random, + session_id = Session_ID, + cipher_suites = from_2bytes(CipherSuites), + compression_methods = Comp_methods, + renegotiation_info = RenegotiationInfo, + hash_signs = HashSigns, + next_protocol_negotiation = NextProtocolNegotiation + }; dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID:SID_length/binary, @@ -868,7 +976,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID:SID_length/binary, - Cipher_suite:2/binary, ?BYTE(Comp_method), + Cipher_suite:2/binary, ?BYTE(Comp_method), ?UINT16(ExtLen), Extensions:ExtLen/binary>>) -> HelloExtensions = dec_hello_extensions(Extensions, []), @@ -876,6 +984,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, undefined), HashSigns = proplists:get_value(hash_signs, HelloExtensions, undefined), + NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined), + #server_hello{ server_version = {Major,Minor}, random = Random, @@ -883,34 +993,12 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, cipher_suite = Cipher_suite, compression_method = Comp_method, renegotiation_info = RenegotiationInfo, - hash_signs = HashSigns}; + hash_signs = HashSigns, + next_protocol_negotiation = NextProtocolNegotiation}; dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; - -dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, - ?UINT16(GLen), G:GLen/binary, - ?UINT16(YLen), Y:YLen/binary, - ?UINT16(0)>>) -> %% May happen if key_algorithm is dh_anon - #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, - dh_y = Y}, - signed_params = <<>>, hashsign = {null, anon}}; -dec_hs({Major, Minor}, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, - ?UINT16(GLen), G:GLen/binary, - ?UINT16(YLen), Y:YLen/binary, - ?BYTE(HashAlgo), ?BYTE(SignAlgo), - ?UINT16(Len), Sig:Len/binary>>) - when Major == 3, Minor >= 3 -> - #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, - dh_y = Y}, - signed_params = Sig, - hashsign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}}; -dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, - ?UINT16(GLen), G:GLen/binary, - ?UINT16(YLen), Y:YLen/binary, - ?UINT16(Len), Sig:Len/binary>>) -> - #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, - dh_y = Y}, - signed_params = Sig, hashsign = undefined}; +dec_hs(_Version, ?SERVER_KEY_EXCHANGE, Keys) -> + #server_key_exchange{exchange_keys = Keys}; dec_hs({Major, Minor}, ?CERTIFICATE_REQUEST, <<?BYTE(CertTypesLen), CertTypes:CertTypesLen/binary, ?UINT16(HashSignsLen), HashSigns:HashSignsLen/binary, @@ -950,6 +1038,42 @@ dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> #client_diffie_hellman_public{dh_public = DH_Y}. +dec_ske_params(Len, Keys, Version) -> + <<Params:Len/bytes, Signature/binary>> = Keys, + dec_ske_signature(Params, Signature, Version). + +dec_ske_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo), + ?UINT16(0)>>, {Major, Minor}) + when Major == 3, Minor >= 3 -> + HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}, + {Params, HashSign, <<>>}; +dec_ske_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo), + ?UINT16(Len), Signature:Len/binary>>, {Major, Minor}) + when Major == 3, Minor >= 3 -> + HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}, + {Params, HashSign, Signature}; +dec_ske_signature(Params, <<>>, _) -> + {Params, {null, anon}, <<>>}; +dec_ske_signature(Params, <<?UINT16(0)>>, _) -> + {Params, {null, anon}, <<>>}; +dec_ske_signature(Params, <<?UINT16(Len), Signature:Len/binary>>, _) -> + {Params, undefined, Signature}; +dec_ske_signature(_, _, _) -> + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)). + +dec_server_key(<<?UINT16(PLen), P:PLen/binary, + ?UINT16(GLen), G:GLen/binary, + ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct, + ?KEY_EXCHANGE_DIFFIE_HELLMAN, Version) -> + Params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}, + {BinMsg, HashSign, Signature} = dec_ske_params(PLen + GLen + YLen + 6, KeyStruct, Version), + #server_key_params{params = Params, + params_bin = BinMsg, + hashsign = HashSign, + signature = Signature}; +dec_server_key(_, _, _) -> + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)). + dec_hello_extensions(<<>>) -> []; dec_hello_extensions(<<?UINT16(ExtLen), Extensions:ExtLen/binary>>) -> @@ -959,6 +1083,9 @@ dec_hello_extensions(_) -> dec_hello_extensions(<<>>, Acc) -> Acc; +dec_hello_extensions(<<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc) -> + Prop = {next_protocol_negotiation, #next_protocol_negotiation{extension_data = ExtensionData}}, + dec_hello_extensions(Rest, [Prop | Acc]); dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binary, Rest/binary>>, Acc) -> RenegotiateInfo = case Len of 1 -> % Initial handshake @@ -982,6 +1109,7 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len), %% Ignore data following the ClientHello (i.e., %% extensions) if not understood. + dec_hello_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Acc) -> dec_hello_extensions(Rest, Acc); %% This theoretically should not happen if the protocol is followed, but if it does it is ignored. @@ -1014,6 +1142,11 @@ certs_from_list(ACList) -> <<?UINT24(CertLen), Cert/binary>> end || Cert <- ACList]). +enc_hs(#next_protocol{selected_protocol = SelectedProtocol}, _Version) -> + PaddingLength = 32 - ((byte_size(SelectedProtocol) + 2) rem 32), + + {?NEXT_PROTOCOL, <<?BYTE((byte_size(SelectedProtocol))), SelectedProtocol/binary, + ?BYTE(PaddingLength), 0:(PaddingLength * 8)>>}; enc_hs(#hello_request{}, _Version) -> {?HELLO_REQUEST, <<>>}; enc_hs(#client_hello{client_version = {Major, Minor}, @@ -1022,19 +1155,21 @@ enc_hs(#client_hello{client_version = {Major, Minor}, cipher_suites = CipherSuites, compression_methods = CompMethods, renegotiation_info = RenegotiationInfo, - hash_signs = HashSigns}, _Version) -> + hash_signs = HashSigns, + next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SIDLength = byte_size(SessionID), BinCompMethods = list_to_binary(CompMethods), CmLength = byte_size(BinCompMethods), BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), - Extensions0 = hello_extensions(RenegotiationInfo), + Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), Extensions1 = if Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); true -> Extensions0 end, ExtensionsBin = enc_hello_extensions(Extensions1), - {?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, + + {?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SIDLength), SessionID/binary, ?UINT16(CsLength), BinCipherSuites/binary, ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>}; @@ -1044,9 +1179,10 @@ enc_hs(#server_hello{server_version = {Major, Minor}, session_id = Session_ID, cipher_suite = Cipher_suite, compression_method = Comp_method, - renegotiation_info = RenegotiationInfo}, _Version) -> + renegotiation_info = RenegotiationInfo, + next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SID_length = byte_size(Session_ID), - Extensions = hello_extensions(RenegotiationInfo), + Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID/binary, @@ -1055,18 +1191,12 @@ enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) -> ASN1Certs = certs_from_list(ASN1CertList), ACLen = erlang:iolist_size(ASN1Certs), {?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>}; -enc_hs(#server_key_exchange{params = #server_dh_params{ - dh_p = P, dh_g = G, dh_y = Y}, - signed_params = SignedParams, hashsign = HashSign}, Version) -> - PLen = byte_size(P), - GLen = byte_size(G), - YLen = byte_size(Y), - Signature = enc_sign(HashSign, SignedParams, Version), - {?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P/binary, - ?UINT16(GLen), G/binary, - ?UINT16(YLen), Y/binary, - Signature/binary>> - }; +enc_hs(#server_key_exchange{exchange_keys = Keys}, _Version) -> + {?SERVER_KEY_EXCHANGE, Keys}; +enc_hs(#server_key_params{params_bin = Keys, hashsign = HashSign, + signature = Signature}, Version) -> + EncSign = enc_sign(HashSign, Signature, Version), + {?SERVER_KEY_EXCHANGE, <<Keys/binary, EncSign/binary>>}; enc_hs(#certificate_request{certificate_types = CertTypes, hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSignAlgos}, certificate_authorities = CertAuths}, @@ -1110,6 +1240,14 @@ enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), <<?UINT16(Len), DHPublic/binary>>. +enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> + PLen = byte_size(P), + GLen = byte_size(G), + YLen = byte_size(Y), + <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>. + +enc_sign({_, anon}, _Sign, _Version) -> + <<>>; enc_sign({HashAlg, SignAlg}, Signature, _Version = {Major, Minor}) when Major == 3, Minor >= 3-> SignLen = byte_size(Signature), @@ -1119,8 +1257,9 @@ enc_sign(_HashSign, Sign, _Version) -> SignLen = byte_size(Sign), <<?UINT16(SignLen), Sign/binary>>. -hello_extensions(undefined) -> - []; +hello_extensions(RenegotiationInfo, NextProtocolNegotiation) -> + hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation). + %% Renegotiation info hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) -> []; @@ -1129,6 +1268,11 @@ hello_extensions(#renegotiation_info{} = Info) -> hello_extensions(#hash_sign_algos{} = Info) -> [Info]. +next_protocol_extension(undefined) -> + []; +next_protocol_extension(#next_protocol_negotiation{} = Info) -> + [Info]. + enc_hello_extensions(Extensions) -> enc_hello_extensions(Extensions, <<>>). enc_hello_extensions([], <<>>) -> @@ -1137,6 +1281,9 @@ enc_hello_extensions([], Acc) -> Size = byte_size(Acc), <<?UINT16(Size), Acc/binary>>; +enc_hello_extensions([#next_protocol_negotiation{extension_data = ExtensionData} | Rest], Acc) -> + Len = byte_size(ExtensionData), + enc_hello_extensions(Rest, <<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len), ExtensionData/binary, Acc/binary>>); enc_hello_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = Info} | Rest], Acc) -> Len = byte_size(Info), enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info/binary, Acc/binary>>); @@ -1151,8 +1298,15 @@ enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], {Hash, Sign} <- HashSignAlgos >>, ListLen = byte_size(SignAlgoList), Len = ListLen + 2, - enc_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>). + enc_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT), + ?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>). +encode_client_protocol_negotiation(undefined, _) -> + undefined; +encode_client_protocol_negotiation(_, false) -> + #next_protocol_negotiation{extension_data = <<>>}; +encode_client_protocol_negotiation(_, _) -> + undefined. from_3bytes(Bin3) -> from_3bytes(Bin3, []). @@ -1211,8 +1365,8 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) -> digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 -> public_key:sign({digest, Hash}, HashAlgo, Key); -digitally_signed(_Version, Hash, _HashAlgo, #'DSAPrivateKey'{} = Key) -> - public_key:sign({digest, Hash}, sha, Key); +digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) -> + public_key:sign({digest, Hash}, HashAlgo, Key); digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]). @@ -1261,19 +1415,6 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) -> {unknown, {SslState, UserState}} end. -certificate_verify_rsa(Hashes, sha, Signature, PublicKey, {Major, Minor}) - when Major == 3, Minor >= 3 -> - public_key:verify({digest, Hashes}, sha, Signature, PublicKey); -certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor}) - when Major == 3, Minor >= 3 -> - public_key:verify({digest, Hashes}, HashAlgo, Signature, PublicKey); -certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) -> - case public_key:decrypt_public(Signature, PublicKey, - [{rsa_pad, rsa_pkcs1_padding}]) of - Hashes -> true; - _ -> false - end. - -define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}). -define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}). @@ -1284,6 +1425,7 @@ default_hash_signs() -> [?TLSEXT_SIGALG(sha512), ?TLSEXT_SIGALG(sha384), ?TLSEXT_SIGALG(sha256), + ?TLSEXT_SIGALG(sha224), ?TLSEXT_SIGALG(sha), ?TLSEXT_SIGALG_DSA(sha), ?TLSEXT_SIGALG_RSA(md5)]}. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index cc17dc2975..2414d5b666 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -33,6 +33,8 @@ -type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. -type tls_handshake_history() :: {[binary()], [binary()]}. +-define(NO_PROTOCOL, <<>>). + %% Signature algorithms -define(ANON, 0). -define(RSA, 1). @@ -97,7 +99,8 @@ cipher_suites, % cipher_suites<2..2^16-1> compression_methods, % compression_methods<1..2^8-1>, renegotiation_info, - hash_signs % supported combinations of hashes/signature algos + hash_signs, % supported combinations of hashes/signature algos + next_protocol_negotiation = undefined % [binary()] }). -record(server_hello, { @@ -107,7 +110,8 @@ cipher_suite, % cipher_suites compression_method, % compression_method renegotiation_info, - hash_signs % supported combinations of hashes/signature algos + hash_signs, % supported combinations of hashes/signature algos + next_protocol_negotiation = undefined % [binary()] }). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -137,9 +141,14 @@ }). -record(server_key_exchange, { + exchange_keys + }). + +-record(server_key_params, { params, %% #server_rsa_params{} | #server_dh_params{} - signed_params, %% #signature{} - hashsign %% term(atom(), atom()) + params_bin, + hashsign, %% term(atom(), atom()) + signature %% #signature{} }). %% enum { anonymous, rsa, dsa } SignatureAlgorithm; @@ -234,6 +243,18 @@ hash_sign_algos }). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Next Protocol Negotiation +%% (http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-02) +%% (http://technotes.googlecode.com/git/nextprotoneg.html) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(NEXTPROTONEG_EXT, 13172). +-define(NEXT_PROTOCOL, 67). +-record(next_protocol_negotiation, {extension_data}). + +-record(next_protocol, {selected_protocol}). + -endif. % -ifdef(ssl_handshake). diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index b8f2ae3b51..ed0dc34adf 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -69,8 +69,8 @@ -define(TRUE, 0). -define(FALSE, 1). --define(DEFAULT_SUPPORTED_VERSIONS, [tlsv1, sslv3]). %% Add 'tlsv1.1' in R16 -define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). +-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1, sslv3]). -record(ssl_options, { versions, % 'tlsv1.2' | 'tlsv1.1' | tlsv1 | sslv3 @@ -106,7 +106,9 @@ % after which ssl_connection will % go into hibernation %% This option should only be set to true by inet_tls_dist - erl_dist = false + erl_dist = false, + next_protocols_advertised = undefined, %% [binary()], + next_protocol_selector = undefined %% fun([binary()]) -> binary()) }). -record(socket_options, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 0cf4f2ce33..aa9da65bb8 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,8 +24,6 @@ -module(ssl_manager). -behaviour(gen_server). --include("ssl_internal.hrl"). - %% Internal application API -export([start_link/1, start_link_dist/1, connection_init/2, cache_pem_file/2, @@ -144,8 +142,15 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> new_session_id(Port) -> call({new_session_id, Port}). +%%-------------------------------------------------------------------- +-spec clean_cert_db(reference(), binary()) -> ok. +%% +%% Description: Send clean request of cert db to ssl_manager process should +%% be called by ssl-connection processes. +%%-------------------------------------------------------------------- clean_cert_db(Ref, File) -> - erlang:send_after(?CLEAN_CERT_DB, self(), {clean_cert_db, Ref, File}). + erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), {clean_cert_db, Ref, File}), + ok. %%-------------------------------------------------------------------- -spec register_session(inet:port_number(), #session{}) -> ok. @@ -322,19 +327,12 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) -> handle_info({clean_cert_db, Ref, File}, #state{certificate_db = [CertDb,RefDb, PemCache]} = State) -> - case ssl_certificate_db:ref_count(Ref, RefDb, 0) of - 0 -> - MD5 = crypto:md5(File), - case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of - [{Content, Ref}] -> - ssl_certificate_db:insert(MD5, Content, PemCache); - undefined -> - ok - end, - ssl_certificate_db:remove(Ref, RefDb), - ssl_certificate_db:remove_trusted_certs(Ref, CertDb); + + case ssl_certificate_db:lookup(Ref, RefDb) of + undefined -> %% Alredy cleaned + ok; _ -> - ok + clean_cert_db(Ref, CertDb, RefDb, PemCache, File) end, {noreply, State}; @@ -347,7 +345,7 @@ handle_info(_Info, State) -> {noreply, State}. %%-------------------------------------------------------------------- --spec terminate(reason(), #state{}) -> term(). +-spec terminate(reason(), #state{}) -> ok. %% %% Description: This function is called by a gen_server when it is about to %% terminate. It should be the opposite of Module:init/1 and do any necessary @@ -466,3 +464,19 @@ new_id(Port, Tries, Cache, CacheCb) -> _ -> new_id(Port, Tries - 1, Cache, CacheCb) end. + +clean_cert_db(Ref, CertDb, RefDb, PemCache, File) -> + case ssl_certificate_db:ref_count(Ref, RefDb, 0) of + 0 -> + MD5 = crypto:md5(File), + case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of + [{Content, Ref}] -> + ssl_certificate_db:insert(MD5, Content, PemCache); + _ -> + ok + end, + ssl_certificate_db:remove(Ref, RefDb), + ssl_certificate_db:remove_trusted_certs(Ref, CertDb); + _ -> + ok + end. diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 8e93ce4634..173b9611c6 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -463,10 +463,9 @@ supported_protocol_versions() -> supported_protocol_versions([]) -> Vsns = case sufficient_tlsv1_2_crypto_support() of true -> - %%?ALL_SUPPORTED_VERSIONS; %% Add TlS-1.2 as default in R16 - ?DEFAULT_SUPPORTED_VERSIONS; + ?ALL_SUPPORTED_VERSIONS; false -> - ?DEFAULT_SUPPORTED_VERSIONS + ?MIN_SUPPORTED_VERSIONS end, application:set_env(ssl, protocol_version, Vsns), Vsns; diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index 2ad422fc03..a24b2d9444 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -72,15 +72,12 @@ valid_session(#session{time_stamp = TimeStamp}, LifeTime) -> server_id(Port, <<>>, _SslOpts, _Cert, _, _) -> {ssl_manager:new_session_id(Port), undefined}; -server_id(Port, SuggestedId, - #ssl_options{reuse_sessions = ReuseEnabled, - reuse_session = ReuseFun}, - Cert, Cache, CacheCb) -> +server_id(Port, SuggestedId, Options, Cert, Cache, CacheCb) -> LifeTime = case application:get_env(ssl, session_lifetime) of {ok, Time} when is_integer(Time) -> Time; _ -> ?'24H_in_sec' end, - case is_resumable(SuggestedId, Port, ReuseEnabled,ReuseFun, + case is_resumable(SuggestedId, Port, Options, Cache, CacheCb, LifeTime, Cert) of {true, Resumed} -> @@ -112,9 +109,9 @@ select_session(Sessions, #ssl_options{ciphers = Ciphers}, OwnCert) -> [[Id, _]|_] -> Id end. -is_resumable(_, _, false, _, _, _, _, _) -> +is_resumable(_, _, #ssl_options{reuse_sessions = false}, _, _, _, _) -> {false, undefined}; -is_resumable(SuggestedSessionId, Port, true, ReuseFun, Cache, +is_resumable(SuggestedSessionId, Port, #ssl_options{reuse_session = ReuseFun} = Options, Cache, CacheCb, SecondLifeTime, OwnCert) -> case CacheCb:lookup(Cache, {Port, SuggestedSessionId}) of #session{cipher_suite = CipherSuite, @@ -125,6 +122,7 @@ is_resumable(SuggestedSessionId, Port, true, ReuseFun, Cache, case resumable(IsResumable) andalso (OwnCert == SessionOwnCert) andalso valid_session(Session, SecondLifeTime) + andalso reusable_options(Options, Session) andalso ReuseFun(SuggestedSessionId, PeerCert, Compression, CipherSuite) of @@ -139,3 +137,9 @@ resumable(new) -> false; resumable(IsResumable) -> IsResumable. + +reusable_options(#ssl_options{fail_if_no_peer_cert = true, + verify = verify_peer}, Session) -> + (Session#session.peer_certificate =/= undefined); +reusable_options(_,_) -> + true. diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index a8476b104f..a22af6b960 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2012. All Rights Reserved. +%% Copyright Ericsson AB 2011-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -89,7 +89,7 @@ handle_call({connect, Ip, Port}, {From, _}, State) -> ok -> flush_old_controller(From, Socket), {reply, Res, State} - end; + end; {Pid, Error} -> {reply, Error, State} end; @@ -115,13 +115,13 @@ code_change(_OldVsn, St, _Extra) -> get_tcp_address(Socket) -> case inet:sockname(Socket) of {ok, Address} -> - {ok, Host} = inet:gethostname(), + {ok, Host} = inet:gethostname(), NetAddress = #net_address{ - address = Address, - host = Host, - protocol = proxy, - family = inet - }, + address = Address, + host = Host, + protocol = proxy, + family = inet + }, {ok, NetAddress}; {error, _} = Error -> Error end. @@ -129,17 +129,17 @@ get_tcp_address(Socket) -> accept_loop(Proxy, erts = Type, Listen, Extra) -> process_flag(priority, max), case gen_tcp:accept(Listen) of - {ok, Socket} -> - Extra ! {accept,self(),Socket,inet,proxy}, - receive - {_Kernel, controller, Pid} -> - ok = gen_tcp:controlling_process(Socket, Pid), - flush_old_controller(Pid, Socket), - Pid ! {self(), controller}; - {_Kernel, unsupported_protocol} -> - exit(unsupported_protocol) - end; - Error -> + {ok, Socket} -> + Extra ! {accept,self(),Socket,inet,proxy}, + receive + {_Kernel, controller, Pid} -> + ok = gen_tcp:controlling_process(Socket, Pid), + flush_old_controller(Pid, Socket), + Pid ! {self(), controller}; + {_Kernel, unsupported_protocol} -> + exit(unsupported_protocol) + end; + Error -> exit(Error) end, accept_loop(Proxy, Type, Listen, Extra); @@ -242,7 +242,7 @@ loop_conn(World, Erts) -> ssl:close(World); {ssl_closed, World} -> gen_tcp:close(Erts) - end. + end. get_ssl_options(Type) -> case init:get_argument(ssl_dist_opt) of @@ -255,7 +255,7 @@ get_ssl_options(Type) -> ssl_options(_,[]) -> []; ssl_options(server, ["client_" ++ _, _Value |T]) -> - ssl_options(server,T); + ssl_options(server,T); ssl_options(client, ["server_" ++ _, _Value|T]) -> ssl_options(client,T); ssl_options(server, ["server_certfile", Value|T]) -> @@ -265,7 +265,7 @@ ssl_options(client, ["client_certfile", Value | T]) -> ssl_options(server, ["server_cacertfile", Value|T]) -> [{cacertfile, Value} | ssl_options(server,T)]; ssl_options(client, ["client_cacertfile", Value|T]) -> - [{cacertfile, Value} | ssl_options(client,T)]; + [{cacertfile, Value} | ssl_options(client,T)]; ssl_options(server, ["server_keyfile", Value|T]) -> [{keyfile, Value} | ssl_options(server,T)]; ssl_options(client, ["client_keyfile", Value|T]) -> @@ -277,7 +277,7 @@ ssl_options(client, ["client_password", Value|T]) -> ssl_options(server, ["server_verify", Value|T]) -> [{verify, atomize(Value)} | ssl_options(server,T)]; ssl_options(client, ["client_verify", Value|T]) -> - [{verify, atomize(Value)} | ssl_options(client,T)]; + [{verify, atomize(Value)} | ssl_options(client,T)]; ssl_options(server, ["server_reuse_sessions", Value|T]) -> [{reuse_sessions, atomize(Value)} | ssl_options(server,T)]; ssl_options(client, ["client_reuse_sessions", Value|T]) -> @@ -295,11 +295,11 @@ ssl_options(server, ["server_hibernate_after", Value|T]) -> ssl_options(client, ["client_hibernate_after", Value|T]) -> [{hibernate_after, list_to_integer(Value)} | ssl_options(client,T)]; ssl_options(server, ["server_ciphers", Value|T]) -> - [{ciphers, Value} | ssl_options(server,T)]; + [{ciphers, Value} | ssl_options(server,T)]; ssl_options(client, ["client_ciphers", Value|T]) -> [{ciphers, Value} | ssl_options(client,T)]; ssl_options(server, ["server_dhfile", Value|T]) -> - [{dhfile, Value} | ssl_options(server,T)]; + [{dhfile, Value} | ssl_options(server,T)]; ssl_options(server, ["server_fail_if_no_peer_cert", Value|T]) -> [{fail_if_no_peer_cert, atomize(Value)} | ssl_options(server,T)]; ssl_options(_,_) -> diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 343157b22e..847907cde8 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -37,13 +37,16 @@ VSN=$(GS_VSN) MODULES = \ ssl_test_lib \ ssl_basic_SUITE \ + ssl_cipher_SUITE \ + ssl_certificate_verify_SUITE\ + ssl_dist_SUITE \ ssl_handshake_SUITE \ + ssl_npn_hello_SUITE \ + ssl_npn_handshake_SUITE \ ssl_packet_SUITE \ - ssl_cipher_SUITE \ ssl_payload_SUITE \ - ssl_to_openssl_SUITE \ ssl_session_cache_SUITE \ - ssl_dist_SUITE \ + ssl_to_openssl_SUITE \ make_certs\ erl_make_certs diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 254aa6d2f9..5b92e551a5 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -137,10 +137,10 @@ decode_key(PemBin, Pw) -> encode_key(Key = #'RSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), - {'RSAPrivateKey', list_to_binary(Der), not_encrypted}; + {'RSAPrivateKey', Der, not_encrypted}; encode_key(Key = #'DSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {'DSAPrivateKey', list_to_binary(Der), not_encrypted}. + {'DSAPrivateKey', Der, not_encrypted}. make_tbs(SubjectKey, Opts) -> Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl index 693289990c..4603a9f846 100644 --- a/lib/ssl/test/make_certs.erl +++ b/lib/ssl/test/make_certs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -121,7 +121,19 @@ create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) -> " -keyout ", KeyFile, " -out ", CertFile], Env = [{"ROOTDIR", Root}], - cmd(Cmd, Env). + cmd(Cmd, Env), + fix_key_file(OpenSSLCmd, KeyFile). + +% openssl 1.0 generates key files in pkcs8 format by default and we don't handle this format +fix_key_file(OpenSSLCmd, KeyFile) -> + KeyFileTmp = KeyFile ++ ".tmp", + Cmd = [OpenSSLCmd, " rsa", + " -in ", + KeyFile, + " -out ", + KeyFileTmp], + cmd(Cmd, []), + ok = file:rename(KeyFileTmp, KeyFile). create_ca_dir(Root, CAName, Cnf) -> CARoot = filename:join([Root, CAName]), @@ -139,7 +151,8 @@ create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) -> " -keyout ", KeyFile, " -out ", ReqFile], Env = [{"ROOTDIR", Root}], - cmd(Cmd, Env). + cmd(Cmd, Env), + fix_key_file(OpenSSLCmd, KeyFile). sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) -> CACnfFile = filename:join([Root, CA, "ca.cnf"]), diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 112ed85ec5..7067cd861d 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,127 +41,10 @@ -define(RENEGOTIATION_DISABLE_TIME, 12000). -define(CLEAN_SESSION_DB, 60000). -%% Test server callback functions %%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initialization before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- -init_per_suite(Config0) -> - Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2), - catch crypto:stop(), - try crypto:start() of - ok -> - application:start(public_key), - - %% make rsa certs using oppenssl - Result = - (catch make_certs:all(?config(data_dir, Config0), - ?config(priv_dir, Config0))), - test_server:format("Make certs ~p~n", [Result]), - - Config1 = ssl_test_lib:make_dsa_cert(Config0), - Config = ssl_test_lib:cert_options(Config1), - [{watchdog, Dog} | Config] - catch _:_ -> - {skip, "Crypto did not start"} - end. -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto). - -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%% Description: Initialization before each test case +%% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- -init_per_testcase(no_authority_key_identifier, Config) -> - %% Clear cach so that root cert will not - %% be found. - ssl:clear_pem_cache(), - Config; -init_per_testcase(protocol_versions, Config) -> - ssl:stop(), - application:load(ssl), - %% For backwards compatibility sslv2 should be filtered out. - application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]), - ssl:start(), - Config; - -init_per_testcase(reuse_session_expired, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - ssl:stop(), - application:load(ssl), - application:set_env(ssl, session_lifetime, ?EXPIRE), - application:set_env(ssl, session_delay_cleanup_time, 500), - ssl:start(), - Config; - -init_per_testcase(empty_protocol_versions, Config) -> - ssl:stop(), - application:load(ssl), - application:set_env(ssl, protocol_version, []), - ssl:start(), - Config; - -%% init_per_testcase(different_ca_peer_sign, Config0) -> -%% ssl_test_lib:make_mix_cert(Config0); - -init_per_testcase(_TestCase, Config0) -> - test_server:format("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]), - Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case -%%-------------------------------------------------------------------- -end_per_testcase(reuse_session_expired, Config) -> - application:unset_env(ssl, session_lifetime), - application:unset_env(ssl, session_delay_cleanup_time), - end_per_testcase(default_action, Config); - -end_per_testcase(_TestCase, Config) -> - Dog = ?config(watchdog, Config), - case Dog of - undefined -> - ok; - _ -> - test_server:timetrap_cancel(Dog) - end. - -%%-------------------------------------------------------------------- -%% Function: all(Clause) -> TestCases -%% Clause - atom() - suite | doc -%% TestCases - [Case] -%% Case - atom() -%% Name of a test case. -%% Description: Returns a list of all test cases in this test suite -%%-------------------------------------------------------------------- suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -183,7 +66,6 @@ groups() -> {'tlsv1', [], all_versions_groups() ++ rizzo_tests()}, {'sslv3', [], all_versions_groups() ++ rizzo_tests()}, {api,[], api_tests()}, - {certificate_verify, [], certificate_verify_tests()}, {session, [], session_tests()}, {renegotiate, [], renegotiate_tests()}, {ciphers, [], cipher_tests()}, @@ -192,36 +74,18 @@ groups() -> all_versions_groups ()-> [{group, api}, - {group, certificate_verify}, {group, renegotiate}, {group, ciphers}, {group, error_handling_tests}]. -init_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - case ssl_test_lib:sufficient_crypto_support(GroupName) of - true -> - ssl_test_lib:init_tls_version(GroupName), - Config; - false -> - {skip, "Missing crypto support"} - end; - _ -> - ssl:start(), - Config - end. - - -end_per_group(_GroupName, Config) -> - Config. basic_tests() -> [app, alerts, send_close, connect_twice, - connect_dist + connect_dist, + clear_pem_cache ]. options_tests() -> @@ -242,12 +106,14 @@ options_tests() -> protocol_versions, empty_protocol_versions, ipv6, - reuseaddr]. + reuseaddr, + tcp_reuseaddr]. api_tests() -> [connection_info, peername, peercert, + peercert_with_client_cert, sockname, versions, controlling_process, @@ -258,41 +124,11 @@ api_tests() -> shutdown_both, shutdown_error, hibernate, + listen_socket, ssl_accept_timeout, ssl_recv_timeout ]. -certificate_verify_tests() -> - [server_verify_peer_passive, - server_verify_peer_active, - server_verify_peer_active_once, - server_verify_none_passive, - server_verify_none_active, - server_verify_none_active_once, - server_verify_no_cacerts, - server_require_peer_cert_ok, - server_require_peer_cert_fail, - server_verify_client_once_passive, - server_verify_client_once_active, - server_verify_client_once_active_once, - client_verify_none_passive, - client_verify_none_active, - client_verify_none_active_once, - extended_key_usage_verify_peer, - extended_key_usage_verify_none, - invalid_signature_client, - invalid_signature_server, - cert_expired, - client_with_cert_cipher_suites_handshake, - verify_fun_always_run_client, - verify_fun_always_run_server, - unknown_server_ca_fail, - unknown_server_ca_accept_verify_none, - unknown_server_ca_accept_verify_peer, - unknown_server_ca_accept_backwardscompatibility, - no_authority_key_identifier - ]. - session_tests() -> [reuse_session, reuse_session_expired, @@ -332,19 +168,109 @@ rizzo_tests() -> [rizzo, no_rizzo_rc4]. -%% Test cases starts here. %%-------------------------------------------------------------------- -app(doc) -> - "Test that the ssl app file is ok"; -app(suite) -> - []; +init_per_suite(Config0) -> + Dog = ct:timetrap(?LONG_TIMEOUT *2), + catch crypto:stop(), + try crypto:start() of + ok -> + application:start(public_key), + + %% make rsa certs using oppenssl + Result = + (catch make_certs:all(?config(data_dir, Config0), + ?config(priv_dir, Config0))), + ct:print("Make certs ~p~n", [Result]), + + Config1 = ssl_test_lib:make_dsa_cert(Config0), + Config = ssl_test_lib:cert_options(Config1), + [{watchdog, Dog} | Config] + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +%%-------------------------------------------------------------------- +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, "Missing crypto support"} + end; + _ -> + ssl:start(), + Config + end. + + +end_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +init_per_testcase(no_authority_key_identifier, Config) -> + %% Clear cach so that root cert will not + %% be found. + ssl:clear_pem_cache(), + Config; + +init_per_testcase(protocol_versions, Config) -> + ssl:stop(), + application:load(ssl), + %% For backwards compatibility sslv2 should be filtered out. + application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]), + ssl:start(), + Config; + +init_per_testcase(reuse_session_expired, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, ?EXPIRE), + application:set_env(ssl, session_delay_cleanup_time, 500), + ssl:start(), + Config; + +init_per_testcase(empty_protocol_versions, Config) -> + ssl:stop(), + application:load(ssl), + application:set_env(ssl, protocol_version, []), + ssl:start(), + Config; + +%% init_per_testcase(different_ca_peer_sign, Config0) -> +%% ssl_test_lib:make_mix_cert(Config0); + +init_per_testcase(_TestCase, Config0) -> + ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]), + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ct:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +end_per_testcase(reuse_session_expired, Config) -> + application:unset_env(ssl, session_lifetime), + application:unset_env(ssl, session_delay_cleanup_time), + end_per_testcase(default_action, Config); + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +app() -> + [{doc, "Test that the ssl app file is ok"}]. app(Config) when is_list(Config) -> - ok = test_server:app_test(ssl). + ok = ?t:app_test(ssl). %%-------------------------------------------------------------------- -alerts(doc) -> - "Test ssl_alert:alert_txt/1"; -alerts(suite) -> - []; +alerts() -> + [{doc, "Test ssl_alert:alert_txt/1"}]. alerts(Config) when is_list(Config) -> Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC, ?DECRYPTION_FAILED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE, @@ -361,14 +287,12 @@ alerts(Config) when is_list(Config) -> Txt when is_list(Txt) -> ok; Other -> - test_server:fail({unexpected, Other}) + ct:fail({unexpected, Other}) end end, Alerts). %%-------------------------------------------------------------------- -connection_info(doc) -> - ["Test the API function ssl:connection_info/1"]; -connection_info(suite) -> - []; +connection_info() -> + [{doc,"Test the API function ssl:connection_info/1"}]. connection_info(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -387,7 +311,7 @@ connection_info(Config) when is_list(Config) -> [{ciphers,[{rsa,rc4_128,sha,no_export}]} | ClientOpts]}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), Version = @@ -400,58 +324,23 @@ connection_info(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). -connection_info_result(Socket) -> - ssl:connection_info(Socket). - %%-------------------------------------------------------------------- - -protocol_versions(doc) -> - ["Test to set a list of protocol versions in app environment."]; - -protocol_versions(suite) -> - []; +protocol_versions() -> + [{doc,"Test to set a list of protocol versions in app environment."}]. protocol_versions(Config) when is_list(Config) -> basic_test(Config). - -empty_protocol_versions(doc) -> - ["Test to set an empty list of protocol versions in app environment."]; - -empty_protocol_versions(suite) -> - []; +%%-------------------------------------------------------------------- +empty_protocol_versions() -> + [{doc,"Test to set an empty list of protocol versions in app environment."}]. empty_protocol_versions(Config) when is_list(Config) -> basic_test(Config). - -basic_test(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -controlling_process(doc) -> - ["Test API function controlling_process/2"]; - -controlling_process(suite) -> - []; +controlling_process() -> + [{doc,"Test API function controlling_process/2"}]. controlling_process(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -475,7 +364,7 @@ controlling_process(Config) when is_list(Config) -> ClientMsg]}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), receive @@ -494,46 +383,15 @@ controlling_process(Config) when is_list(Config) -> ok end; Unexpected -> - test_server:fail(Unexpected) + ct:fail(Unexpected) end, ssl_test_lib:close(Server), ssl_test_lib:close(Client). -controlling_process_result(Socket, Pid, Msg) -> - ok = ssl:controlling_process(Socket, Pid), - %% Make sure other side has evaluated controlling_process - %% before message is sent - test_server:sleep(?SLEEP), - ssl:send(Socket, Msg), - no_result_msg. - -receive_s_rizzo_duong_beast() -> - receive - {ssl, _, "erver hello"} -> - receive - {ssl, _, "C"} -> - receive - {ssl, _, "lient hello"} -> - ok - end - end - end. -receive_c_rizzo_duong_beast() -> - receive - {ssl, _, "lient hello"} -> - receive - {ssl, _, "S"} -> - receive - {ssl, _, "erver hello"} -> - ok - end - end - end. %%-------------------------------------------------------------------- -controller_dies(doc) -> - ["Test that the socket is closed after controlling process dies"]; -controller_dies(suite) -> []; +controller_dies() -> + [{doc,"Test that the socket is closed after controlling process dies"}]. controller_dies(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -556,8 +414,8 @@ controller_dies(Config) when is_list(Config) -> ClientMsg]}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), - test_server:sleep(?SLEEP), %% so that they are connected + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), + ct:sleep(?SLEEP), %% so that they are connected process_flag(trap_exit, true), @@ -574,7 +432,7 @@ controller_dies(Config) when is_list(Config) -> %% Make sure server finishes and verification %% and is in coonection state before %% killing client - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), Pid ! {self(), connected, Socket}, receive die_nice -> normal end end, @@ -594,13 +452,13 @@ controller_dies(Config) when is_list(Config) -> Client3 ! die_nice end, - test_server:format("Wating on exit ~p~n",[Client3]), + ct:print("Wating on exit ~p~n",[Client3]), receive {'EXIT', Client3, normal} -> ok end, receive %% Client3 is dead but that doesn't matter, socket should not be closed. Unexpected -> - test_server:format("Unexpected ~p~n",[Unexpected]), - test_server:fail({line, ?LINE-1}) + ct:print("Unexpected ~p~n",[Unexpected]), + ct:fail({line, ?LINE-1}) after 1000 -> ok end, @@ -616,39 +474,17 @@ controller_dies(Config) when is_list(Config) -> controller_dies_result, [self(), ClientMsg]}}, {options, [{reuseaddr,true}|ClientOpts]}]), - test_server:sleep(?SLEEP), %% so that they are connected + ct:sleep(?SLEEP), %% so that they are connected exit(Server, killed), get_close(Server, ?LINE), process_flag(trap_exit, false), ssl_test_lib:close(LastClient). -controller_dies_result(_Socket, _Pid, _Msg) -> - receive Result -> Result end. - -get_close(Pid, Where) -> - receive - {'EXIT', Pid, _Reason} -> - receive - {_, {ssl_closed, Socket}} -> - test_server:format("Socket closed ~p~n",[Socket]); - Unexpected -> - test_server:format("Unexpected ~p~n",[Unexpected]), - test_server:fail({line, ?LINE-1}) - after 5000 -> - test_server:fail({timeout, {line, ?LINE, Where}}) - end; - Unexpected -> - test_server:format("Unexpected ~p~n",[Unexpected]), - test_server:fail({line, ?LINE-1}) - after 5000 -> - test_server:fail({timeout, {line, ?LINE, Where}}) - end. - %%-------------------------------------------------------------------- -client_closes_socket(doc) -> - ["Test what happens when client closes socket before handshake is compleated"]; -client_closes_socket(suite) -> []; +client_closes_socket() -> + [{doc,"Test what happens when client closes socket before handshake is compleated"}]. + client_closes_socket(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -665,7 +501,7 @@ client_closes_socket(Config) when is_list(Config) -> [Hostname, Port, TcpOpts]), %% Make sure that ssl_accept is called before %% client process ends and closes socket. - test_server:sleep(?SLEEP) + ct:sleep(?SLEEP) end, _Client = spawn_link(Connect), @@ -673,11 +509,8 @@ client_closes_socket(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, {error,closed}). %%-------------------------------------------------------------------- -connect_dist(doc) -> - ["Test a simple connect as is used by distribution"]; - -connect_dist(suite) -> - []; +connect_dist() -> + [{doc,"Test a simple connect as is used by distribution"}]. connect_dist(Config) when is_list(Config) -> ClientOpts0 = ?config(client_kc_opts, Config), @@ -703,22 +536,36 @@ connect_dist(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). -connect_dist_s(S) -> - Msg = term_to_binary({erlang,term}), - ok = ssl:send(S, Msg). - -connect_dist_c(S) -> - Test = binary_to_list(term_to_binary({erlang,term})), - {ok, Test} = ssl:recv(S, 0, 10000), - ok. +%%-------------------------------------------------------------------- +clear_pem_cache() -> + [{doc,"Test that internal reference tabel is cleaned properly even when " + " the PEM cache is cleared" }]. +clear_pem_cache(Config) when is_list(Config) -> + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + [_,FilRefDb, _] = element(5, State), + {Server, Client} = basic_verify_test_no_close(Config), + 2 = ets:info(FilRefDb, size), + ssl:clear_pem_cache(), + _ = sys:get_status(whereis(ssl_manager)), + {Server1, Client1} = basic_verify_test_no_close(Config), + 4 = ets:info(FilRefDb, size), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + ct:sleep(5000), + _ = sys:get_status(whereis(ssl_manager)), + 2 = ets:info(FilRefDb, size), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1), + ct:sleep(5000), + _ = sys:get_status(whereis(ssl_manager)), + 0 = ets:info(FilRefDb, size). %%-------------------------------------------------------------------- -peername(doc) -> - ["Test API function peername/1"]; - -peername(suite) -> - []; +peername() -> + [{doc,"Test API function peername/1"}]. peername(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -741,7 +588,7 @@ peername(Config) when is_list(Config) -> ServerMsg = {ok, {ClientIp, ClientPort}}, ClientMsg = {ok, {ServerIp, Port}}, - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -749,14 +596,9 @@ peername(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). -peername_result(S) -> - ssl:peername(S). - %%-------------------------------------------------------------------- -peercert(doc) -> - [""]; -peercert(suite) -> - []; +peercert() -> + [{doc,"Test API function peercert/1"}]. peercert(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -779,7 +621,7 @@ peercert(Config) when is_list(Config) -> ServerMsg = {error, no_peercert}, ClientMsg = {ok, BinCert}, - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -789,14 +631,45 @@ peercert(Config) when is_list(Config) -> peercert_result(Socket) -> ssl:peercert(Socket). - %%-------------------------------------------------------------------- -sockname(doc) -> - ["Test API function sockname/1"]; -sockname(suite) -> - []; +peercert_with_client_cert() -> + [{doc,"Test API function peercert/1"}]. +peercert_with_client_cert(Config) when is_list(Config) -> + ClientOpts = ?config(client_dsa_opts, Config), + ServerOpts = ?config(server_dsa_verify_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, ClientOpts}]), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + [{'Certificate', ServerBinCert, _}]= ssl_test_lib:pem_to_der(ServerCertFile), + ClientCertFile = proplists:get_value(certfile, ClientOpts), + [{'Certificate', ClientBinCert, _}]= ssl_test_lib:pem_to_der(ClientCertFile), + + ServerMsg = {ok, ClientBinCert}, + ClientMsg = {ok, ServerBinCert}, + + ct:print("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +sockname() -> + [{doc,"Test API function sockname/1"}]. sockname(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -818,7 +691,7 @@ sockname(Config) when is_list(Config) -> ServerMsg = {ok, {ServerIp, Port}}, ClientMsg = {ok, {ClientIp, ClientPort}}, - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -830,11 +703,8 @@ sockname_result(S) -> ssl:sockname(S). %%-------------------------------------------------------------------- -cipher_suites(doc) -> - ["Test API function cipher_suites/0"]; - -cipher_suites(suite) -> - []; +cipher_suites() -> + [{doc,"Test API function cipher_suites/0"}]. cipher_suites(Config) when is_list(Config) -> MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha}, @@ -844,11 +714,8 @@ cipher_suites(Config) when is_list(Config) -> [_|_] =ssl:cipher_suites(openssl). %%-------------------------------------------------------------------- -socket_options(doc) -> - ["Test API function getopts/2 and setopts/2"]; - -socket_options(suite) -> - []; +socket_options() -> + [{doc,"Test API function getopts/2 and setopts/2"}]. socket_options(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -897,16 +764,13 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> ssl:setopts(Socket, [{nodelay, true}]), {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]), {ok, All} = ssl:getopts(Socket, []), - test_server:format("All opts ~p~n", [All]), + ct:print("All opts ~p~n", [All]), ok. %%-------------------------------------------------------------------- -invalid_inet_get_option(doc) -> - ["Test handling of invalid inet options in getopts"]; - -invalid_inet_get_option(suite) -> - []; +invalid_inet_get_option() -> + [{doc,"Test handling of invalid inet options in getopts"}]. invalid_inet_get_option(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -923,24 +787,16 @@ invalid_inet_get_option(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). - -get_invalid_inet_option(Socket) -> - {error, {eoptions, {inet_option, foo, _}}} = ssl:getopts(Socket, [foo]), - ok. - %%-------------------------------------------------------------------- -invalid_inet_get_option_not_list(doc) -> - ["Test handling of invalid type in getopts"]; - -invalid_inet_get_option_not_list(suite) -> - []; +invalid_inet_get_option_not_list() -> + [{doc,"Test handling of invalid type in getopts"}]. invalid_inet_get_option_not_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -957,7 +813,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -971,11 +827,8 @@ get_invalid_inet_option_not_list(Socket) -> ok. %%-------------------------------------------------------------------- -invalid_inet_get_option_improper_list(doc) -> - ["Test handling of invalid type in getopts"]; - -invalid_inet_get_option_improper_list(suite) -> - []; +invalid_inet_get_option_improper_list() -> + [{doc,"Test handling of invalid type in getopts"}]. invalid_inet_get_option_improper_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -992,7 +845,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -1005,11 +858,8 @@ get_invalid_inet_option_improper_list(Socket) -> ok. %%-------------------------------------------------------------------- -invalid_inet_set_option(doc) -> - ["Test handling of invalid inet options in setopts"]; - -invalid_inet_set_option(suite) -> - []; +invalid_inet_set_option() -> + [{doc,"Test handling of invalid inet options in setopts"}]. invalid_inet_set_option(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1026,7 +876,7 @@ invalid_inet_set_option(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -1040,11 +890,8 @@ set_invalid_inet_option(Socket) -> {error, {eoptions, {inet_opt, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]), ok. %%-------------------------------------------------------------------- -invalid_inet_set_option_not_list(doc) -> - ["Test handling of invalid type in setopts"]; - -invalid_inet_set_option_not_list(suite) -> - []; +invalid_inet_set_option_not_list() -> + [{doc,"Test handling of invalid type in setopts"}]. invalid_inet_set_option_not_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1061,7 +908,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -1075,11 +922,8 @@ set_invalid_inet_option_not_list(Socket) -> ok. %%-------------------------------------------------------------------- -invalid_inet_set_option_improper_list(doc) -> - ["Test handling of invalid tye in setopts"]; - -invalid_inet_set_option_improper_list(suite) -> - []; +invalid_inet_set_option_improper_list() -> + [{doc,"Test handling of invalid tye in setopts"}]. invalid_inet_set_option_improper_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1096,7 +940,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -1109,11 +953,8 @@ set_invalid_inet_option_improper_list(Socket) -> ok. %%-------------------------------------------------------------------- -misc_ssl_options(doc) -> - ["Test what happens when we give valid options"]; - -misc_ssl_options(suite) -> - []; +misc_ssl_options() -> + [{doc,"Test what happens when we give valid options"}]. misc_ssl_options(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1131,17 +972,17 @@ misc_ssl_options(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, TestOpts ++ ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, TestOpts ++ ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1149,23 +990,16 @@ misc_ssl_options(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -versions(doc) -> - ["Test API function versions/0"]; - -versions(suite) -> - []; +versions() -> + [{doc,"Test API function versions/0"}]. versions(Config) when is_list(Config) -> [_|_] = Versions = ssl:versions(), - test_server:format("~p~n", [Versions]). + ct:print("~p~n", [Versions]). %%-------------------------------------------------------------------- -send_recv(doc) -> - [""]; - -send_recv(suite) -> - []; - +send_recv() -> + [{doc,""}]. send_recv(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1173,17 +1007,17 @@ send_recv(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1192,12 +1026,8 @@ send_recv(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -send_close(doc) -> - [""]; - -send_close(suite) -> - []; - +send_close() -> + [{doc,""}]. send_close(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1205,7 +1035,7 @@ send_close(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect, @@ -1213,7 +1043,7 @@ send_close(Config) when is_list(Config) -> {ok, SslS} = rpc:call(ClientNode, ssl, connect, [TcpS,[{active, false}|ClientOpts]]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), self(), Server]), ok = ssl:send(SslS, "Hello world"), {ok,<<"Hello world">>} = ssl:recv(SslS, 11), @@ -1221,11 +1051,8 @@ send_close(Config) when is_list(Config) -> {error, _} = ssl:send(SslS, "Hello world"). %%-------------------------------------------------------------------- -close_transport_accept(doc) -> - ["Tests closing ssl socket when waiting on ssl:transport_accept/1"]; - -close_transport_accept(suite) -> - []; +close_transport_accept() -> + [{doc,"Tests closing ssl socket when waiting on ssl:transport_accept/1"}]. close_transport_accept(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), @@ -1235,7 +1062,7 @@ close_transport_accept(Config) when is_list(Config) -> Opts = [{active, false} | ServerOpts], {ok, ListenSocket} = rpc:call(ServerNode, ssl, listen, [Port, Opts]), spawn_link(fun() -> - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), rpc:call(ServerNode, ssl, close, [ListenSocket]) end), case rpc:call(ServerNode, ssl, transport_accept, [ListenSocket]) of @@ -1246,11 +1073,8 @@ close_transport_accept(Config) when is_list(Config) -> end. %%-------------------------------------------------------------------- -dh_params(doc) -> - ["Test to specify DH-params file in server."]; - -dh_params(suite) -> - []; +dh_params() -> + [{doc,"Test to specify DH-params file in server."}]. dh_params(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1262,13 +1086,13 @@ dh_params(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{dhfile, DHParamFile} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{ciphers,[{dhe_rsa,aes_256_cbc,sha,ignore}]} | ClientOpts]}]), @@ -1279,11 +1103,8 @@ dh_params(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -upgrade(doc) -> - ["Test that you can upgrade an tcp connection to an ssl connection"]; - -upgrade(suite) -> - []; +upgrade() -> + [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}]. upgrade(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1307,7 +1128,7 @@ upgrade(Config) when is_list(Config) -> {tcp_options, TcpOpts}, {ssl_options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1331,11 +1152,8 @@ upgrade_result(Socket) -> end. %%-------------------------------------------------------------------- -upgrade_with_timeout(doc) -> - ["Test ssl_accept/3"]; - -upgrade_with_timeout(suite) -> - []; +upgrade_with_timeout() -> + [{doc,"Test ssl_accept/3"}]. upgrade_with_timeout(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1360,7 +1178,7 @@ upgrade_with_timeout(Config) when is_list(Config) -> {tcp_options, TcpOpts}, {ssl_options, ClientOpts}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1369,11 +1187,8 @@ upgrade_with_timeout(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -tcp_connect(doc) -> - ["Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"]; - -tcp_connect(suite) -> - []; +tcp_connect() -> + [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}]. tcp_connect(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), @@ -1389,22 +1204,19 @@ tcp_connect(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]), - test_server:format("Testcase ~p connected to Server ~p ~n", [self(), Server]), + ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]), gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"), receive {tcp_closed, Socket} -> receive {Server, {error, Error}} -> - test_server:format("Error ~p", [Error]) + ct:print("Error ~p", [Error]) end end. - -tcp_connect_big(doc) -> - ["Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"]; - -tcp_connect_big(suite) -> - []; +%%-------------------------------------------------------------------- +tcp_connect_big() -> + [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}]. tcp_connect_big(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), @@ -1420,7 +1232,7 @@ tcp_connect_big(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]), - test_server:format("Testcase ~p connected to Server ~p ~n", [self(), Server]), + ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]), Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1), gen_tcp:send(Socket, <<?BYTE(0), @@ -1430,24 +1242,16 @@ tcp_connect_big(Config) when is_list(Config) -> {tcp_closed, Socket} -> receive {Server, {error, timeout}} -> - test_server:fail("hangs"); + ct:fail("hangs"); {Server, {error, Error}} -> - test_server:format("Error ~p", [Error]) + ct:print("Error ~p", [Error]) end end. -dummy(_Socket) -> - %% Should not happen as the ssl connection will not be established - %% due to fatal handshake failiure - exit(kill). - %%-------------------------------------------------------------------- ipv6() -> - [{require, ipv6_hosts}]. -ipv6(doc) -> - ["Test ipv6."]; -ipv6(suite) -> - []; + [{require, ipv6_hosts}, + {doc,"Test ipv6."}]. ipv6(Config) when is_list(Config) -> {ok, Hostname0} = inet:gethostname(), @@ -1459,18 +1263,18 @@ ipv6(Config) when is_list(Config) -> ssl_test_lib:run_where(Config, ipv6), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [inet6, {active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [inet6, {active, false} | ClientOpts]}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1483,12 +1287,8 @@ ipv6(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -ekeyfile(doc) -> - ["Test what happens with an invalid key file"]; - -ekeyfile(suite) -> - []; - +ekeyfile() -> + [{doc,"Test what happens with an invalid key file"}]. ekeyfile(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), BadOpts = ?config(server_bad_key, Config), @@ -1511,11 +1311,8 @@ ekeyfile(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -ecertfile(doc) -> - ["Test what happens with an invalid cert file"]; - -ecertfile(suite) -> - []; +ecertfile() -> + [{doc,"Test what happens with an invalid cert file"}]. ecertfile(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1540,11 +1337,8 @@ ecertfile(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -ecacertfile(doc) -> - ["Test what happens with an invalid cacert file"]; - -ecacertfile(suite) -> - []; +ecacertfile() -> + [{doc,"Test what happens with an invalid cacert file"}]. ecacertfile(Config) when is_list(Config) -> ClientOpts = [{reuseaddr, true}|?config(client_opts, Config)], @@ -1592,12 +1386,9 @@ ecacertfile(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -eoptions(doc) -> - ["Test what happens when we give invalid options"]; +eoptions() -> + [{doc,"Test what happens when we give invalid options"}]. -eoptions(suite) -> - []; - eoptions(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1654,12 +1445,8 @@ eoptions(Config) when is_list(Config) -> ok. %%-------------------------------------------------------------------- -shutdown(doc) -> - [""]; - -shutdown(suite) -> - []; - +shutdown() -> + [{doc,"Test API function ssl:shutdown/2"}]. shutdown(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1684,25 +1471,9 @@ shutdown(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). -shutdown_result(Socket, server) -> - ssl:send(Socket, "Hej"), - ssl:shutdown(Socket, write), - {ok, "Hej hopp"} = ssl:recv(Socket, 8), - ok; - -shutdown_result(Socket, client) -> - {ok, "Hej"} = ssl:recv(Socket, 3), - ssl:send(Socket, "Hej hopp"), - ssl:shutdown(Socket, write), - ok. - %%-------------------------------------------------------------------- -shutdown_write(doc) -> - [""]; - -shutdown_write(suite) -> - []; - +shutdown_write() -> + [{doc,"Test API function ssl:shutdown/2 with option write."}]. shutdown_write(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1719,20 +1490,10 @@ shutdown_write(Config) when is_list(Config) -> {options, [{active, false} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, {error, closed}). - -shutdown_write_result(Socket, server) -> - test_server:sleep(?SLEEP), - ssl:shutdown(Socket, write); -shutdown_write_result(Socket, client) -> - ssl:recv(Socket, 0). %%-------------------------------------------------------------------- -shutdown_both(doc) -> - [""]; - -shutdown_both(suite) -> - []; - +shutdown_both() -> + [{doc,"Test API function ssl:shutdown/2 with option both."}]. shutdown_both(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1750,19 +1511,9 @@ shutdown_both(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok, Client, {error, closed}). -shutdown_both_result(Socket, server) -> - test_server:sleep(?SLEEP), - ssl:shutdown(Socket, read_write); -shutdown_both_result(Socket, client) -> - ssl:recv(Socket, 0). - %%-------------------------------------------------------------------- -shutdown_error(doc) -> - [""]; - -shutdown_error(suite) -> - []; - +shutdown_error() -> + [{doc,"Test ssl:shutdown/2 error handling"}]. shutdown_error(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), Port = ssl_test_lib:inet_port(node()), @@ -1772,141 +1523,60 @@ shutdown_error(Config) when is_list(Config) -> {error, closed} = ssl:shutdown(Listen, read_write). %%------------------------------------------------------------------- -ciphers_rsa_signed_certs(doc) -> - ["Test all rsa ssl cipher suites in highest support ssl/tls version"]; +ciphers_rsa_signed_certs() -> + [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}]. -ciphers_rsa_signed_certs(suite) -> - []; - ciphers_rsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:rsa_suites(), - test_server:format("~p erlang cipher suites ~p~n", [Version, Ciphers]), + ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, rsa). - -ciphers_rsa_signed_certs_openssl_names(doc) -> - ["Test all rsa ssl cipher suites in highest support ssl/tls version"]; +%%------------------------------------------------------------------- +ciphers_rsa_signed_certs_openssl_names() -> + [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}]. -ciphers_rsa_signed_certs_openssl_names(suite) -> - []; - ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:openssl_rsa_suites(), - test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, rsa). - -ciphers_dsa_signed_certs(doc) -> - ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; +%%------------------------------------------------------------------- +ciphers_dsa_signed_certs() -> + [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}]. -ciphers_dsa_signed_certs(suite) -> - []; - ciphers_dsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:dsa_suites(), - test_server:format("~p erlang cipher suites ~p~n", [Version, Ciphers]), + ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, dsa). - -ciphers_dsa_signed_certs_openssl_names(doc) -> - ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; +%%------------------------------------------------------------------- +ciphers_dsa_signed_certs_openssl_names() -> + [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}]. -ciphers_dsa_signed_certs_openssl_names(suite) -> - []; - ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:openssl_dsa_suites(), - test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, dsa). - -anonymous_cipher_suites(doc)-> - ["Test the anonymous ciphersuites"]; -anonymous_cipher_suites(suite) -> - []; +%%------------------------------------------------------------------- +anonymous_cipher_suites()-> + [{doc,"Test the anonymous ciphersuites"}]. anonymous_cipher_suites(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:anonymous_suites(), run_suites(Ciphers, Version, Config, anonymous). -run_suites(Ciphers, Version, Config, Type) -> - {ClientOpts, ServerOpts} = - case Type of - rsa -> - {?config(client_opts, Config), - ?config(server_opts, Config)}; - dsa -> - {?config(client_opts, Config), - ?config(server_dsa_opts, Config)}; - anonymous -> - %% No certs in opts! - {?config(client_opts, Config), - ?config(server_anon, Config)} - end, - - Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, - Ciphers), - case lists:flatten(Result) of - [] -> - ok; - Error -> - test_server:format("Cipher suite errors: ~p~n", [Error]), - test_server:fail(cipher_suite_failed_see_test_case_log) - end. - -erlang_cipher_suite(Suite) when is_list(Suite)-> - ssl:suite_definition(ssl_cipher:openssl_suite(Suite)); -erlang_cipher_suite(Suite) -> - Suite. - -cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> - %% process_flag(trap_exit, true), - test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - ErlangCipherSuite = erlang_cipher_suite(CipherSuite), - - ConnectionInfo = {ok, {Version, ErlangCipherSuite}}, - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, - {options, - [{ciphers,[CipherSuite]} | - ClientOpts]}]), - - Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - - case Result of - ok -> - []; - Error -> - [{ErlangCipherSuite, Error}] - end. - %%-------------------------------------------------------------------- -default_reject_anonymous(doc)-> - ["Test that by default anonymous cipher suites are rejected "]; -default_reject_anonymous(suite) -> - []; +default_reject_anonymous()-> + [{doc,"Test that by default anonymous cipher suites are rejected "}]. default_reject_anonymous(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), ClientOpts = ?config(client_opts, Config), @@ -1925,16 +1595,12 @@ default_reject_anonymous(Config) when is_list(Config) -> [{ciphers,[Cipher]} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error, "insufficient security"}, - Client, {error, "insufficient security"}). + ssl_test_lib:check_result(Server, {error, {essl, "insufficient security"}}, + Client, {error, {essl, "insufficient security"}}). %%-------------------------------------------------------------------- -reuse_session(doc) -> - ["Test reuse of sessions (short handshake)"]; - -reuse_session(suite) -> - []; - +reuse_session() -> + [{doc,"Test reuse of sessions (short handshake)"}]. reuse_session(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1960,7 +1626,7 @@ reuse_session(Config) when is_list(Config) -> Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), Client1 = ssl_test_lib:start_client([{node, ClientNode}, @@ -1971,9 +1637,9 @@ reuse_session(Config) when is_list(Config) -> {Client1, SessionInfo} -> ok; {Client1, Other} -> - test_server:format("Expected: ~p, Unexpected: ~p~n", + ct:print("Expected: ~p, Unexpected: ~p~n", [SessionInfo, Other]), - test_server:fail(session_not_reused) + ct:fail(session_not_reused) end, Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, @@ -1986,7 +1652,7 @@ reuse_session(Config) when is_list(Config) -> | ClientOpts]}]), receive {Client2, SessionInfo} -> - test_server:fail( + ct:fail( session_reused_when_session_reuse_disabled_by_client); {Client2, _} -> ok @@ -2016,7 +1682,7 @@ reuse_session(Config) when is_list(Config) -> Server1 ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), Client4 = ssl_test_lib:start_client([{node, ClientNode}, @@ -2026,10 +1692,10 @@ reuse_session(Config) when is_list(Config) -> receive {Client4, SessionInfo1} -> - test_server:fail( + ct:fail( session_reused_when_session_reuse_disabled_by_server); {Client4, _Other} -> - test_server:format("OTHER: ~p ~n", [_Other]), + ct:print("OTHER: ~p ~n", [_Other]), ok end, @@ -2041,12 +1707,8 @@ reuse_session(Config) when is_list(Config) -> ssl_test_lib:close(Client4). %%-------------------------------------------------------------------- -reuse_session_expired(doc) -> - ["Test sessions is not reused when it has expired"]; - -reuse_session_expired(suite) -> - []; - +reuse_session_expired() -> + [{doc,"Test sessions is not reused when it has expired"}]. reuse_session_expired(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2072,7 +1734,7 @@ reuse_session_expired(Config) when is_list(Config) -> Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), Client1 = ssl_test_lib:start_client([{node, ClientNode}, @@ -2083,15 +1745,15 @@ reuse_session_expired(Config) when is_list(Config) -> {Client1, SessionInfo} -> ok; {Client1, Other} -> - test_server:format("Expected: ~p, Unexpected: ~p~n", + ct:print("Expected: ~p, Unexpected: ~p~n", [SessionInfo, Other]), - test_server:fail(session_not_reused) + ct:fail(session_not_reused) end, Server ! listen, %% Make sure session is unregistered due to expiration - test_server:sleep((?EXPIRE+1)), + ct:sleep((?EXPIRE+1)), [{session_id, Id} |_] = SessionInfo, make_sure_expired(Hostname, Port, Id), @@ -2103,7 +1765,7 @@ reuse_session_expired(Config) when is_list(Config) -> {from, self()}, {options, ClientOpts}]), receive {Client2, SessionInfo} -> - test_server:fail(session_reused_when_session_expired); + ct:fail(session_reused_when_session_expired); {Client2, _} -> ok end, @@ -2125,17 +1787,13 @@ make_sure_expired(Host, Port, Id) -> #session{is_resumable = false} -> ok; _ -> - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), make_sure_expired(Host, Port, Id) end. %%-------------------------------------------------------------------- -server_does_not_want_to_reuse_session(doc) -> - ["Test reuse of sessions (short handshake)"]; - -server_does_not_want_to_reuse_session(suite) -> - []; - +server_does_not_want_to_reuse_session() -> + [{doc,"Test reuse of sessions (short handshake)"}]. server_does_not_want_to_reuse_session(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2164,7 +1822,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), ssl_test_lib:close(Client0), Client1 = @@ -2174,7 +1832,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> - test_server:fail(session_reused_when_server_does_not_want_to); + ct:fail(session_reused_when_server_does_not_want_to); {Client1, _Other} -> ok end, @@ -2183,512 +1841,55 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- - -server_verify_peer_passive(doc) -> - ["Test server option verify_peer"]; - -server_verify_peer_passive(suite) -> - []; - -server_verify_peer_passive(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false}, {verify, verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_verify_peer_active(doc) -> - ["Test server option verify_peer"]; - -server_verify_peer_active(suite) -> - []; - -server_verify_peer_active(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, true}, {verify, verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -server_verify_peer_active_once(doc) -> - ["Test server option verify_peer"]; - -server_verify_peer_active_once(suite) -> - []; - -server_verify_peer_active_once(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once}, {verify, verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_verify_none_passive(doc) -> - ["Test server option verify_none"]; - -server_verify_none_passive(suite) -> - []; - -server_verify_none_passive(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false}, {verify, verify_none} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_verify_none_active(doc) -> - ["Test server option verify_none"]; - -server_verify_none_active(suite) -> - []; - -server_verify_none_active(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, true}, {verify, verify_none} | - ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -server_verify_none_active_once(doc) -> - ["Test server option verify_none"]; - -server_verify_none_active_once(suite) -> - []; - -server_verify_none_active_once(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once}, {verify, verify_none} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_verify_client_once_passive(doc) -> - ["Test server option verify_client_once"]; - -server_verify_client_once_passive(suite) -> - []; - -server_verify_client_once_passive(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false}, {verify, verify_peer}, - {verify_client_once, true} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client0, ok), - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - ssl_test_lib:close(Client0), - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, result_ok, []}}, - {options, [{active, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Client1, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- - -server_verify_client_once_active(doc) -> - ["Test server option verify_client_once"]; - -server_verify_client_once_active(suite) -> - []; - -server_verify_client_once_active(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, true}, {verify, verify_peer}, - {verify_client_once, true} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client0, ok), - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - ssl_test_lib:close(Client0), - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, result_ok, []}}, - {options, [{active, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Client1, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- - -server_verify_client_once_active_once(doc) -> - ["Test server option verify_client_once"]; - -server_verify_client_once_active_once(suite) -> - []; - -server_verify_client_once_active_once(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once}, {verify, verify_peer}, - {verify_client_once, true} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client0, ok), - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - ssl_test_lib:close(Client0), - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, result_ok, []}}, - {options, [{active, once} | ClientOpts]}]), - - ssl_test_lib:check_result(Client1, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- - -server_verify_no_cacerts(doc) -> - ["Test server must have cacerts if it wants to verify client"]; - -server_verify_no_cacerts(suite) -> - []; -server_verify_no_cacerts(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, [{verify, verify_peer} - | ServerOpts]}]), - - ssl_test_lib:check_result(Server, {error, {eoptions, {cacertfile, ""}}}). - -%%-------------------------------------------------------------------- - -server_require_peer_cert_ok(doc) -> - ["Test server option fail_if_no_peer_cert when peer sends cert"]; - -server_require_peer_cert_ok(suite) -> - []; - -server_require_peer_cert_ok(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ?config(server_verification_opts, Config)], - ClientOpts = ?config(client_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_require_peer_cert_fail(doc) -> - ["Test server option fail_if_no_peer_cert when peer doesn't send cert"]; - -server_require_peer_cert_fail(suite) -> - []; - -server_require_peer_cert_fail(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ?config(server_verification_opts, Config)], - BadClientOpts = ?config(client_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, [{active, false} | ServerOpts]}]), - - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{active, false} | BadClientOpts]}]), - - ssl_test_lib:check_result(Server, {error, esslaccept}, - Client, {error, esslconnect}). - -%%-------------------------------------------------------------------- - -client_verify_none_passive(doc) -> - ["Test client option verify_none"]; - -client_verify_none_passive(suite) -> - []; - -client_verify_none_passive(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, - {options, [{active, false}, - {verify, verify_none} - | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -client_verify_none_active(doc) -> - ["Test client option verify_none"]; - -client_verify_none_active(suite) -> - []; - -client_verify_none_active(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, [{active, true} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, [{active, true}, - {verify, verify_none} - | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -client_verify_none_active_once(doc) -> - ["Test client option verify_none"]; - -client_verify_none_active_once(suite) -> - []; - -client_verify_none_active_once(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active_once, []}}, - {options, [{active, once} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active_once, - []}}, - {options, [{active, once}, - {verify, verify_none} - | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -client_renegotiate(doc) -> - ["Test ssl:renegotiate/1 on client."]; - -client_renegotiate(suite) -> - []; - +client_renegotiate() -> + [{doc,"Test ssl:renegotiate/1 on client."}]. client_renegotiate(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - + Data = "From erlang to erlang", - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, + {from, self()}, + {mfa, {?MODULE, renegotiate, [Data]}}, {options, [{reuse_sessions, false} | ClientOpts]}]), - ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:check_result(Client, ok, Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -server_renegotiate(doc) -> - ["Test ssl:renegotiate/1 on server."]; - -server_renegotiate(suite) -> - []; - +server_renegotiate() -> + [{doc,"Test ssl:renegotiate/1 on server."}]. server_renegotiate(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - + Data = "From erlang to erlang", Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, + {mfa, {?MODULE, renegotiate, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, + {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, [{reuse_sessions, false} | ClientOpts]}]), @@ -2697,805 +1898,133 @@ server_renegotiate(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -client_renegotiate_reused_session(doc) -> - ["Test ssl:renegotiate/1 on client when the ssl session will be reused."]; - -client_renegotiate_reused_session(suite) -> - []; - +client_renegotiate_reused_session() -> + [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}]. client_renegotiate_reused_session(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - + Data = "From erlang to erlang", - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, + {from, self()}, + {mfa, {?MODULE, renegotiate_reuse_session, [Data]}}, {options, [{reuse_sessions, true} | ClientOpts]}]), - ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:check_result(Client, ok, Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -server_renegotiate_reused_session(doc) -> - ["Test ssl:renegotiate/1 on server when the ssl session will be reused."]; - -server_renegotiate_reused_session(suite) -> - []; - +server_renegotiate_reused_session() -> + [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}]. server_renegotiate_reused_session(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Data = "From erlang to erlang", - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, renegotiate_reuse_session, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, + {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, [{reuse_sessions, true} | ClientOpts]}]), - + ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -client_no_wrap_sequence_number(doc) -> - ["Test that erlang client will renegotiate session when", +client_no_wrap_sequence_number() -> + [{doc,"Test that erlang client will renegotiate session when", "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."]; - -client_no_wrap_sequence_number(suite) -> - []; + "in the testcase we use the test option renegotiate_at" + " to lower treashold substantially."}]. client_no_wrap_sequence_number(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - + ErlData = "From erlang to erlang", N = 10, - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - + Version = ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, + {from, self()}, + {mfa, {ssl_test_lib, trigger_renegotiate, [[ErlData, treashold(N, Version)]]}}, {options, [{reuse_sessions, false}, {renegotiate_at, N} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:check_result(Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). - %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast -treashold(N, {3,0}) -> - (N div 2) + 1; -treashold(N, {3,1}) -> - (N div 2) + 1; -treashold(N, _) -> - N + 1. - %%-------------------------------------------------------------------- -server_no_wrap_sequence_number(doc) -> - ["Test that erlang server will renegotiate session when", +server_no_wrap_sequence_number() -> + [{doc, "Test that erlang server will renegotiate session when", "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."]; - -server_no_wrap_sequence_number(suite) -> - []; + "in the testcase we use the test option renegotiate_at" + " to lower treashold substantially."}]. server_no_wrap_sequence_number(Config) when is_list(Config) -> - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - N = 10, - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[Data, N+2]]}}, - {options, [{renegotiate_at, N} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuse_sessions, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -extended_key_usage_verify_peer(doc) -> - ["Test cert that has a critical extended_key_usage extension in verify_peer mode"]; - -extended_key_usage_verify_peer(suite) -> - []; - -extended_key_usage_verify_peer(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - PrivDir = ?config(priv_dir, Config), - - KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), - - ServerCertFile = proplists:get_value(certfile, ServerOpts), - NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), - [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), - ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), - ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, - ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, - ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, - NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = - [ServerExtKeyUsageExt | - ServerExtensions]}, - NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), - NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], - - ClientCertFile = proplists:get_value(certfile, ClientOpts), - NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), - [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), - ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), - ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, - ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, - ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, - NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = - [ClientExtKeyUsageExt | - ClientExtensions]}, - NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), - NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{verify, verify_peer} | NewServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{verify, verify_peer} | NewClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -extended_key_usage_verify_none(doc) -> - ["Test cert that has a critical extended_key_usage extension in verify_none mode"]; - -extended_key_usage_verify_none(suite) -> - []; - -extended_key_usage_verify_none(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - PrivDir = ?config(priv_dir, Config), - - KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), - - ServerCertFile = proplists:get_value(certfile, ServerOpts), - NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), - [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), - ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), - ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, - ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, - ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, - NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = - [ServerExtKeyUsageExt | - ServerExtensions]}, - NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), - NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], - - ClientCertFile = proplists:get_value(certfile, ClientOpts), - NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), - [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), - ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), - ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, - ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, - ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, - NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = - [ClientExtKeyUsageExt | - ClientExtensions]}, - NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), - NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{verify, verify_none} | NewServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{verify, verify_none} | NewClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -no_authority_key_identifier(doc) -> - ["Test cert that does not have authorityKeyIdentifier extension" - " but are present in trusted certs db."]; - -no_authority_key_identifier(suite) -> - []; -no_authority_key_identifier(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), ServerOpts = ?config(server_opts, Config), - PrivDir = ?config(priv_dir, Config), - - KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), - - CertFile = proplists:get_value(certfile, ServerOpts), - NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), - [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), - OTPCert = public_key:pkix_decode_cert(DerCert, otp), - OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, - Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, - NewExtensions = delete_authority_key_extension(Extensions, []), - NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions}, - - test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), - - NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), - NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, NewServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{verify, verify_peer} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -delete_authority_key_extension([], Acc) -> - lists:reverse(Acc); -delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest], - Acc) -> - delete_authority_key_extension(Rest, Acc); -delete_authority_key_extension([Head | Rest], Acc) -> - delete_authority_key_extension(Rest, [Head | Acc]). - -%%-------------------------------------------------------------------- - -invalid_signature_server(doc) -> - ["Test server with invalid signature"]; - -invalid_signature_server(suite) -> - []; - -invalid_signature_server(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - PrivDir = ?config(priv_dir, Config), - - KeyFile = filename:join(PrivDir, "server/key.pem"), - [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), - - ServerCertFile = proplists:get_value(certfile, ServerOpts), - NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"), - [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), - ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), - ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, - NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), - NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, NewServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{verify, verify_peer} | ClientOpts]}]), - - tcp_delivery_workaround(Server, {error, "bad certificate"}, - Client, {error,"bad certificate"}). - -%%-------------------------------------------------------------------- - -invalid_signature_client(doc) -> - ["Test server with invalid signature"]; - -invalid_signature_client(suite) -> - []; - -invalid_signature_client(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - PrivDir = ?config(priv_dir, Config), - - KeyFile = filename:join(PrivDir, "client/key.pem"), - [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), - - ClientCertFile = proplists:get_value(certfile, ClientOpts), - NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"), - [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), - ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), - ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, - NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), - NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, [{verify, verify_peer} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, NewClientOpts}]), - - tcp_delivery_workaround(Server, {error, "bad certificate"}, - Client, {error,"bad certificate"}). - -tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> - receive - {Server, ServerMsg} -> - client_msg(Client, ClientMsg); - {Client, ClientMsg} -> - server_msg(Server, ServerMsg); - {Client, {error,closed}} -> - server_msg(Server, ServerMsg); - {Server, {error,closed}} -> - client_msg(Client, ClientMsg); - {Client, {error, esslconnect}} -> - server_msg(Server, ServerMsg); - {Server, {error, esslaccept}} -> - client_msg(Client, ClientMsg) - end. - -client_msg(Client, ClientMsg) -> - receive - {Client, ClientMsg} -> - ok; - {Client, {error,closed}} -> - test_server:format("client got close"), - ok; - {Client, {error, esslconnect}} -> - test_server:format("client got econnaborted"), - ok; - Unexpected -> - test_server:fail(Unexpected) - end. - -server_msg(Server, ServerMsg) -> - receive - {Server, ServerMsg} -> - ok; - {Server, {error,closed}} -> - test_server:format("server got close"), - ok; - {Server, {error, esslaccept}} -> - test_server:format("server got econnaborted"), - ok; - Unexpected -> - test_server:fail(Unexpected) - end. - -%%-------------------------------------------------------------------- -cert_expired(doc) -> - ["Test server with invalid signature"]; - -cert_expired(suite) -> - []; - -cert_expired(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - PrivDir = ?config(priv_dir, Config), - - KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), - Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), - - ServerCertFile = proplists:get_value(certfile, ServerOpts), - NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"), - [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), - OTPCert = public_key:pkix_decode_cert(DerCert, otp), - OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, - - {Year, Month, Day} = date(), - {Hours, Min, Sec} = time(), - NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2, - two_digits_str(Month), - two_digits_str(Day), - two_digits_str(Hours), - two_digits_str(Min), - two_digits_str(Sec)])), - NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1, - two_digits_str(Month), - two_digits_str(Day), - two_digits_str(Hours), - two_digits_str(Min), - two_digits_str(Sec)])), - NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}}, - - test_server:format("Validity: ~p ~n NewValidity: ~p ~n", - [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]), - - NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity}, - NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), - ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), - NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, NewServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{verify, verify_peer} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, {error, "certificate expired"}, - Client, {error, "certificate expired"}). - -two_digits_str(N) when N < 10 -> - lists:flatten(io_lib:format("0~p", [N])); -two_digits_str(N) -> - lists:flatten(io_lib:format("~p", [N])). - -%%-------------------------------------------------------------------- - -client_with_cert_cipher_suites_handshake(doc) -> - ["Test that client with a certificate without keyEncipherment usage " - " extension can connect to a server with restricted cipher suites "]; - -client_with_cert_cipher_suites_handshake(suite) -> - []; - -client_with_cert_cipher_suites_handshake(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts_digital_signature_only, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, [{active, true}, - {ciphers, ssl_test_lib:rsa_non_signed_suites()} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, [{active, true} - | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -verify_fun_always_run_client(doc) -> - ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"]; -verify_fun_always_run_client(suite) -> - []; -verify_fun_always_run_client(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - %% If user verify fun is called correctly we fail the connection. - %% otherwise we can not tell this case apart form where we miss - %% to call users verify fun - FunAndState = {fun(_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, [ChainLen]) -> - {valid, [ChainLen + 1]}; - (_, valid_peer, [2]) -> - {fail, "verify_fun_was_always_run"}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, [0]}, - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState} - | ClientOpts]}]), - %% Server error may be esslaccept or closed depending on timing - %% this is not a bug it is a circumstance of how tcp works! - receive - {Server, ServerError} -> - test_server:format("Server Error ~p~n", [ServerError]) - end, - - ssl_test_lib:check_result(Client, {error, esslconnect}). - -%%-------------------------------------------------------------------- -verify_fun_always_run_server(doc) -> - ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"]; -verify_fun_always_run_server(suite) -> - []; -verify_fun_always_run_server(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - %% If user verify fun is called correctly we fail the connection. - %% otherwise we can not tell this case apart form where we miss - %% to call users verify fun - FunAndState = {fun(_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, [ChainLen]) -> - {valid, [ChainLen + 1]}; - (_, valid_peer, [2]) -> - {fail, "verify_fun_was_always_run"}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, [0]}, - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState} | - ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer} - | ClientOpts]}]), - - %% Client error may be esslconnect or closed depending on timing - %% this is not a bug it is a circumstance of how tcp works! - receive - {Client, ClientError} -> - test_server:format("Client Error ~p~n", [ClientError]) - end, - - ssl_test_lib:check_result(Server, {error, esslaccept}). - -%%-------------------------------------------------------------------- -unknown_server_ca_fail(doc) -> - ["Test that the client fails if the ca is unknown in verify_peer mode"]; -unknown_server_ca_fail(suite) -> - []; -unknown_server_ca_fail(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) -> - {fail, Reason}; - (_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, UserState) -> - {valid, [test_to_update_user_state | UserState]}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, []}, - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState} - | ClientOpts]}]), - - ssl_test_lib:check_result(Server, {error,"unknown ca"}, - Client, {error, "unknown ca"}). - -%%-------------------------------------------------------------------- -unknown_server_ca_accept_verify_none(doc) -> - ["Test that the client succeds if the ca is unknown in verify_none mode"]; -unknown_server_ca_accept_verify_none(suite) -> - []; -unknown_server_ca_accept_verify_none(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, - [{verify, verify_none}| ClientOpts]}]), + ClientOpts = ?config(client_opts, Config), - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -unknown_server_ca_accept_verify_peer(doc) -> - ["Test that the client succeds if the ca is unknown in verify_peer mode" - " with a verify_fun that accepts the unknown ca error"]; -unknown_server_ca_accept_verify_peer(suite) -> - []; -unknown_server_ca_accept_verify_peer(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) -> - {valid, UserState}; - (_,{bad_cert, _} = Reason, _) -> - {fail, Reason}; - (_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, UserState) -> - {valid, UserState}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, []}, - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState}| ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + Data = "From erlang to erlang", + N = 10, -%%-------------------------------------------------------------------- -unknown_server_ca_accept_backwardscompatibility(doc) -> - ["Test that old style verify_funs will work"]; -unknown_server_ca_accept_backwardscompatibility(suite) -> - []; -unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; - (Other, Acc) -> [Other | Acc] - end, - VerifyFun = - fun(ErrorList) -> - case lists:foldl(AcceptBadCa, [], ErrorList) of - [] -> true; - [_|_] -> false - end - end, + {mfa, {ssl_test_lib, + trigger_renegotiate, [[Data, N+2]]}}, + {options, [{renegotiate_at, N} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, - send_recv_result_active, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, VerifyFun}| ClientOpts]}]), + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), - ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -der_input(doc) -> - ["Test to input certs and key as der"]; - -der_input(suite) -> - []; +der_input() -> + [{doc,"Test to input certs and key as der"}]. der_input(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), @@ -3516,19 +2045,19 @@ der_input(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). - +%%-------------------------------------------------------------------- der_input_opts(Opts) -> Certfile = proplists:get_value(certfile, Opts), CaCertsfile = proplists:get_value(cacertfile, Opts), @@ -3545,12 +2074,9 @@ der_input_opts(Opts) -> {Cert, {Asn1Type, Key}, CaCerts, DHParams}. %%-------------------------------------------------------------------- -%% different_ca_peer_sign(doc) -> +%% different_ca_peer_sign() -> %% ["Check that a CA can have a different signature algorithm than the peer cert."]; -%% different_ca_peer_sign(suite) -> -%% []; - %% different_ca_peer_sign(Config) when is_list(Config) -> %% ClientOpts = ?config(client_mix_opts, Config), %% ServerOpts = ?config(server_mix_verify_opts, Config), @@ -3558,7 +2084,7 @@ der_input_opts(Opts) -> %% {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), %% Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, %% {from, self()}, -%% {mfa, {?MODULE, send_recv_result_active_once, []}}, +%% {mfa, {ssl_test_lib, send_recv_result_active_once, []}}, %% {options, [{active, once}, %% {verify, verify_peer} | ServerOpts]}]), %% Port = ssl_test_lib:inet_port(Server), @@ -3566,7 +2092,7 @@ der_input_opts(Opts) -> %% Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, %% {host, Hostname}, %% {from, self()}, -%% {mfa, {?MODULE, +%% {mfa, {ssl_test_lib, %% send_recv_result_active_once, %% []}}, %% {options, [{active, once}, @@ -3579,12 +2105,8 @@ der_input_opts(Opts) -> %%-------------------------------------------------------------------- -no_reuses_session_server_restart_new_cert(doc) -> - ["Check that a session is not reused if the server is restarted with a new cert."]; - -no_reuses_session_server_restart_new_cert(suite) -> - []; - +no_reuses_session_server_restart_new_cert() -> + [{doc,"Check that a session is not reused if the server is restarted with a new cert."}]. no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -3610,10 +2132,15 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> end, %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), + Monitor = erlang:monitor(process, Server), ssl_test_lib:close(Server), ssl_test_lib:close(Client0), - + receive + {'DOWN', Monitor, _, _, _} -> + ok + end, + Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, @@ -3627,7 +2154,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> - test_server:fail(session_reused_when_server_has_new_cert); + ct:fail(session_reused_when_server_has_new_cert); {Client1, _Other} -> ok end, @@ -3635,12 +2162,9 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- -no_reuses_session_server_restart_new_cert_file(doc) -> - ["Check that a session is not reused if a server is restarted with a new " - "cert contained in a file with the same name as the old cert."]; - -no_reuses_session_server_restart_new_cert_file(suite) -> - []; +no_reuses_session_server_restart_new_cert_file() -> + [{doc,"Check that a session is not reused if a server is restarted with a new " + "cert contained in a file with the same name as the old cert."}]. no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -3670,7 +2194,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> %% Make sure session is registered and we get %% new file time stamp when calling new_config! - test_server:sleep(?SLEEP* 2), + ct:sleep(?SLEEP* 2), ssl_test_lib:close(Server), ssl_test_lib:close(Client0), @@ -3690,7 +2214,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> - test_server:fail(session_reused_when_server_has_new_cert); + ct:fail(session_reused_when_server_has_new_cert); {Client1, _Other} -> ok end, @@ -3698,11 +2222,8 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- -reuseaddr(doc) -> - [""]; - -reuseaddr(suite) -> - []; +reuseaddr() -> + [{doc,"Test reuseaddr option"}]. reuseaddr(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -3720,20 +2241,19 @@ reuseaddr(Config) when is_list(Config) -> {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, [{active, false} | ClientOpts]}]), - test_server:sleep(?SLEEP), ssl_test_lib:close(Server), ssl_test_lib:close(Client), - + Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), ssl_test_lib:check_result(Server1, ok, Client1, ok), @@ -3741,14 +2261,51 @@ reuseaddr(Config) when is_list(Config) -> ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- +tcp_reuseaddr() -> + [{doc, "Reference test case."}]. +tcp_reuseaddr(Config) when is_list(Config) -> + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {transport, gen_tcp}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{active, false}, {reuseaddr, true}]}]), + Port = ssl_test_lib:inet_port(Server), + Client = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {transport, gen_tcp}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{active, false}]}]), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {transport, gen_tcp}, + {mfa, {?MODULE, tcp_send_recv_result, []}}, + {options, [{active, false}, {reuseaddr, true}]}]), + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {transport, gen_tcp}, + {mfa, {?MODULE, tcp_send_recv_result, []}}, + {options, [{active, false}]}]), -hibernate(doc) -> - ["Check that an SSL connection that is started with option " - "{hibernate_after, 1000} indeed hibernates after 1000ms of " - "inactivity"]; + ssl_test_lib:check_result(Server1, ok, Client1, ok), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1). + +%%-------------------------------------------------------------------- -hibernate(suite) -> - []; +hibernate() -> + [{doc,"Check that an SSL connection that is started with option " + "{hibernate_after, 1000} indeed hibernates after 1000ms of " + "inactivity"}]. hibernate(Config) -> ClientOpts = ?config(client_opts, Config), @@ -3758,14 +2315,14 @@ hibernate(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), {Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket, {node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{hibernate_after, 1000}|ClientOpts]}]), {current_function, _} = process_info(Pid, current_function), @@ -3779,10 +2336,34 @@ hibernate(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -ssl_accept_timeout(doc) -> - ["Test ssl:ssl_accept timeout"]; -ssl_accept_timeout(suite) -> - []; +listen_socket() -> + [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}]. + +listen_socket(Config) -> + ServerOpts = ?config(server_opts, Config), + {ok, ListenSocket} = ssl:listen(0, ServerOpts), + + %% This can be a valid thing to do as + %% options are inherited by the accept socket + ok = ssl:controlling_process(ListenSocket, self()), + + {ok, _} = ssl:sockname(ListenSocket), + + {error, enotconn} = ssl:send(ListenSocket, <<"data">>), + {error, enotconn} = ssl:recv(ListenSocket, 0), + {error, enotconn} = ssl:connection_info(ListenSocket), + {error, enotconn} = ssl:peername(ListenSocket), + {error, enotconn} = ssl:peercert(ListenSocket), + {error, enotconn} = ssl:session_info(ListenSocket), + {error, enotconn} = ssl:renegotiate(ListenSocket), + {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, client_random, 256), + {error, enotconn} = ssl:shutdown(ListenSocket, read_write), + + ok = ssl:close(ListenSocket). +%%-------------------------------------------------------------------- +ssl_accept_timeout() -> + [{doc,"Test ssl:ssl_accept timeout"}]. + ssl_accept_timeout(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -3806,10 +2387,9 @@ ssl_accept_timeout(Config) -> end. %%-------------------------------------------------------------------- -ssl_recv_timeout(doc) -> - ["Test ssl:ssl_accept timeout"]; -ssl_recv_timeout(suite) -> - []; +ssl_recv_timeout() -> + [{doc,"Test ssl:ssl_accept timeout"}]. + ssl_recv_timeout(Config) -> ServerOpts = ?config(server_opts, Config), ClientOpts = ?config(client_opts, Config), @@ -3835,11 +2415,8 @@ ssl_recv_timeout(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- - -connect_twice(doc) -> - [""]; -connect_twice(suite) -> - []; +connect_twice() -> + [{doc,""}]. connect_twice(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -3849,7 +2426,7 @@ connect_twice(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{keepalive, true},{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), @@ -3857,7 +2434,7 @@ connect_twice(Config) when is_list(Config) -> ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{keepalive, true},{active, false} | ClientOpts]}]), Server ! listen, @@ -3867,11 +2444,11 @@ connect_twice(Config) when is_list(Config) -> {node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{keepalive, true},{active, false} | ClientOpts]}]), - test_server:format("Testcase ~p, Client ~p Server ~p ~n", + ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -3882,13 +2459,9 @@ connect_twice(Config) when is_list(Config) -> ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- -renegotiate_dos_mitigate_active(doc) -> - ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", - "immediately after each other"]; - -renegotiate_dos_mitigate_active(suite) -> - []; - +renegotiate_dos_mitigate_active() -> + [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"}]. renegotiate_dos_mitigate_active(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), ClientOpts = ?config(client_opts, Config), @@ -3898,7 +2471,7 @@ renegotiate_dos_mitigate_active(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), @@ -3914,13 +2487,9 @@ renegotiate_dos_mitigate_active(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -renegotiate_dos_mitigate_passive(doc) -> - ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", - "immediately after each other"]; - -renegotiate_dos_mitigate_passive(suite) -> - []; - +renegotiate_dos_mitigate_passive() -> + [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"}]. renegotiate_dos_mitigate_passive(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), ClientOpts = ?config(client_opts, Config), @@ -3930,7 +2499,7 @@ renegotiate_dos_mitigate_passive(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result, []}}, + {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), @@ -3946,8 +2515,8 @@ renegotiate_dos_mitigate_passive(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -tcp_error_propagation_in_active_mode(doc) -> - ["Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"]; +tcp_error_propagation_in_active_mode() -> + [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}]. tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -3976,11 +2545,9 @@ tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}). - %%-------------------------------------------------------------------- - -recv_error_handling(doc) -> - ["Special case of call error handling"]; +recv_error_handling() -> + [{doc,"Special case of call error handling"}]. recv_error_handling(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -4000,11 +2567,11 @@ recv_error_handling(Config) when is_list(Config) -> ssl:close(SslSocket), ssl_test_lib:check_result(Server, ok). - %%-------------------------------------------------------------------- -rizzo(doc) -> ["Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is - vunrable to Rizzo/Dungon attack"]; +rizzo() -> + [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is + vunrable to Rizzo/Dungon attack"}]. rizzo(Config) when is_list(Config) -> Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(), Y =/= rc4_128], @@ -4013,8 +2580,8 @@ rizzo(Config) when is_list(Config) -> run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_rizzo, []}). %%-------------------------------------------------------------------- -no_rizzo_rc4(doc) -> - ["Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"]; +no_rizzo_rc4() -> + [{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}]. no_rizzo_rc4(Config) when is_list(Config) -> Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(),Y == rc4_128], @@ -4024,58 +2591,124 @@ no_rizzo_rc4(Config) when is_list(Config) -> {?MODULE, send_recv_result_active_no_rizzo, []}). %%-------------------------------------------------------------------- -run_send_recv_rizzo(Ciphers, Config, Version, Mfa) -> - Result = lists:map(fun(Cipher) -> - rizzo_test(Cipher, Config, Version, Mfa) end, - Ciphers), - case lists:flatten(Result) of - [] -> - ok; - Error -> - test_server:format("Cipher suite errors: ~p~n", [Error]), - test_server:fail(cipher_suite_failed_see_test_case_log) - end. +new_server_wants_peer_cert() -> + [{doc, "Test that server configured to do client certification does" + " not reuse session without a client certificate."}]. +new_server_wants_peer_cert(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ?config(server_verification_opts, Config)], + ClientOpts = ?config(client_verification_opts, Config), -rizzo_test(Cipher, Config, Version, Mfa) -> - {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, Mfa}, - {options, [{active, true}, {ciphers, [Cipher]}, - {versions, [Version]} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, Mfa}, - {options, [{active, true} | ClientOpts]}]), - - Result = ssl_test_lib:check_result(Server, ok, Client, ok), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, [ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ClientOpts}]), + + Monitor = erlang:monitor(process, Server), ssl_test_lib:close(Server), ssl_test_lib:close(Client), - case Result of - ok -> - []; - Error -> - [{Cipher, Error}] - end. + receive + {'DOWN', Monitor, _, _, _} -> + ok + end, + + Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, VServerOpts}]), + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [ClientOpts]}]), -client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa -> - {?config(client_opts, Config), - ?config(server_opts, Config)}; -client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss -> - {?config(client_dsa_opts, Config), - ?config(server_dsa_opts, Config)}. + CertFile = proplists:get_value(certfile, ClientOpts), + [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), + + ServerMsg = {error, no_peercert}, + Sever1Msg = {ok, BinCert}, + + ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg), + + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client), + ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- -%%% Internal functions +session_cache_process_list() -> + [{doc,"Test reuse of sessions (short handshake)"}]. +session_cache_process_list(Config) when is_list(Config) -> + session_cache_process(list,Config). +%%-------------------------------------------------------------------- +session_cache_process_mnesia() -> + [{doc,"Test reuse of sessions (short handshake)"}]. +session_cache_process_mnesia(Config) when is_list(Config) -> + session_cache_process(mnesia,Config). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- send_recv_result(Socket) -> ssl:send(Socket, "Hello world"), {ok,"Hello world"} = ssl:recv(Socket, 11), ok. +tcp_send_recv_result(Socket) -> + gen_tcp:send(Socket, "Hello world"), + {ok,"Hello world"} = gen_tcp:recv(Socket, 11), + ok. + +basic_verify_test_no_close(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + {Server, Client}. + +basic_test(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). send_recv_result_timeout_client(Socket) -> {error, timeout} = ssl:recv(Socket, 11, 500), @@ -4103,17 +2736,6 @@ recv_close(Socket) -> ok end. -send_recv_result_active(Socket) -> - ssl:send(Socket, "Hello world"), - receive - {ssl, Socket, "H"} -> - receive - {ssl, Socket, "ello world"} -> - ok - end; - {ssl, Socket, "Hello world"} -> - ok - end. send_recv_result_active_rizzo(Socket) -> ssl:send(Socket, "Hello world"), @@ -4132,26 +2754,13 @@ send_recv_result_active_no_rizzo(Socket) -> ok end. -send_recv_result_active_once(Socket) -> - ssl:send(Socket, "Hello world"), - receive - {ssl, Socket, "H"} -> - ssl:setopts(Socket, [{active, once}]), - receive - {ssl, Socket, "ello world"} -> - ok - end; - {ssl, Socket, "Hello world"} -> - ok - end. - result_ok(_Socket) -> ok. renegotiate(Socket, Data) -> - test_server:format("Renegotiating ~n", []), + ct:print("Renegotiating ~n", []), Result = ssl:renegotiate(Socket), - test_server:format("Result ~p~n", [Result]), + ct:print("Result ~p~n", [Result]), ssl:send(Socket, Data), case Result of ok -> @@ -4162,7 +2771,7 @@ renegotiate(Socket, Data) -> renegotiate_reuse_session(Socket, Data) -> %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), renegotiate(Socket, Data). renegotiate_immediately(Socket) -> @@ -4178,9 +2787,9 @@ renegotiate_immediately(Socket) -> end, ok = ssl:renegotiate(Socket), {error, renegotiation_rejected} = ssl:renegotiate(Socket), - test_server:sleep(?RENEGOTIATION_DISABLE_TIME +1), + ct:sleep(?RENEGOTIATION_DISABLE_TIME +1), ok = ssl:renegotiate(Socket), - test_server:format("Renegotiated again"), + ct:print("Renegotiated again"), ssl:send(Socket, "Hello world"), ok. @@ -4199,27 +2808,11 @@ new_config(PrivDir, ServerOpts0) -> ServerOpts = proplists:delete(keyfile, ServerOpts2), {ok, PEM} = file:read_file(NewCaCertFile), - test_server:format("CA file content: ~p~n", [public_key:pem_decode(PEM)]), + ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]), [{cacertfile, NewCaCertFile}, {certfile, NewCertFile}, {keyfile, NewKeyFile} | ServerOpts]. -session_cache_process_list(doc) -> - ["Test reuse of sessions (short handshake)"]; - -session_cache_process_list(suite) -> - []; -session_cache_process_list(Config) when is_list(Config) -> - session_cache_process(list,Config). - -session_cache_process_mnesia(doc) -> - ["Test reuse of sessions (short handshake)"]; - -session_cache_process_mnesia(suite) -> - []; -session_cache_process_mnesia(Config) when is_list(Config) -> - session_cache_process(mnesia,Config). - session_cache_process(_Type,Config) when is_list(Config) -> reuse_session(Config). @@ -4361,9 +2954,9 @@ erlang_ssl_receive(Socket, Data) -> io:format("Received ~p~n",[Byte]), erlang_ssl_receive(Socket, tl(Data)); Other -> - test_server:fail({unexpected_message, Other}) - after ?SLEEP * 3 -> - test_server:fail({did_not_get, Data}) + ct:fail({unexpected_message, Other}) + after ?SLEEP * 3 * test_server:timetrap_scale_factor() -> + ct:fail({did_not_get, Data}) end. receive_msg(_) -> @@ -4371,3 +2964,222 @@ receive_msg(_) -> Msg -> Msg end. + +controlling_process_result(Socket, Pid, Msg) -> + ok = ssl:controlling_process(Socket, Pid), + %% Make sure other side has evaluated controlling_process + %% before message is sent + ct:sleep(?SLEEP), + ssl:send(Socket, Msg), + no_result_msg. + +receive_s_rizzo_duong_beast() -> + receive + {ssl, _, "erver hello"} -> + receive + {ssl, _, "C"} -> + receive + {ssl, _, "lient hello"} -> + ok + end + end + end. +receive_c_rizzo_duong_beast() -> + receive + {ssl, _, "lient hello"} -> + receive + {ssl, _, "S"} -> + receive + {ssl, _, "erver hello"} -> + ok + end + end + end. + +controller_dies_result(_Socket, _Pid, _Msg) -> + receive Result -> Result end. + +get_close(Pid, Where) -> + receive + {'EXIT', Pid, _Reason} -> + receive + {_, {ssl_closed, Socket}} -> + ct:print("Socket closed ~p~n",[Socket]); + Unexpected -> + ct:print("Unexpected ~p~n",[Unexpected]), + ct:fail({line, ?LINE-1}) + after 5000 -> + ct:fail({timeout, {line, ?LINE, Where}}) + end; + Unexpected -> + ct:print("Unexpected ~p~n",[Unexpected]), + ct:fail({line, ?LINE-1}) + after 5000 -> + ct:fail({timeout, {line, ?LINE, Where}}) + end. + +run_send_recv_rizzo(Ciphers, Config, Version, Mfa) -> + Result = lists:map(fun(Cipher) -> + rizzo_test(Cipher, Config, Version, Mfa) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + ct:print("Cipher suite errors: ~p~n", [Error]), + ct:fail(cipher_suite_failed_see_test_case_log) + end. + +rizzo_test(Cipher, Config, Version, Mfa) -> + {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, Mfa}, + {options, [{active, true}, {ciphers, [Cipher]}, + {versions, [Version]} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, Mfa}, + {options, [{active, true} | ClientOpts]}]), + + Result = ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + case Result of + ok -> + []; + Error -> + [{Cipher, Error}] + end. + +client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; +client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss -> + {?config(client_dsa_opts, Config), + ?config(server_dsa_opts, Config)}. + +run_suites(Ciphers, Version, Config, Type) -> + {ClientOpts, ServerOpts} = + case Type of + rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; + dsa -> + {?config(client_opts, Config), + ?config(server_dsa_opts, Config)}; + anonymous -> + %% No certs in opts! + {?config(client_opts, Config), + ?config(server_anon, Config)} + end, + + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + ct:print("Cipher suite errors: ~p~n", [Error]), + ct:fail(cipher_suite_failed_see_test_case_log) + end. + +erlang_cipher_suite(Suite) when is_list(Suite)-> + ssl:suite_definition(ssl_cipher:openssl_suite(Suite)); +erlang_cipher_suite(Suite) -> + Suite. + +cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> + %% process_flag(trap_exit, true), + ct:print("Testing CipherSuite ~p~n", [CipherSuite]), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + ErlangCipherSuite = erlang_cipher_suite(CipherSuite), + + ConnectionInfo = {ok, {Version, ErlangCipherSuite}}, + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, + {options, + [{ciphers,[CipherSuite]} | + ClientOpts]}]), + + Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + + case Result of + ok -> + []; + Error -> + [{ErlangCipherSuite, Error}] + end. + +connection_info_result(Socket) -> + ssl:connection_info(Socket). + +connect_dist_s(S) -> + Msg = term_to_binary({erlang,term}), + ok = ssl:send(S, Msg). + +connect_dist_c(S) -> + Test = binary_to_list(term_to_binary({erlang,term})), + {ok, Test} = ssl:recv(S, 0, 10000), + ok. + + %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast +treashold(N, {3,0}) -> + (N div 2) + 1; +treashold(N, {3,1}) -> + (N div 2) + 1; +treashold(N, _) -> + N + 1. + +get_invalid_inet_option(Socket) -> + {error, {eoptions, {inet_option, foo, _}}} = ssl:getopts(Socket, [foo]), + ok. + +shutdown_result(Socket, server) -> + ssl:send(Socket, "Hej"), + ssl:shutdown(Socket, write), + {ok, "Hej hopp"} = ssl:recv(Socket, 8), + ok; + +shutdown_result(Socket, client) -> + {ok, "Hej"} = ssl:recv(Socket, 3), + ssl:send(Socket, "Hej hopp"), + ssl:shutdown(Socket, write), + ok. + +shutdown_write_result(Socket, server) -> + ct:sleep(?SLEEP), + ssl:shutdown(Socket, write); +shutdown_write_result(Socket, client) -> + ssl:recv(Socket, 0). + +dummy(_Socket) -> + %% Should not happen as the ssl connection will not be established + %% due to fatal handshake failiure + exit(kill). + +shutdown_both_result(Socket, server) -> + ct:sleep(?SLEEP), + ssl:shutdown(Socket, read_write); +shutdown_both_result(Socket, client) -> + ssl:recv(Socket, 0). + +peername_result(S) -> + ssl:peername(S). diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl new file mode 100644 index 0000000000..86e1d47be7 --- /dev/null +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -0,0 +1,978 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012-2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/.2 +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_certificate_verify_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +-include("ssl_internal.hrl"). +-include("ssl_alert.hrl"). +-include("ssl_internal.hrl"). +-include("ssl_record.hrl"). +-include("ssl_handshake.hrl"). + +-define(LONG_TIMEOUT, 600000). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [{group, active}, + {group, passive}, + {group, active_once}, + {group, error_handling}]. + + +groups() -> + [{active, [], tests()}, + {active_once, [], tests()}, + {passive, [], tests()}, + {error_handling, [],error_handling_tests()}]. + +tests() -> + [server_verify_peer, + server_verify_none, + server_require_peer_cert_ok, + server_require_peer_cert_fail, + verify_fun_always_run_client, + verify_fun_always_run_server, + cert_expired, + invalid_signature_client, + invalid_signature_server, + extended_key_usage_verify_peer, + extended_key_usage_verify_none]. + +error_handling_tests()-> + [client_with_cert_cipher_suites_handshake, + server_verify_no_cacerts, + unknown_server_ca_fail, + unknown_server_ca_accept_verify_none, + unknown_server_ca_accept_verify_peer, + unknown_server_ca_accept_backwardscompatibility, + no_authority_key_identifier]. + +init_per_suite(Config0) -> + Dog = ct:timetrap(?LONG_TIMEOUT *2), + catch crypto:stop(), + try crypto:start() of + ok -> + application:start(public_key), + application:start(ssl), + %% make rsa certs using oppenssl + Result = + (catch make_certs:all(?config(data_dir, Config0), + ?config(priv_dir, Config0))), + ct:print("Make certs ~p~n", [Result]), + + Config1 = ssl_test_lib:make_dsa_cert(Config0), + Config = ssl_test_lib:cert_options(Config1), + [{watchdog, Dog} | Config] + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(active, Config) -> + [{active, true}, {receive_function, send_recv_result_active} | Config]; +init_per_group(active_once, Config) -> + [{active, once}, {receive_function, send_recv_result_active_once} | Config]; +init_per_group(passive, Config) -> + [{active, false}, {receive_function, send_recv_result} | Config]; +init_per_group(_, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +server_verify_peer() -> + [{doc,"Test server option verify_peer"}]. +server_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active}, {verify, verify_peer} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +server_verify_none() -> + [{doc,"Test server option verify_none"}]. + +server_verify_none(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active}, {verify, verify_none} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +server_verify_client_once() -> + [{doc,"Test server option verify_client_once"}]. + +server_verify_client_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active}, {verify, verify_peer}, + {verify_client_once, true} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client0, ok), + Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + ssl_test_lib:close(Client0), + Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, result_ok, []}}, + {options, [{active, Active} | ClientOpts]}]), + + ssl_test_lib:check_result(Client1, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client1). + +%%-------------------------------------------------------------------- + +server_require_peer_cert_ok() -> + [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}]. + +server_require_peer_cert_ok(Config) when is_list(Config) -> + ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ?config(server_verification_opts, Config)], + ClientOpts = ?config(client_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib,send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +server_require_peer_cert_fail() -> + [{doc,"Test server option fail_if_no_peer_cert when peer doesn't send cert"}]. + +server_require_peer_cert_fail(Config) when is_list(Config) -> + ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ?config(server_verification_opts, Config)], + BadClientOpts = ?config(client_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{active, false} | ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{active, false} | BadClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, {essl, "handshake failure"}}, + Client, {error, {essl, "handshake failure"}}). + + +%%-------------------------------------------------------------------- +verify_fun_always_run_client() -> + [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}]. + +verify_fun_always_run_client(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + %% If user verify fun is called correctly we fail the connection. + %% otherwise we can not tell this case apart form where we miss + %% to call users verify fun + FunAndState = {fun(_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, [ChainLen]) -> + {valid, [ChainLen + 1]}; + (_, valid_peer, [2]) -> + {fail, "verify_fun_was_always_run"}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, [0]}, + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} + | ClientOpts]}]), + %% Server error may be {essl,"handshake failure"} or closed depending on timing + %% this is not a bug it is a circumstance of how tcp works! + receive + {Server, ServerError} -> + ct:print("Server Error ~p~n", [ServerError]) + end, + + ssl_test_lib:check_result(Client, {error, {essl, "handshake failure"}}). + +%%-------------------------------------------------------------------- +verify_fun_always_run_server() -> + [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}]. +verify_fun_always_run_server(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + %% If user verify fun is called correctly we fail the connection. + %% otherwise we can not tell this case apart form where we miss + %% to call users verify fun + FunAndState = {fun(_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, [ChainLen]) -> + {valid, [ChainLen + 1]}; + (_, valid_peer, [2]) -> + {fail, "verify_fun_was_always_run"}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, [0]}, + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer} + | ClientOpts]}]), + + %% Client error may be {essl, "handshake failure" } or closed depending on timing + %% this is not a bug it is a circumstance of how tcp works! + receive + {Client, ClientError} -> + ct:print("Client Error ~p~n", [ClientError]) + end, + + ssl_test_lib:check_result(Server, {error, {essl, "handshake failure"}}). + +%%-------------------------------------------------------------------- + +client_verify_none_passive() -> + [{doc,"Test client option verify_none"}]. + +client_verify_none_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false}, + {verify, verify_none} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +cert_expired() -> + [{doc,"Test server with expired certificate"}]. + +cert_expired(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + + {Year, Month, Day} = date(), + {Hours, Min, Sec} = time(), + NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2, + two_digits_str(Month), + two_digits_str(Day), + two_digits_str(Hours), + two_digits_str(Min), + two_digits_str(Sec)])), + NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1, + two_digits_str(Month), + two_digits_str(Day), + two_digits_str(Hours), + two_digits_str(Min), + two_digits_str(Sec)])), + NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}}, + + ct:print("Validity: ~p ~n NewValidity: ~p ~n", + [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]), + + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity}, + NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, {essl, "certificate expired"}}, + Client, {error, {essl, "certificate expired"}}). + +two_digits_str(N) when N < 10 -> + lists:flatten(io_lib:format("0~p", [N])); +two_digits_str(N) -> + lists:flatten(io_lib:format("~p", [N])). + +%%-------------------------------------------------------------------- + +client_verify_none_active() -> + [{doc,"Test client option verify_none"}]. + +client_verify_none_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, [{active, true} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, [{active, true}, + {verify, verify_none} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +client_verify_none_active_once() -> + [{doc,"Test client option verify_none"}]. + +client_verify_none_active_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, [{active, once} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active_once, + []}}, + {options, [{active, once}, + {verify, verify_none} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +extended_key_usage_verify_peer() -> + [{doc,"Test cert that has a critical extended_key_usage extension in verify_peer mode"}]. + +extended_key_usage_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, + NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = + [ServerExtKeyUsageExt | + ServerExtensions]}, + NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, + NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = + [ClientExtKeyUsageExt | + ClientExtensions]}, + NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_peer}, {active, Active} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_peer}, {active, Active} | + NewClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +extended_key_usage_verify_none() -> + [{doc,"Test cert that has a critical extended_key_usage extension in verify_none mode"}]. + +extended_key_usage_verify_none(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, + NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = + [ServerExtKeyUsageExt | + ServerExtensions]}, + NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, + NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = + [ClientExtKeyUsageExt | + ClientExtensions]}, + NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +no_authority_key_identifier() -> + [{doc, "Test cert that does not have authorityKeyIdentifier extension" + " but are present in trusted certs db."}]. + +no_authority_key_identifier(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + CertFile = proplists:get_value(certfile, ServerOpts), + NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, + NewExtensions = delete_authority_key_extension(Extensions, []), + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions}, + + ct:print("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), + + NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +delete_authority_key_extension([], Acc) -> + lists:reverse(Acc); +delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest], + Acc) -> + delete_authority_key_extension(Rest, Acc); +delete_authority_key_extension([Head | Rest], Acc) -> + delete_authority_key_extension(Rest, [Head | Acc]). + +%%-------------------------------------------------------------------- + +invalid_signature_server() -> + [{doc,"Test client with invalid signature"}]. + +invalid_signature_server(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "server/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + tcp_delivery_workaround(Server, {error, {essl, "bad certificate"}}, + Client, {error, {essl, "bad certificate"}}). + +%%-------------------------------------------------------------------- + +invalid_signature_client() -> + [{doc,"Test server with invalid signature"}]. + +invalid_signature_client(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "client/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{verify, verify_peer} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, NewClientOpts}]), + + tcp_delivery_workaround(Server, {error, {essl, "bad certificate"}}, + Client, {error, {essl, "bad certificate"}}). + + +%%-------------------------------------------------------------------- + +client_with_cert_cipher_suites_handshake() -> + [{doc, "Test that client with a certificate without keyEncipherment usage " + " extension can connect to a server with restricted cipher suites "}]. +client_with_cert_cipher_suites_handshake(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts_digital_signature_only, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, [{active, true}, + {ciphers, ssl_test_lib:rsa_non_signed_suites()} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, [{active, true} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +server_verify_no_cacerts() -> + [{doc,"Test server must have cacerts if it wants to verify client"}]. +server_verify_no_cacerts(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{verify, verify_peer} + | ServerOpts]}]), + + ssl_test_lib:check_result(Server, {error, {eoptions, {cacertfile, ""}}}). + + +%%-------------------------------------------------------------------- +unknown_server_ca_fail() -> + [{doc,"Test that the client fails if the ca is unknown in verify_peer mode"}]. +unknown_server_ca_fail(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, [test_to_update_user_state | UserState]}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, []}, + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, {essl, "unknown ca"}}, + Client, {error, {essl, "unknown ca"}}). + +%%-------------------------------------------------------------------- +unknown_server_ca_accept_verify_none() -> + [{doc,"Test that the client succeds if the ca is unknown in verify_none mode"}]. +unknown_server_ca_accept_verify_none(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, + [{verify, verify_none}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +unknown_server_ca_accept_verify_peer() -> + [{doc, "Test that the client succeds if the ca is unknown in verify_peer mode" + " with a verify_fun that accepts the unknown ca error"}]. +unknown_server_ca_accept_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, []}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +unknown_server_ca_accept_backwardscompatibility() -> + [{doc,"Test that old style verify_funs will work"}]. +unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; + (Other, Acc) -> [Other | Acc] + end, + VerifyFun = + fun(ErrorList) -> + case lists:foldl(AcceptBadCa, [], ErrorList) of + [] -> true; + [_|_] -> false + end + end, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, VerifyFun}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- + +tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> + receive + {Server, ServerMsg} -> + client_msg(Client, ClientMsg); + {Client, ClientMsg} -> + server_msg(Server, ServerMsg); + {Client, {error,closed}} -> + server_msg(Server, ServerMsg); + {Server, {error,closed}} -> + client_msg(Client, ClientMsg) + end. + +client_msg(Client, ClientMsg) -> + receive + {Client, ClientMsg} -> + ok; + {Client, {error,closed}} -> + ct:print("client got close"), + ok; + {Client, {error, Reason}} -> + ct:print("client got econnaborted: ~p", [Reason]), + ok; + Unexpected -> + ct:fail(Unexpected) + end. +server_msg(Server, ServerMsg) -> + receive + {Server, ServerMsg} -> + ok; + {Server, {error,closed}} -> + ct:print("server got close"), + ok; + {Server, {error, Reason}} -> + ct:print("server got econnaborted: ~p", [Reason]), + ok; + Unexpected -> + ct:fail(Unexpected) + end. diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl index ea1d9dc90c..9869812e6e 100644 --- a/lib/ssl/test/ssl_cipher_SUITE.erl +++ b/lib/ssl/test/ssl_cipher_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,16 +31,18 @@ -define(TIMEOUT, 600000). -%% Test server callback functions %%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initialization before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. +%% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [aes_decipher_good, aes_decipher_good_tls11, aes_decipher_fail, aes_decipher_fail_tls11]. + +groups() -> + []. + init_per_suite(Config) -> try crypto:start() of ok -> @@ -48,81 +50,30 @@ init_per_suite(Config) -> catch _:_ -> {skip, "Crypto did not start"} end. -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- + end_per_suite(_Config) -> ssl:stop(), application:stop(crypto). -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%% Description: Initialization before each test case -%%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case -%%-------------------------------------------------------------------- -end_per_testcase(_TestCase, Config) -> - Dog = ?config(watchdog, Config), - case Dog of - undefined -> - ok; - _ -> - test_server:timetrap_cancel(Dog) - end. - -%%-------------------------------------------------------------------- -%% Function: all(Clause) -> TestCases -%% Clause - atom() - suite | doc -%% TestCases - [Case] -%% Case - atom() -%% Name of a test case. -%% Description: Returns a list of all test cases in this test suite -%%-------------------------------------------------------------------- -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [aes_decipher_good, aes_decipher_good_tls11, aes_decipher_fail, aes_decipher_fail_tls11]. - -groups() -> - []. - init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ct:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. -%% Test cases starts here. -%%-------------------------------------------------------------------- -aes_decipher_good(doc) -> - ["Decipher a known cryptotext."]; +end_per_testcase(_TestCase, Config) -> + Config. -aes_decipher_good(suite) -> - []; +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +aes_decipher_good() -> + [{doc,"Decipher a known cryptotext."}]. aes_decipher_good(Config) when is_list(Config) -> HashSz = 32, @@ -142,11 +93,8 @@ aes_decipher_good(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -aes_decipher_good_tls11(doc) -> - ["Decipher a known TLS 1.1 cryptotext."]; - -aes_decipher_good_tls11(suite) -> - []; +aes_decipher_good_tls11() -> + [{doc,"Decipher a known TLS 1.1 cryptotext."}]. %% the fragment is actuall a TLS 1.1 record, with %% Version = TLS 1.1, we get the correct NextIV in #cipher_state @@ -169,11 +117,8 @@ aes_decipher_good_tls11(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -aes_decipher_fail(doc) -> - ["Decipher a known cryptotext."]; - -aes_decipher_fail(suite) -> - []; +aes_decipher_fail() -> + [{doc,"Decipher a known cryptotext."}]. %% same as above, last byte of key replaced aes_decipher_fail(Config) when is_list(Config) -> @@ -196,11 +141,8 @@ aes_decipher_fail(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -aes_decipher_fail_tls11(doc) -> - ["Decipher a known TLS 1.1 cryptotext."]; - -aes_decipher_fail_tls11(suite) -> - []; +aes_decipher_fail_tls11() -> + [{doc,"Decipher a known TLS 1.1 cryptotext."}]. %% same as above, last byte of key replaced %% stricter padding checks in TLS 1.1 mean we get an alert instead @@ -213,9 +155,11 @@ aes_decipher_fail_tls11(Config) when is_list(Config) -> 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, Version = {3,2}, - #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), + #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = + ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), Version1 = {3,3}, - #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1), + #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = + ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1), ok. %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 818f7f1897..7bfd678f4b 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ -module(ssl_dist_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -35,7 +35,10 @@ nodename} ). -%% Test server callback functions +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -54,6 +57,7 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config0) -> try crypto:start() of ok -> + %% Currently no ct function avilable for is_cover! case test_server:is_cover() of false -> Config = add_ssl_opts_config(Config0), @@ -98,11 +102,13 @@ common_end(_, Config) -> Dog = ?config(watchdog, Config), ?t:timetrap_cancel(Dog), ok. + %%-------------------------------------------------------------------- -%% Test cases starts here. +%% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- -basic(doc) -> - ["Test that two nodes can connect via ssl distribution"]; + +basic() -> + [{doc,"Test that two nodes can connect via ssl distribution"}]. basic(Config) when is_list(Config) -> NH1 = start_ssl_node(Config), Node1 = NH1#node_handle.nodename, @@ -162,8 +168,8 @@ basic(Config) when is_list(Config) -> success(Config). %%-------------------------------------------------------------------- -payload(doc) -> - ["Test that send a lot of data between the ssl distributed noes"]; +payload() -> + [{doc,"Test that send a lot of data between the ssl distributed noes"}]. payload(Config) when is_list(Config) -> NH1 = start_ssl_node(Config), Node1 = NH1#node_handle.nodename, @@ -204,8 +210,8 @@ payload(Config) when is_list(Config) -> stop_ssl_node(NH2), success(Config). %%-------------------------------------------------------------------- -plain_options(doc) -> - ["Test specifying additional options"]; +plain_options() -> + [{doc,"Test specifying additional options"}]. plain_options(Config) when is_list(Config) -> DistOpts = "-ssl_dist_opt server_secure_renegotiate true " "client_secure_renegotiate true " @@ -228,8 +234,8 @@ plain_options(Config) when is_list(Config) -> stop_ssl_node(NH2), success(Config). %%-------------------------------------------------------------------- -plain_verify_options(doc) -> - ["Test specifying additional options"]; +plain_verify_options() -> + [{doc,"Test specifying additional options"}]. plain_verify_options(Config) when is_list(Config) -> DistOpts = "-ssl_dist_opt server_secure_renegotiate true " "client_secure_renegotiate true " @@ -251,7 +257,7 @@ plain_verify_options(Config) when is_list(Config) -> success(Config). %%-------------------------------------------------------------------- -%%% Internal functions +%%% Internal functions ----------------------------------------------- %%-------------------------------------------------------------------- %% ssl_node side api diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index 363a0be594..aff0e0fbbc 100644 --- a/lib/ssl/test/ssl_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,6 +27,9 @@ -include("ssl_internal.hrl"). -include("ssl_handshake.hrl"). +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [ @@ -34,6 +37,9 @@ all() -> [ decode_single_hello_extension_correctly, decode_unknown_hello_extension_correctly]. +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- decode_hello_handshake(_Config) -> HelloPacket = <<16#02, 16#00, 16#00, 16#44, 16#03, 16#03, 16#4e, 16#7f, 16#c1, 16#03, 16#35, diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl new file mode 100644 index 0000000000..4e848095a5 --- /dev/null +++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl @@ -0,0 +1,312 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_npn_handshake_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}]. + +groups() -> + [ + {'tlsv1.2', [], next_protocol_tests()}, + {'tlsv1.1', [], next_protocol_tests()}, + {'tlsv1', [], next_protocol_tests()}, + {'sslv3', [], next_protocol_not_supported()} + ]. + +next_protocol_tests() -> + [validate_empty_protocols_are_not_allowed, + validate_empty_advertisement_list_is_allowed, + validate_advertisement_must_be_a_binary_list, + validate_client_protocols_must_be_a_tuple, + normal_npn_handshake_server_preference, + normal_npn_handshake_client_preference, + fallback_npn_handshake, + fallback_npn_handshake_server_preference, + client_negotiate_server_does_not_support, + no_client_negotiate_but_server_supports_npn, + renegotiate_from_client_after_npn_handshake + ]. + +next_protocol_not_supported() -> + [npn_not_supported_client, + npn_not_supported_server + ]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + application:start(public_key), + ssl:start(), + Result = + (catch make_certs:all(?config(data_dir, Config), + ?config(priv_dir, Config))), + ct:print("Make certs ~p~n", [Result]), + ssl_test_lib:cert_options(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, "Missing crypto support"} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +validate_empty_protocols_are_not_allowed(Config) when is_list(Config) -> + {error, {eoptions, {next_protocols_advertised, {invalid_protocol, <<>>}}}} + = (catch ssl:listen(9443, + [{next_protocols_advertised, [<<"foo/1">>, <<"">>]}])), + {error, {eoptions, {client_preferred_next_protocols, {invalid_protocol, <<>>}}}} + = (catch ssl:connect({127,0,0,1}, 9443, + [{client_preferred_next_protocols, + {client, [<<"foo/1">>, <<"">>], <<"foox/1">>}}], infinity)), + Option = {client_preferred_next_protocols, {invalid_protocol, <<"">>}}, + {error, {eoptions, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option], infinity)). + +%-------------------------------------------------------------------------------- + +validate_empty_advertisement_list_is_allowed(Config) when is_list(Config) -> + Option = {next_protocols_advertised, []}, + {ok, Socket} = ssl:listen(0, [Option]), + ssl:close(Socket). +%-------------------------------------------------------------------------------- + +validate_advertisement_must_be_a_binary_list(Config) when is_list(Config) -> + Option = {next_protocols_advertised, blah}, + {error, {eoptions, Option}} = (catch ssl:listen(9443, [Option])). +%-------------------------------------------------------------------------------- + +validate_client_protocols_must_be_a_tuple(Config) when is_list(Config) -> + Option = {client_preferred_next_protocols, [<<"foo/1">>]}, + {error, {eoptions, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option])). + +%-------------------------------------------------------------------------------- + +normal_npn_handshake_server_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, + {server, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- + +normal_npn_handshake_client_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, + {client, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.0">>}). + +%-------------------------------------------------------------------------------- + +fallback_npn_handshake(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- + +fallback_npn_handshake_server_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {server, [<<"spdy/2">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). + +%-------------------------------------------------------------------------------- + +no_client_negotiate_but_server_supports_npn(Config) when is_list(Config) -> + run_npn_handshake(Config, + [], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {error, next_protocol_not_negotiated}). +%-------------------------------------------------------------------------------- + + +client_negotiate_server_does_not_support(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], + [], + {error, next_protocol_not_negotiated}). + +%-------------------------------------------------------------------------------- +renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) -> + Data = "hello world", + + ClientOpts0 = ?config(client_opts, Config), + ClientOpts = [{client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, + ServerOpts0 = ?config(server_opts, Config), + ServerOpts = [{next_protocols_advertised, + [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, + ExpectedProtocol = {ok, <<"http/1.0">>}, + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, ssl_receive_and_assert_npn, [ExpectedProtocol, Data]}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, assert_npn_and_renegotiate_and_send_data, [ExpectedProtocol, Data]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + +%-------------------------------------------------------------------------------- +npn_not_supported_client(Config) when is_list(Config) -> + ClientOpts0 = ?config(client_opts, Config), + PrefProtocols = {client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}, + ClientOpts = [PrefProtocols] ++ ClientOpts0, + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, + {port, 8888}, {host, Hostname}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, {error, + {eoptions, + {not_supported_in_sslv3, PrefProtocols}}}). + +%-------------------------------------------------------------------------------- +npn_not_supported_server(Config) when is_list(Config)-> + ServerOpts0 = ?config(server_opts, Config), + AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, + ServerOpts = [AdvProtocols] ++ ServerOpts0, + + {error, {eoptions, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> + Data = "hello world", + + ClientOpts0 = ?config(client_opts, Config), + ClientOpts = ClientExtraOpts ++ ClientOpts0, + ServerOpts0 = ?config(server_opts, Config), + ServerOpts = ServerExtraOpts ++ ServerOpts0, + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, ssl_receive_and_assert_npn, [ExpectedProtocol, Data]}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, ssl_send_and_assert_npn, [ExpectedProtocol, Data]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + + +assert_npn(Socket, Protocol) -> + ct:print("Negotiated Protocol ~p, Expecting: ~p ~n", + [ssl:negotiated_next_protocol(Socket), Protocol]), + Protocol = ssl:negotiated_next_protocol(Socket). + +assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) -> + assert_npn(Socket, Protocol), + ct:print("Renegotiating ~n", []), + ok = ssl:renegotiate(Socket), + ssl:send(Socket, Data), + assert_npn(Socket, Protocol), + ok. + +ssl_send_and_assert_npn(Socket, Protocol, Data) -> + assert_npn(Socket, Protocol), + ssl_send(Socket, Data). + +ssl_receive_and_assert_npn(Socket, Protocol, Data) -> + assert_npn(Socket, Protocol), + ssl_receive(Socket, Data). + +ssl_send(Socket, Data) -> + ct:print("Connection info: ~p~n", + [ssl:connection_info(Socket)]), + ssl:send(Socket, Data). + +ssl_receive(Socket, Data) -> + ssl_receive(Socket, Data, []). + +ssl_receive(Socket, Data, Buffer) -> + ct:print("Connection info: ~p~n", + [ssl:connection_info(Socket)]), + receive + {ssl, Socket, MoreData} -> + ct:print("Received ~p~n",[MoreData]), + NewBuffer = Buffer ++ MoreData, + case NewBuffer of + Data -> + ssl:send(Socket, "Got it"), + ok; + _ -> + ssl_receive(Socket, Data, NewBuffer) + end; + Other -> + ct:fail({unexpected_message, Other}) + after 4000 -> + ct:fail({did_not_get, Data}) + end. + + +connection_info_result(Socket) -> + ssl:connection_info(Socket). diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl new file mode 100644 index 0000000000..72768bcb55 --- /dev/null +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -0,0 +1,129 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssl_npn_hello_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include("ssl_handshake.hrl"). +-include("ssl_record.hrl"). +-include_lib("common_test/include/ct.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [encode_and_decode_npn_client_hello_test, + encode_and_decode_npn_server_hello_test, + encode_and_decode_client_hello_test, + encode_and_decode_server_hello_test, + create_server_hello_with_advertised_protocols_test, + create_server_hello_with_no_advertised_protocols_test]. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +encode_and_decode_client_hello_test(_Config) -> + HandShakeData = create_client_handshake(undefined), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + {[{DecodedHandshakeMessage, _Raw}], _} = + ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>), + NextProtocolNegotiation = DecodedHandshakeMessage#client_hello.next_protocol_negotiation, + NextProtocolNegotiation = undefined. +%%-------------------------------------------------------------------- +encode_and_decode_npn_client_hello_test(_Config) -> + HandShakeData = create_client_handshake(#next_protocol_negotiation{extension_data = <<>>}), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + {[{DecodedHandshakeMessage, _Raw}], _} = + ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>), + NextProtocolNegotiation = DecodedHandshakeMessage#client_hello.next_protocol_negotiation, + NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<>>}. +%%-------------------------------------------------------------------- +encode_and_decode_server_hello_test(_Config) -> + HandShakeData = create_server_handshake(undefined), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + {[{DecodedHandshakeMessage, _Raw}], _} = + ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>), + NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation, + NextProtocolNegotiation = undefined. +%%-------------------------------------------------------------------- +encode_and_decode_npn_server_hello_test(_Config) -> + HandShakeData = create_server_handshake(#next_protocol_negotiation{extension_data = <<6, "spdy/2">>}), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + {[{DecodedHandshakeMessage, _Raw}], _} = + ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>), + NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation, + ct:print("~p ~n", [NextProtocolNegotiation]), + NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}. + +%%-------------------------------------------------------------------- +create_server_hello_with_no_advertised_protocols_test(_Config) -> + Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined), + undefined = Hello#server_hello.next_protocol_negotiation. +%%-------------------------------------------------------------------- +create_server_hello_with_advertised_protocols_test(_Config) -> + Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), + false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]), + #next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} = + Hello#server_hello.next_protocol_negotiation. +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +create_client_handshake(Npn) -> + ssl_handshake:encode_handshake(#client_hello{ + client_version = {1, 2}, + random = <<1:256>>, + session_id = <<>>, + cipher_suites = "", + compression_methods = "", + next_protocol_negotiation = Npn, + renegotiation_info = #renegotiation_info{} + }, vsn). + +create_server_handshake(Npn) -> + ssl_handshake:encode_handshake(#server_hello{ + server_version = {1, 2}, + random = <<1:256>>, + session_id = <<>>, + cipher_suite = <<1,2>>, + compression_method = 1, + next_protocol_negotiation = Npn, + renegotiation_info = #renegotiation_info{} + }, vsn). + +create_connection_states() -> + #connection_states{ + pending_read = #connection_state{ + security_parameters = #security_parameters{ + server_random = <<1:256>>, + compression_algorithm = 1, + cipher_suite = <<1, 2>> + } + }, + + current_read = #connection_state { + secure_renegotiation = false + } + }. diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 8ce80cb725..158c40e372 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,84 +41,10 @@ -define(MANY, 1000). -define(SOME, 50). - -%% Test server callback functions %%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initialization before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. +%% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- -init_per_suite(Config) -> - catch crypto:stop(), - try crypto:start() of - ok -> - application:start(public_key), - ssl:start(), - Result = - (catch make_certs:all(?config(data_dir, Config), - ?config(priv_dir, Config))), - test_server:format("Make certs ~p~n", [Result]), - ssl_test_lib:cert_options(Config) - catch _:_ -> - {skip, "Crypto did not start"} - end. -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto). -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%% Description: Initialization before each test case -%%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case -%%-------------------------------------------------------------------- -end_per_testcase(_TestCase, Config) -> - Dog = ?config(watchdog, Config), - case Dog of - undefined -> - ok; - _ -> - test_server:timetrap_cancel(Dog) - end. - -%%-------------------------------------------------------------------- -%% Function: all(Clause) -> TestCases -%% Clause - atom() - suite | doc -%% TestCases - [Case] -%% Case - atom() -%% Name of a test case. -%% Description: Returns a list of all test cases in this test suite -%%-------------------------------------------------------------------- suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -129,12 +55,6 @@ all() -> {group, 'sslv3'} ]. -groups() -> - [{'tlsv1.2', [], packet_tests()}, - {'tlsv1.1', [], packet_tests()}, - {'tlsv1', [], packet_tests()}, - {'sslv3', [], packet_tests()}]. - packet_tests() -> active_packet_tests() ++ active_once_packet_tests() ++ passive_packet_tests() ++ [packet_send_to_large, @@ -208,6 +128,24 @@ active_packet_tests() -> header_decode_two_bytes_one_sent_active ]. +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + application:start(public_key), + ssl:start(), + Result = + (catch make_certs:all(?config(data_dir, Config), + ?config(priv_dir, Config))), + ct:print("Make certs ~p~n", [Result]), + ssl_test_lib:cert_options(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). init_per_group(GroupName, Config) -> case ssl_test_lib:is_tls_version(GroupName) of @@ -228,1032 +166,262 @@ init_per_group(GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ct:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. -%% Test cases starts here. -%%-------------------------------------------------------------------- -packet_raw_passive_many_small(doc) -> - ["Test packet option {packet, raw} in passive mode."]; - -packet_raw_passive_many_small(suite) -> - []; -packet_raw_passive_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "Packet option is {packet, raw}", +end_per_testcase(_TestCase, Config) -> + Config. - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_raw, [Data, ?MANY]}}, - {options, - [{active, false}, - {packet, raw} | - ClientOpts]}]), +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- - ssl_test_lib:check_result(Client, ok), +packet_raw_passive_many_small() -> + [{doc,"Test packet option {packet, raw} in passive mode."}]. - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). +packet_raw_passive_many_small(Config) when is_list(Config) -> + Data = "Packet option is {packet, raw}", + packet(Config, Data, send, passive_recv_packet, ?MANY, raw, false). %%-------------------------------------------------------------------- -packet_raw_passive_some_big(doc) -> - ["Test packet option {packet, raw} in passive mode."]; - -packet_raw_passive_some_big(suite) -> - []; - -packet_raw_passive_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_raw_passive_some_big() -> + [{doc,"Test packet option {packet, raw} in passive mode."}]. +packet_raw_passive_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_raw, [Data, ?SOME]}}, - {options, - [{active, false}, - {packet, raw} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send, passive_recv_packet, ?SOME, raw, false). %%-------------------------------------------------------------------- -packet_0_passive_many_small(doc) -> - ["Test packet option {packet, 0} in passive mode."]; - -packet_0_passive_many_small(suite) -> - []; - -packet_0_passive_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_0_passive_many_small() -> + [{doc,"Test packet option {packet, 0} in passive mode."}]. +packet_0_passive_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 0}, equivalent to packet raw.", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_raw, [Data, ?MANY]}}, - {options, [{active, false}, - {packet, 0} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?MANY, 0, false). %%-------------------------------------------------------------------- -packet_0_passive_some_big(doc) -> - ["Test packet option {packet, 0} in passive mode."]; - -packet_0_passive_some_big(suite) -> - []; - -packet_0_passive_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_0_passive_some_big() -> + [{doc,"Test packet option {packet, 0} in passive mode."}]. +packet_0_passive_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_raw, [Data, ?SOME]}}, - {options, [{active, false}, - {packet, 0} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?SOME, 0, false). %%-------------------------------------------------------------------- -packet_1_passive_many_small(doc) -> - ["Test packet option {packet, 1} in passive mode."]; - -packet_1_passive_many_small(suite) -> - []; - -packet_1_passive_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_1_passive_many_small() -> + [{doc,"Test packet option {packet, 1} in passive mode."}]. +packet_1_passive_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 1}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 1}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_recv_packet, - [Data, ?MANY]}}, - {options, [{active, false}, - {packet, 1} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?MANY, 1, false). %%-------------------------------------------------------------------- -packet_1_passive_some_big(doc) -> - ["Test packet option {packet, 1} in passive mode."]; - -packet_1_passive_some_big(suite) -> - []; - -packet_1_passive_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_1_passive_some_big() -> + [{doc,"Test packet option {packet, 1} in passive mode."}]. +packet_1_passive_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(255, "1")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 1}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_recv_packet, - [Data, ?SOME]}}, - {options, [{active, false}, - {packet, 1} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?SOME, 1, false). %%-------------------------------------------------------------------- -packet_2_passive_many_small(doc) -> - ["Test packet option {packet, 2} in passive mode"]; - -packet_2_passive_many_small(suite) -> - []; - -packet_2_passive_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_2_passive_many_small() -> + [{doc,"Test packet option {packet, 2} in passive mode"}]. +packet_2_passive_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 2}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 2}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_recv_packet, - [Data, ?MANY]}}, - {options, [{active, false}, - {packet, 2} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?MANY, 2, false). %%-------------------------------------------------------------------- -packet_2_passive_some_big(doc) -> - ["Test packet option {packet, 2} in passive mode"]; - -packet_2_passive_some_big(suite) -> - []; - -packet_2_passive_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_2_passive_some_big() -> + [{doc,"Test packet option {packet, 2} in passive mode"}]. +packet_2_passive_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 2}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_recv_packet, - [Data, ?SOME]}}, - {options, [{active, false}, - {packet, 2} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?SOME, 2, false). %%-------------------------------------------------------------------- -packet_4_passive_many_small(doc) -> - ["Test packet option {packet, 4} in passive mode"]; - -packet_4_passive_many_small(suite) -> - []; - -packet_4_passive_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_4_passive_many_small() -> + [{doc,"Test packet option {packet, 4} in passive mode"}]. +packet_4_passive_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 4}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, - {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 4}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_recv_packet, - [Data, ?MANY]}}, - {options, [{active, false}, - {packet, 4} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send, passive_recv_packet, ?MANY, 4, false). %%-------------------------------------------------------------------- -packet_4_passive_some_big(doc) -> - ["Test packet option {packet, 4} in passive mode"]; - -packet_4_passive_some_big(suite) -> - []; - -packet_4_passive_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_4_passive_some_big() -> + [{doc,"Test packet option {packet, 4} in passive mode"}]. +packet_4_passive_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 4}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, passive_recv_packet, - [Data, ?SOME]}}, - {options, [{active, false}, - {packet, 4} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send, passive_recv_packet, ?SOME, 4, false). %%-------------------------------------------------------------------- -packet_raw_active_once_many_small(doc) -> - ["Test packet option {packet, raw} in active once mode."]; - -packet_raw_active_once_many_small(suite) -> - []; - -packet_raw_active_once_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_raw_active_once_many_small() -> + [{doc,"Test packet option {packet, raw} in active once mode."}]. +packet_raw_active_once_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, raw}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, active_once_raw, - [Data, ?MANY]}}, - {options, [{active, once}, - {packet, raw} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?MANY, raw, once). %%-------------------------------------------------------------------- -packet_raw_active_once_some_big(doc) -> - ["Test packet option {packet, raw} in active once mode."]; - -packet_raw_active_once_some_big(suite) -> - []; - -packet_raw_active_once_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_raw_active_once_some_big() -> + [{doc,"Test packet option {packet, raw} in active once mode."}]. +packet_raw_active_once_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, active_once_raw, - [Data, ?SOME]}}, - {options, [{active, once}, - {packet, raw} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?SOME, raw, once). %%-------------------------------------------------------------------- -packet_0_active_once_many_small(doc) -> - ["Test packet option {packet, 0} in active once mode."]; - -packet_0_active_once_many_small(suite) -> - []; - -packet_0_active_once_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_0_active_once_many_small() -> + [{doc,"Test packet option {packet, 0} in active once mode."}]. +packet_0_active_once_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 0}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, active_once_raw, - [Data, ?MANY]}}, - {options, [{active, once}, - {packet, 0} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send_raw, active_once_raw, ?MANY, 0, once). %%-------------------------------------------------------------------- -packet_0_active_once_some_big(doc) -> - ["Test packet option {packet, 0} in active once mode."]; - -packet_0_active_once_some_big(suite) -> - []; - -packet_0_active_once_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_0_active_once_some_big() -> + [{doc,"Test packet option {packet, 0} in active once mode."}]. +packet_0_active_once_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw , - [Data, ?SOME]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, active_once_raw, - [Data, ?SOME]}}, - {options, [{active, once}, - {packet, 0} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?SOME, 0, once). %%-------------------------------------------------------------------- -packet_1_active_once_many_small(doc) -> - ["Test packet option {packet, 1} in active once mode."]; - -packet_1_active_once_many_small(suite) -> - []; - -packet_1_active_once_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_1_active_once_many_small() -> + [{doc,"Test packet option {packet, 1} in active once mode."}]. +packet_1_active_once_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 1}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 1}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_once_packet, - [Data, ?MANY]}}, - {options, [{active, once}, - {packet, 1} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?MANY, 1, once). %%-------------------------------------------------------------------- -packet_1_active_once_some_big(doc) -> - ["Test packet option {packet, 1} in active once mode."]; - -packet_1_active_once_some_big(suite) -> - []; - -packet_1_active_once_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_1_active_once_some_big() -> + [{doc,"Test packet option {packet, 1} in active once mode."}]. +packet_1_active_once_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(255, "1")), + packet(Config, Data, send_raw, active_once_raw, ?SOME, 1, once). - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 1}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_once_packet, - [Data, ?SOME]}}, - {options, [{active, once}, - {packet, 1} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_2_active_once_many_small(doc) -> - ["Test packet option {packet, 2} in active once mode"]; - -packet_2_active_once_many_small(suite) -> - []; - -packet_2_active_once_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_2_active_once_many_small() -> + [{doc,"Test packet option {packet, 2} in active once mode"}]. +packet_2_active_once_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 2}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 2}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_once_packet, - [Data, ?MANY]}}, - {options, [{active, once}, - {packet, 2} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send_raw, active_once_raw, ?MANY, 2, once). %%-------------------------------------------------------------------- -packet_2_active_once_some_big(doc) -> - ["Test packet option {packet, 2} in active once mode"]; - -packet_2_active_once_some_big(suite) -> - []; - -packet_2_active_once_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_2_active_once_some_big() -> + [{doc,"Test packet option {packet, 2} in active once mode"}]. +packet_2_active_once_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 2}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_once_packet, - [Data, ?SOME]}}, - {options, [{active, once}, - {packet, 2} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?SOME, 2, once). %%-------------------------------------------------------------------- -packet_4_active_once_many_small(doc) -> - ["Test packet option {packet, 4} in active once mode"]; - -packet_4_active_once_many_small(suite) -> - []; - -packet_4_active_once_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_4_active_once_many_small() -> + [{doc,"Test packet option {packet, 4} in active once mode"}]. +packet_4_active_once_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 4}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 4}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_once_packet, - [Data, ?MANY]}}, - {options, [{active, once}, - {packet, 4} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?MANY, 4, once). %%-------------------------------------------------------------------- -packet_4_active_once_some_big(doc) -> - ["Test packet option {packet, 4} in active once mode"]; - -packet_4_active_once_some_big(suite) -> - []; - -packet_4_active_once_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_4_active_once_some_big() -> + [{doc,"Test packet option {packet, 4} in active once mode"}]. +packet_4_active_once_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 4}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_once_packet, - [Data, ?SOME]}}, - {options, [{active, once}, - {packet, 4} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_once_raw, ?SOME, 4, once). %%-------------------------------------------------------------------- -packet_raw_active_many_small(doc) -> - ["Test packet option {packet, raw} in active mode."]; - -packet_raw_active_many_small(suite) -> - []; +packet_raw_active_many_small() -> + [{doc,"Test packet option {packet, raw} in active mode."}]. packet_raw_active_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Data = "Packet option is {packet, raw}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, active_raw, - [Data, ?MANY]}}, - {options, [{active, true}, - {packet, raw} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send_raw, active_raw, ?MANY, raw, active). %%-------------------------------------------------------------------- -packet_raw_active_some_big(doc) -> - ["Test packet option {packet, raw} in active mode."]; - -packet_raw_active_some_big(suite) -> - []; +packet_raw_active_some_big() -> + [{doc,"Test packet option {packet, raw} in active mode."}]. packet_raw_active_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, active_raw, [Data, ?SOME]}}, - {options, [{active, true}, - {packet, raw} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_raw, ?SOME, raw, active). %%-------------------------------------------------------------------- -packet_0_active_many_small(doc) -> - ["Test packet option {packet, 0} in active mode."]; - -packet_0_active_many_small(suite) -> - []; - -packet_0_active_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_0_active_many_small() -> + [{doc,"Test packet option {packet, 0} in active mode."}]. +packet_0_active_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 0}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, active_raw, - [Data, ?MANY]}}, - {options, [{active, true}, - {packet, 0} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_raw, ?MANY, 0, active). %%-------------------------------------------------------------------- -packet_0_active_some_big(doc) -> - ["Test packet option {packet, 0} in active mode."]; - -packet_0_active_some_big(suite) -> - []; - -packet_0_active_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_0_active_some_big() -> + [{doc,"Test packet option {packet, 0} in active mode."}]. +packet_0_active_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, active_raw, - [Data, ?SOME]}}, - {options, [{active, true}, - {packet, 0} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send_raw, active_raw, ?SOME, 0, active). %%-------------------------------------------------------------------- -packet_1_active_many_small(doc) -> - ["Test packet option {packet, 1} in active mode."]; - -packet_1_active_many_small(suite) -> - []; - -packet_1_active_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_1_active_many_small() -> + [{doc,"Test packet option {packet, 1} in active mode."}]. +packet_1_active_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 1}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 1}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_packet, [Data, ?MANY]}}, - {options, [{active, true}, - {packet, 1} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_raw, ?MANY, 1, active). %%-------------------------------------------------------------------- -packet_1_active_some_big(doc) -> - ["Test packet option {packet, 1} in active mode."]; - -packet_1_active_some_big(suite) -> - []; - -packet_1_active_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_1_active_some_big() -> + [{doc,"Test packet option {packet, 1} in active mode."}]. +packet_1_active_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(255, "1")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 1}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_packet, [Data, ?SOME]}}, - {options, [{active, true}, - {packet, 1} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_raw, ?SOME, 1, active). %%-------------------------------------------------------------------- -packet_2_active_many_small(doc) -> - ["Test packet option {packet, 2} in active mode"]; - -packet_2_active_many_small(suite) -> - []; - -packet_2_active_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_2_active_many_small() -> + [{doc,"Test packet option {packet, 2} in active mode"}]. +packet_2_active_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 2}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 2}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_packet, [Data, ?MANY]}}, - {options, [{active, true}, - {packet, 2} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_raw, ?MANY, 2, active). %%-------------------------------------------------------------------- -packet_2_active_some_big(doc) -> - ["Test packet option {packet, 2} in active mode"]; - -packet_2_active_some_big(suite) -> - []; - -packet_2_active_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_2_active_some_big() -> + [{doc,"Test packet option {packet, 2} in active mode"}]. +packet_2_active_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 2}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_packet, [Data, ?SOME]}}, - {options, [{active, true}, - {packet, 2} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + packet(Config, Data, send_raw, active_raw, ?SOME, 2, active). %%-------------------------------------------------------------------- -packet_4_active_many_small(doc) -> - ["Test packet option {packet, 4} in active mode"]; - -packet_4_active_many_small(suite) -> - []; - -packet_4_active_many_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_4_active_many_small() -> + [{doc,"Test packet option {packet, 4} in active mode"}]. +packet_4_active_many_small(Config) when is_list(Config) -> Data = "Packet option is {packet, 4}", - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?MANY]}}, - {options, [{packet, 4}|ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_packet, [Data, ?MANY]}}, - {options, [{active, true}, - {packet, 4} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send_raw, active_raw, ?MANY, 4, active). %%-------------------------------------------------------------------- -packet_4_active_some_big(doc) -> - ["Test packet option {packet, 4} in active mode"]; - -packet_4_active_some_big(suite) -> - []; - -packet_4_active_some_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +packet_4_active_some_big() -> + [{doc,"Test packet option {packet, 4} in active mode"}]. +packet_4_active_some_big(Config) when is_list(Config) -> Data = lists:append(lists:duplicate(100, "1234567890")), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send, [Data, ?SOME]}}, - {options, [{packet, 4} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, - {?MODULE, - active_packet, [Data, ?SOME]}}, - {options, [{active, true}, - {packet, 4} | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - + packet(Config, Data, send_raw, active_raw, ?SOME, 4, active). %%-------------------------------------------------------------------- -packet_send_to_large(doc) -> - ["Test setting the packet option {packet, 2} on the send side"]; - -packet_send_to_large(suite) -> []; +packet_send_to_large() -> + [{doc,"Test setting the packet option {packet, 2} on the send side"}]. packet_send_to_large(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1279,16 +447,9 @@ packet_send_to_large(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). - - - - %%-------------------------------------------------------------------- -packet_wait_active(doc) -> - ["Test waiting when complete packages have not arrived"]; - -packet_wait_active(suite) -> - []; +packet_wait_active() -> + [{doc,"Test waiting when complete packages have not arrived"}]. packet_wait_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1320,11 +481,8 @@ packet_wait_active(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -packet_wait_passive(doc) -> - ["Test waiting when complete packages have not arrived"]; - -packet_wait_passive(suite) -> - []; +packet_wait_passive() -> + [{doc,"Test waiting when complete packages have not arrived"}]. packet_wait_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1353,10 +511,8 @@ packet_wait_passive(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_baddata_active(doc) -> - ["Test that if a bad packet arrives error msg is sent and socket is closed"]; -packet_baddata_active(suite) -> - []; +packet_baddata_active() -> + [{doc,"Test that if a bad packet arrives error msg is sent and socket is closed"}]. packet_baddata_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1381,18 +537,15 @@ packet_baddata_active(Config) when is_list(Config) -> {Client, {other, {ssl_error, _Socket, {invalid_packet, _}},{error,closed},1}} -> ok; Unexpected -> - test_server:fail({unexpected, Unexpected}) + ct:fail({unexpected, Unexpected}) end, ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_baddata_passive(doc) -> - ["Test that if a bad packet arrives error msg is sent and socket is closed"]; - -packet_baddata_passive(suite) -> - []; +packet_baddata_passive() -> + [{doc,"Test that if a bad packet arrives error msg is sent and socket is closed"}]. packet_baddata_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1418,19 +571,16 @@ packet_baddata_passive(Config) when is_list(Config) -> receive {Client, {other, {error, {invalid_packet, _}},{error,closed}, 1}} -> ok; Unexpected -> - test_server:fail({unexpected, Unexpected}) + ct:fail({unexpected, Unexpected}) end, ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_size_active(doc) -> - ["Test that if a packet of size larger than - packet_size arrives error msg is sent and socket is closed"]; - -packet_size_active(suite) -> - []; +packet_size_active() -> + [{doc,"Test that if a packet of size larger than + packet_size arrives error msg is sent and socket is closed"}]. packet_size_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1455,17 +605,16 @@ packet_size_active(Config) when is_list(Config) -> {Client, {other, {ssl_error, _Socket, {invalid_packet, _}},{error,closed},1}} -> ok; Unexpected -> - test_server:fail({unexpected, Unexpected}) + ct:fail({unexpected, Unexpected}) end, ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_size_passive(doc) -> - ["Test that if a packet of size larger - than packet_size arrives error msg is sent and socket is closed"]; -packet_size_passive(suite) -> []; +packet_size_passive() -> + [{doc, "Test that if a packet of size larger + than packet_size arrives error msg is sent and socket is closed"}]. packet_size_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1490,17 +639,15 @@ packet_size_passive(Config) when is_list(Config) -> receive {Client, {other, {error, {invalid_packet, _}},{error,closed},1}} -> ok; Unexpected -> - test_server:fail({unexpected, Unexpected}) + ct:fail({unexpected, Unexpected}) end, ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_cdr_decode(doc) -> - ["Test setting the packet option {packet, cdr}, {mode, binary}"]; -packet_cdr_decode(suite) -> - []; +packet_cdr_decode() -> + [{doc,"Test setting the packet option {packet, cdr}, {mode, binary}"}]. packet_cdr_decode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1532,10 +679,8 @@ packet_cdr_decode(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_cdr_decode_list(doc) -> - ["Test setting the packet option {packet, cdr} {mode, list}"]; -packet_cdr_decode_list(suite) -> - []; +packet_cdr_decode_list() -> + [{doc,"Test setting the packet option {packet, cdr} {mode, list}"}]. packet_cdr_decode_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1567,11 +712,9 @@ packet_cdr_decode_list(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_http_decode(doc) -> - ["Test setting the packet option {packet, http} {mode, binary} " - "(Body will be binary http strings are lists)"]; -packet_http_decode(suite) -> - []; +packet_http_decode() -> + [{doc, "Test setting the packet option {packet, http} {mode, binary} " + "(Body will be binary http strings are lists)"}]. packet_http_decode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -1652,11 +795,9 @@ client_http_decode(Socket, HttpRequest) -> ok. %%-------------------------------------------------------------------- -packet_http_decode_list(doc) -> - ["Test setting the packet option {packet, http}, {mode, list}" - "(Body will be list too)"]; -packet_http_decode_list(suite) -> - []; +packet_http_decode_list() -> + [{doc, "Test setting the packet option {packet, http}, {mode, list}" + "(Body will be list too)"}]. packet_http_decode_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1712,11 +853,8 @@ client_http_decode_list(Socket, HttpRequest) -> ok. %%-------------------------------------------------------------------- -packet_http_bin_decode_multi(doc) -> - ["Test setting the packet option {packet, http_bin} with multiple requests"]; -packet_http_bin_decode_multi(suite) -> - []; - +packet_http_bin_decode_multi() -> + [{doc,"Test setting the packet option {packet, http_bin} with multiple requests"}]. packet_http_bin_decode_multi(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1803,11 +941,10 @@ client_http_bin_decode(_, _, _) -> ok. %%-------------------------------------------------------------------- -packet_http_error_passive(doc) -> - ["Test setting the packet option {packet, http}, {active, false}" - " with a incorrect http header." ]; -packet_http_error_passive(suite) -> - []; +packet_http_error_passive() -> + [{doc,"Test setting the packet option {packet, http}, {active, false}" + " with a incorrect http header."}]. + packet_http_error_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1865,10 +1002,9 @@ server_http_decode_error(Socket, HttpResponse) -> ok = ssl:send(Socket, HttpResponse), ok. %%-------------------------------------------------------------------- -packet_httph_active(doc) -> - ["Test setting the packet option {packet, httph}"]; -packet_httph_active(suite) -> - []; +packet_httph_active() -> + [{doc,"Test setting the packet option {packet, httph}"}]. + packet_httph_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1922,10 +1058,8 @@ client_http_decode_trailer_active(Socket) -> ok. %%-------------------------------------------------------------------- -packet_httph_bin_active(doc) -> - ["Test setting the packet option {packet, httph_bin}"]; -packet_httph_bin_active(suite) -> - []; +packet_httph_bin_active() -> + [{doc,"Test setting the packet option {packet, httph_bin}"}]. packet_httph_bin_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -1973,10 +1107,9 @@ client_http_decode_trailer_bin_active(Socket) -> end, ok. %%-------------------------------------------------------------------- -packet_httph_active_once(doc) -> - ["Test setting the packet option {packet, httph}"]; -packet_httph_active_once(suite) -> - []; +packet_httph_active_once() -> + [{doc,"Test setting the packet option {packet, httph}"}]. + packet_httph_active_once(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2027,10 +1160,9 @@ client_http_decode_trailer_active_once(Socket) -> end, ok. %%-------------------------------------------------------------------- -packet_httph_bin_active_once(doc) -> - ["Test setting the packet option {packet, httph_bin}"]; -packet_httph_bin_active_once(suite) -> - []; +packet_httph_bin_active_once() -> + [{doc,"Test setting the packet option {packet, httph_bin}"}]. + packet_httph_bin_active_once(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2082,10 +1214,9 @@ client_http_decode_trailer_bin_active_once(Socket) -> %%-------------------------------------------------------------------- -packet_httph_passive(doc) -> - ["Test setting the packet option {packet, httph}"]; -packet_httph_passive(suite) -> - []; +packet_httph_passive() -> + [{doc,"Test setting the packet option {packet, httph}"}]. + packet_httph_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2123,10 +1254,9 @@ client_http_decode_trailer_passive(Socket) -> ok. %%-------------------------------------------------------------------- -packet_httph_bin_passive(doc) -> - ["Test setting the packet option {packet, httph_bin}"]; -packet_httph_bin_passive(suite) -> - []; +packet_httph_bin_passive() -> + [{doc,"Test setting the packet option {packet, httph_bin}"}]. + packet_httph_bin_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2164,10 +1294,9 @@ client_http_decode_trailer_bin_passive(Socket) -> ok. %%-------------------------------------------------------------------- -packet_line_decode(doc) -> - ["Test setting the packet option {packet, line}, {mode, binary}"]; -packet_line_decode(suite) -> - []; +packet_line_decode() -> + [{doc,"Test setting the packet option {packet, line}, {mode, binary}"}]. + packet_line_decode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2201,10 +1330,9 @@ packet_line_decode(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -packet_line_decode_list(doc) -> - ["Test setting the packet option {packet, line}, {mode, list}"]; -packet_line_decode_list(suite) -> - []; +packet_line_decode_list() -> + [{doc,"Test setting the packet option {packet, line}, {mode, list}"}]. + packet_line_decode_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2240,10 +1368,9 @@ packet_line_decode_list(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -packet_asn1_decode(doc) -> - ["Test setting the packet option {packet, asn1}"]; -packet_asn1_decode(suite) -> - []; +packet_asn1_decode() -> + [{doc,"Test setting the packet option {packet, asn1}"}]. + packet_asn1_decode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2276,10 +1403,9 @@ packet_asn1_decode(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_asn1_decode_list(doc) -> - ["Test setting the packet option {packet, asn1}"]; -packet_asn1_decode_list(suite) -> - []; +packet_asn1_decode_list() -> + [{doc,"Test setting the packet option {packet, asn1}"}]. + packet_asn1_decode_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2314,10 +1440,9 @@ packet_asn1_decode_list(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_tpkt_decode(doc) -> - ["Test setting the packet option {packet, tpkt}"]; -packet_tpkt_decode(suite) -> - []; +packet_tpkt_decode() -> + [{doc,"Test setting the packet option {packet, tpkt}"}]. + packet_tpkt_decode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2347,10 +1472,9 @@ packet_tpkt_decode(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_tpkt_decode_list(doc) -> - ["Test setting the packet option {packet, tpkt}"]; -packet_tpkt_decode_list(suite) -> - []; +packet_tpkt_decode_list() -> + [{doc,"Test setting the packet option {packet, tpkt}"}]. + packet_tpkt_decode_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2381,10 +1505,9 @@ packet_tpkt_decode_list(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -%% packet_fcgi_decode(doc) -> -%% ["Test setting the packet option {packet, fcgi}"]; -%% packet_fcgi_decode(suite) -> -%% []; +%% packet_fcgi_decode() -> +%% [{doc,"Test setting the packet option {packet, fcgi}"}]. + %% packet_fcgi_decode(Config) when is_list(Config) -> %% ClientOpts = ?config(client_opts, Config), %% ServerOpts = ?config(server_opts, Config), @@ -2416,10 +1539,8 @@ packet_tpkt_decode_list(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -packet_sunrm_decode(doc) -> - ["Test setting the packet option {packet, sunrm}"]; -packet_sunrm_decode(suite) -> - []; +packet_sunrm_decode() -> + [{doc,"Test setting the packet option {packet, sunrm}"}]. packet_sunrm_decode(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2449,10 +1570,9 @@ packet_sunrm_decode(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -packet_sunrm_decode_list(doc) -> - ["Test setting the packet option {packet, sunrm}"]; -packet_sunrm_decode_list(suite) -> - []; +packet_sunrm_decode_list() -> + [{doc,"Test setting the packet option {packet, sunrm}"}]. + packet_sunrm_decode_list(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2482,10 +1602,9 @@ packet_sunrm_decode_list(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -header_decode_one_byte_active(doc) -> - ["Test setting the packet option {header, 1}"]; -header_decode_one_byte_active(suite) -> - []; +header_decode_one_byte_active() -> + [{doc,"Test setting the packet option {header, 1}"}]. + header_decode_one_byte_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2516,10 +1635,9 @@ header_decode_one_byte_active(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_active(doc) -> - ["Test setting the packet option {header, 2}"]; -header_decode_two_bytes_active(suite) -> - []; +header_decode_two_bytes_active() -> + [{doc,"Test setting the packet option {header, 2}"}]. + header_decode_two_bytes_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2551,10 +1669,9 @@ header_decode_two_bytes_active(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_two_sent_active(doc) -> - ["Test setting the packet option {header, 2} and sending two byte"]; -header_decode_two_bytes_two_sent_active(suite) -> - []; +header_decode_two_bytes_two_sent_active() -> + [{doc,"Test setting the packet option {header, 2} and sending two byte"}]. + header_decode_two_bytes_two_sent_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2586,10 +1703,9 @@ header_decode_two_bytes_two_sent_active(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_one_sent_active(doc) -> - ["Test setting the packet option {header, 2} and sending one byte"]; -header_decode_two_bytes_one_sent_active(suite) -> - []; +header_decode_two_bytes_one_sent_active() -> + [{doc,"Test setting the packet option {header, 2} and sending one byte"}]. + header_decode_two_bytes_one_sent_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2620,10 +1736,9 @@ header_decode_two_bytes_one_sent_active(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_one_byte_passive(doc) -> - ["Test setting the packet option {header, 1}"]; -header_decode_one_byte_passive(suite) -> - []; +header_decode_one_byte_passive() -> + [{doc,"Test setting the packet option {header, 1}"}]. + header_decode_one_byte_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2654,10 +1769,9 @@ header_decode_one_byte_passive(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_passive(doc) -> - ["Test setting the packet option {header, 2}"]; -header_decode_two_bytes_passive(suite) -> - []; +header_decode_two_bytes_passive() -> + [{doc,"Test setting the packet option {header, 2}"}]. + header_decode_two_bytes_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2689,10 +1803,9 @@ header_decode_two_bytes_passive(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_two_sent_passive(doc) -> - ["Test setting the packet option {header, 2} and sending two byte"]; -header_decode_two_bytes_two_sent_passive(suite) -> - []; +header_decode_two_bytes_two_sent_passive() -> + [{doc,"Test setting the packet option {header, 2} and sending two byte"}]. + header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2724,10 +1837,9 @@ header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_one_sent_passive(doc) -> - ["Test setting the packet option {header, 2} and sending one byte"]; -header_decode_two_bytes_one_sent_passive(suite) -> - []; +header_decode_two_bytes_one_sent_passive() -> + [{doc,"Test setting the packet option {header, 2} and sending one byte"}]. + header_decode_two_bytes_one_sent_passive(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2757,7 +1869,30 @@ header_decode_two_bytes_one_sent_passive(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -%% Internal functions +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +packet(Config, Data, Send, Recv, Quantity, Packet, Active) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, Send ,[Data, Quantity]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, Recv, [Data, Quantity]}}, + {options, [{active, Active}, + {packet, Packet} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). send_raw(Socket,_, 0) -> ssl:send(Socket, <<>>), @@ -2928,7 +2063,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) -> client_packet_decode(Socket, [Head], Tail, Packet). client_packet_decode(Socket, P1, P2, Packet) -> - test_server:format("Packet: ~p ~n", [Packet]), + ct:print("Packet: ~p ~n", [Packet]), ok = ssl:send(Socket, P1), ok = ssl:send(Socket, P2), receive diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index c97f97e70b..77ad546420 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,79 +26,8 @@ -define(TIMEOUT, 600000). -%% Test server callback functions %%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initialization before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- -init_per_suite(Config) -> - catch crypto:stop(), - try crypto:start() of - ok -> - application:start(public_key), - ssl:start(), - make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)), - ssl_test_lib:cert_options(Config) - catch _:_ -> - {skip, "Crypto did not start"} - end. -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto). - -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%% Description: Initialization before each test case -%%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case -%%-------------------------------------------------------------------- -end_per_testcase(_TestCase, Config) -> - Dog = ?config(watchdog, Config), - case Dog of - undefined -> - ok; - _ -> - test_server:timetrap_cancel(Dog) - end. - -%%-------------------------------------------------------------------- -%% Function: all(Clause) -> TestCases -%% Clause - atom() - suite | doc -%% TestCases - [Case] -%% Case - atom() -%% Name of a test case. -%% Description: Returns a list of all test cases in this test suite +%% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -138,6 +67,21 @@ payload_tests() -> client_echos_active_once_huge, client_echos_active_huge]. +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + application:start(public_key), + ssl:start(), + make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)), + ssl_test_lib:cert_options(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). init_per_group(GroupName, Config) -> case ssl_test_lib:is_tls_version(GroupName) of @@ -157,15 +101,20 @@ init_per_group(GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ct:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. -%% Test cases starts here. +end_per_testcase(_TestCase, Config) -> + Config. +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- -server_echos_passive_small(doc) -> - ["Client sends 1000 bytes in passive mode to server, that receives them, " - "sends them back, and closes."]; -server_echos_passive_small(suite) -> - []; +server_echos_passive_small() -> + [{doc, "Client sends 1000 bytes in passive mode to server, that receives them, " + "sends them back, and closes."}]. server_echos_passive_small(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -179,12 +128,9 @@ server_echos_passive_small(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_echos_active_once_small(doc) -> - ["Client sends 1000 bytes in active once mode to server, that receives " - " them, sends them back, and closes."]; - -server_echos_active_once_small(suite) -> - []; +server_echos_active_once_small() -> + [{doc, "Client sends 1000 bytes in active once mode to server, that receives " + " them, sends them back, and closes."}]. server_echos_active_once_small(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -198,12 +144,9 @@ server_echos_active_once_small(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_echos_active_small(doc) -> - ["Client sends 1000 bytes in active mode to server, that receives them, " - "sends them back, and closes."]; - -server_echos_active_small(suite) -> - []; +server_echos_active_small() -> + [{doc, "Client sends 1000 bytes in active mode to server, that receives them, " + "sends them back, and closes."}]. server_echos_active_small(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -216,12 +159,9 @@ server_echos_active_small(Config) when is_list(Config) -> ClientNode, ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_passive_small(doc) -> - ["Server sends 1000 bytes in passive mode to client, that receives them, " - "sends them back, and closes."]; - -client_echos_passive_small(suite) -> - []; +client_echos_passive_small() -> + [{doc, "Server sends 1000 bytes in passive mode to client, that receives them, " + "sends them back, and closes."}]. client_echos_passive_small(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -234,12 +174,9 @@ client_echos_passive_small(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_active_once_small(doc) -> +client_echos_active_once_small() -> ["Server sends 1000 bytes in active once mode to client, that receives " - "them, sends them back, and closes."]; - -client_echos_active_once_small(suite) -> - []; + "them, sends them back, and closes."]. client_echos_active_once_small(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -252,15 +189,12 @@ client_echos_active_once_small(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_active_small(doc) -> - ["Server sends 1000 bytes in active mode to client, that receives them, " - "sends them back, and closes."]; - -client_echos_active_small(suite) -> - []; +client_echos_active_small() -> + [{doc, "Server sends 1000 bytes in active mode to client, that receives them, " + "sends them back, and closes."}]. client_echos_active_small(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), + ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -271,12 +205,9 @@ client_echos_active_small(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_echos_passive_big(doc) -> - ["Client sends 50000 bytes to server in passive mode, that receives them, " - "sends them back, and closes."]; - -server_echos_passive_big(suite) -> - []; +server_echos_passive_big() -> + [{doc, "Client sends 50000 bytes to server in passive mode, that receives them, " + "sends them back, and closes."}]. server_echos_passive_big(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -290,15 +221,12 @@ server_echos_passive_big(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_echos_active_once_big(doc) -> - ["Client sends 50000 bytes to server in active once mode, that receives " - "them, sends them back, and closes."]; - -server_echos_active_once_big(suite) -> - []; +server_echos_active_once_big() -> + [{doc,"Client sends 50000 bytes to server in active once mode, that receives " + "them, sends them back, and closes."}]. server_echos_active_once_big(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), + ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -309,12 +237,9 @@ server_echos_active_once_big(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_echos_active_big(doc) -> - ["Client sends 50000 bytes to server in active once mode, that receives " - " them, sends them back, and closes."]; - -server_echos_active_big(suite) -> - []; +server_echos_active_big() -> + [{doc, "Client sends 50000 bytes to server in active once mode, that receives " + " them, sends them back, and closes."}]. server_echos_active_big(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -327,12 +252,9 @@ server_echos_active_big(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_passive_big(doc) -> - ["Server sends 50000 bytes to client in passive mode, that receives them, " - "sends them back, and closes."]; - -client_echos_passive_big(suite) -> - []; +client_echos_passive_big() -> + [{doc, "Server sends 50000 bytes to client in passive mode, that receives them, " + "sends them back, and closes."}]. client_echos_passive_big(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -345,12 +267,9 @@ client_echos_passive_big(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_active_once_big(doc) -> - ["Server sends 50000 bytes to client in active once mode, that receives" - " them, sends them back, and closes."]; - -client_echos_active_once_big(suite) -> - []; +client_echos_active_once_big() -> + [{doc, "Server sends 50000 bytes to client in active once mode, that receives" + " them, sends them back, and closes."}]. client_echos_active_once_big(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -363,12 +282,9 @@ client_echos_active_once_big(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_active_big(doc) -> - ["Server sends 50000 bytes to client in active mode, that receives them, " - "sends them back, and closes."]; - -client_echos_active_big(suite) -> - []; +client_echos_active_big() -> + [{doc, "Server sends 50000 bytes to client in active mode, that receives them, " + "sends them back, and closes."}]. client_echos_active_big(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -381,12 +297,9 @@ client_echos_active_big(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -server_echos_passive_huge(doc) -> - ["Client sends 500000 bytes to server in passive mode, that receives " - " them, sends them back, and closes."]; - -server_echos_passive_huge(suite) -> - []; +server_echos_passive_huge() -> + [{doc, "Client sends 500000 bytes to server in passive mode, that receives " + " them, sends them back, and closes."}]. server_echos_passive_huge(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -399,12 +312,9 @@ server_echos_passive_huge(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -server_echos_active_once_huge(doc) -> - ["Client sends 500000 bytes to server in active once mode, that receives " - "them, sends them back, and closes."]; - -server_echos_active_once_huge(suite) -> - []; +server_echos_active_once_huge() -> + [{doc, "Client sends 500000 bytes to server in active once mode, that receives " + "them, sends them back, and closes."}]. server_echos_active_once_huge(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -417,12 +327,9 @@ server_echos_active_once_huge(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -server_echos_active_huge(doc) -> - ["Client sends 500000 bytes to server in active mode, that receives them, " - "sends them back, and closes."]; - -server_echos_active_huge(suite) -> - []; +server_echos_active_huge() -> + [{doc, "Client sends 500000 bytes to server in active mode, that receives them, " + "sends them back, and closes."}]. server_echos_active_huge(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -435,12 +342,9 @@ server_echos_active_huge(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_passive_huge(doc) -> - ["Server sends 500000 bytes to client in passive mode, that receives " - "them, sends them back, and closes."]; - -client_echos_passive_huge(suite) -> - []; +client_echos_passive_huge() -> + [{doc, "Server sends 500000 bytes to client in passive mode, that receives " + "them, sends them back, and closes."}]. client_echos_passive_huge(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -452,12 +356,9 @@ client_echos_passive_huge(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_active_once_huge(doc) -> - ["Server sends 500000 bytes to client in active once mode, that receives " - "them, sends them back, and closes."]; - -client_echos_active_once_huge(suite) -> - []; +client_echos_active_once_huge() -> + [{doc, "Server sends 500000 bytes to client in active once mode, that receives " + "them, sends them back, and closes."}]. client_echos_active_once_huge(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -469,12 +370,9 @@ client_echos_active_once_huge(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- -client_echos_active_huge(doc) -> - ["Server sends 500000 bytes to client in active mode, that receives them, " - "sends them back, and closes."]; - -client_echos_active_huge(suite) -> - []; +client_echos_active_huge() -> + [{doc, "Server sends 500000 bytes to client in active mode, that receives them, " + "sends them back, and closes."}]. client_echos_active_huge(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), @@ -486,6 +384,8 @@ client_echos_active_huge(Config) when is_list(Config) -> ServerNode, Hostname). %%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- server_echos_passive(Data, Length, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) -> @@ -656,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) -> sender(Socket, Data, Size) -> ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end), - test_server:format("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]), + ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]), ok. sender_once(Socket, Data, Size) -> send(Socket, Data, Size, 100, fun() -> do_active_once(Socket, Data, Size, <<>>, false) end), - test_server:format("Sender active once: ~p~n", + ct:print("Sender active once: ~p~n", [ssl:getopts(Socket, [active])]), ok. sender_active(Socket, Data, Size) -> F = fun() -> do_active(Socket, Data, Size, <<>>, false) end, send(Socket, Data, Size, 100, F), - test_server:format("Sender active: ~p~n", [ssl:getopts(Socket, [active])]), + ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]), ok. echoer(Socket, Data, Size) -> - test_server:format("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]), + ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]), echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100). echoer_once(Socket, Data, Size) -> - test_server:format("Echoer active once: ~p ~n", + ct:print("Echoer active once: ~p ~n", [ssl:getopts(Socket, [active])]), echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100). echoer_active(Socket, Data, Size) -> - test_server:format("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]), + ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]), echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100). echo(_Fun, 0) -> ok; diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index 1d71efd40c..fd9a0a594c 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2012. All Rights Reserved. +%% Copyright Ericsson AB 2010-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -37,18 +37,22 @@ -export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3, select_session/2]). -%% Test server callback functions %%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initialization before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. +%% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [session_cleanup, + session_cache_process_list, + session_cache_process_mnesia]. + +groups() -> + []. + init_per_suite(Config0) -> - Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2), + Dog = ct:timetrap(?LONG_TIMEOUT *2), catch crypto:stop(), try crypto:start() of ok -> @@ -59,7 +63,7 @@ init_per_suite(Config0) -> Result = (catch make_certs:all(?config(data_dir, Config0), ?config(priv_dir, Config0))), - test_server:format("Make certs ~p~n", [Result]), + ct:print("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), @@ -68,29 +72,16 @@ init_per_suite(Config0) -> {skip, "Crypto did not start"} end. -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- end_per_suite(_Config) -> ssl:stop(), application:stop(crypto). -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%% Description: Initialization before each test case -%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + init_per_testcase(session_cache_process_list, Config) -> init_customized_session_cache(list, Config); @@ -100,7 +91,7 @@ init_per_testcase(session_cache_process_mnesia, Config) -> init_per_testcase(session_cleanup, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), + Dog = ct:timetrap(?TIMEOUT), ssl:stop(), application:load(ssl), application:set_env(ssl, session_lifetime, 5), @@ -110,12 +101,12 @@ init_per_testcase(session_cleanup, Config0) -> init_per_testcase(_TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), + Dog = ct:timetrap(?TIMEOUT), [{watchdog, Dog} | Config]. init_customized_session_cache(Type, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), + Dog = ct:timetrap(?TIMEOUT), ssl:stop(), application:load(ssl), application:set_env(ssl, session_cb, ?MODULE), @@ -123,14 +114,6 @@ init_customized_session_cache(Type, Config0) -> ssl:start(), [{watchdog, Dog} | Config]. -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case -%%-------------------------------------------------------------------- end_per_testcase(session_cache_process_list, Config) -> application:unset_env(ssl, session_cb), end_per_testcase(default_action, Config); @@ -146,43 +129,14 @@ end_per_testcase(session_cleanup, Config) -> application:unset_env(ssl, session_lifetime), end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> - Dog = ?config(watchdog, Config), - case Dog of - undefined -> - ok; - _ -> - test_server:timetrap_cancel(Dog) - end. - -%%-------------------------------------------------------------------- -%% Function: all(Clause) -> TestCases -%% Clause - atom() - suite | doc -%% TestCases - [Case] -%% Case - atom() -%% Name of a test case. -%% Description: Returns a list of all test cases in this test suite -%%-------------------------------------------------------------------- -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [session_cleanup, - session_cache_process_list, - session_cache_process_mnesia]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> Config. -end_per_group(_GroupName, Config) -> - Config. %%-------------------------------------------------------------------- -session_cleanup(doc) -> - ["Test that sessions are cleand up eventually, so that the session table " - "does not grow and grow ..."]; -session_cleanup(suite) -> - []; +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +session_cleanup() -> + [{doc, "Test that sessions are cleand up eventually, so that the session table " + "does not grow and grow ..."}]. session_cleanup(Config)when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_opts, Config), @@ -207,7 +161,7 @@ session_cleanup(Config)when is_list(Config) -> end, %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, @@ -224,14 +178,14 @@ session_cleanup(Config)when is_list(Config) -> %% Make sure session has expired and been cleaned up check_timer(SessionTimer), - test_server:sleep(?DELAY *2), %% Delay time + some extra time + ct:sleep(?DELAY *2), %% Delay time + some extra time {ServerDelayTimer, ClientDelayTimer} = get_delay_timers(), check_timer(ServerDelayTimer), check_timer(ClientDelayTimer), - test_server:sleep(?SLEEP), %% Make sure clean has had time to run + ct:sleep(?SLEEP), %% Make sure clean has had time to run undefined = ssl_session_cache:lookup(Cache, {{Hostname, Port}, Id}), undefined = ssl_session_cache:lookup(Cache, {Port, Id}), @@ -248,7 +202,7 @@ check_timer(Timer) -> {status, _, _, _} = sys:get_status(whereis(ssl_manager)), ok; Int -> - test_server:sleep(Int), + ct:sleep(Int), check_timer(Timer) end. @@ -258,31 +212,25 @@ get_delay_timers() -> State = ssl_test_lib:state(Prop), case element(7, State) of {undefined, undefined} -> - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), get_delay_timers(); {undefined, _} -> - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), get_delay_timers(); {_, undefined} -> - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), get_delay_timers(); DelayTimers -> DelayTimers end. %%-------------------------------------------------------------------- -session_cache_process_list(doc) -> - ["Test reuse of sessions (short handshake)"]; - -session_cache_process_list(suite) -> - []; +session_cache_process_list() -> + [{doc,"Test reuse of sessions (short handshake)"}]. session_cache_process_list(Config) when is_list(Config) -> session_cache_process(list,Config). %%-------------------------------------------------------------------- -session_cache_process_mnesia(doc) -> - ["Test reuse of sessions (short handshake)"]; - -session_cache_process_mnesia(suite) -> - []; +session_cache_process_mnesia() -> + [{doc,"Test reuse of sessions (short handshake)"}]. session_cache_process_mnesia(Config) when is_list(Config) -> session_cache_process(mnesia,Config). diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index f1f5b9ae0a..8d96a70a6e 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,8 +20,7 @@ %% -module(ssl_test_lib). --include("test_server.hrl"). --include("test_server_line.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). %% Note: This directive should only be used in test suites. @@ -29,12 +28,6 @@ -record(sslsocket, { fd = nil, pid = nil}). -timetrap(Time) -> - Mul = try - test_server:timetrap_scale_factor() - catch _:_ -> 1 end, - test_server:timetrap(1000+Time*Mul). - %% For now always run locally run_where(_) -> ClientNode = node(), @@ -65,8 +58,9 @@ run_server(Opts) -> Port = proplists:get_value(port, Opts), Options = proplists:get_value(options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("ssl:listen(~p, ~p)~n", [Port, Options]), - {ok, ListenSocket} = rpc:call(Node, ssl, listen, [Port, Options]), + Transport = proplists:get_value(transport, Opts, ssl), + ct:print("ssl:listen(~p, ~p)~n", [Port, Options]), + {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), run_server(ListenSocket, Opts). @@ -81,14 +75,15 @@ do_run_server(_, {error, timeout} = Result, Opts) -> do_run_server(ListenSocket, AcceptSocket, Opts) -> Node = proplists:get_value(node, Opts), Pid = proplists:get_value(from, Opts), + Transport = proplists:get_value(transport, Opts, ssl), {Module, Function, Args} = proplists:get_value(mfa, Opts), - test_server:format("Server: apply(~p,~p,~p)~n", + ct:print("Server: apply(~p,~p,~p)~n", [Module, Function, [AcceptSocket | Args]]), case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of no_result_msg -> ok; Msg -> - test_server:format("Server Msg: ~p ~n", [Msg]), + ct:print("Server Msg: ~p ~n", [Msg]), Pid ! {self(), Msg} end, receive @@ -97,15 +92,16 @@ do_run_server(ListenSocket, AcceptSocket, Opts) -> {listen, MFA} -> run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]); close -> - test_server:format("Server closing ~p ~n", [self()]), - Result = rpc:call(Node, ssl, close, [AcceptSocket], 500), - test_server:format("Result ~p ~n", [Result]); + ct:print("Server closing ~p ~n", [self()]), + Result = rpc:call(Node, Transport, close, [AcceptSocket], 500), + Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500), + ct:print("Result ~p : ~p ~n", [Result, Result1]); {ssl_closed, _} -> ok end. %%% To enable to test with s_client -reconnect -connect(ListenSocket, Opts) -> +connect(#sslsocket{} = ListenSocket, Opts) -> Node = proplists:get_value(node, Opts), ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0), Timeout = proplists:get_value(timeout, Opts, infinity), @@ -116,15 +112,21 @@ connect(ListenSocket, Opts) -> _ -> remove_close_msg(ReconnectTimes), AcceptSocket - end. - + end; +connect(ListenSocket, Opts) -> + Node = proplists:get_value(node, Opts), + ct:print("gen_tcp:accept(~p)~n", [ListenSocket]), + {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, + [ListenSocket]), + AcceptSocket. + connect(_, _, 0, AcceptSocket, _) -> AcceptSocket; connect(ListenSocket, Node, N, _, Timeout) -> - test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]), + ct:print("ssl:transport_accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, [ListenSocket]), - test_server:format("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]), + ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]), case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of ok -> @@ -157,47 +159,111 @@ run_client(Opts) -> Host = proplists:get_value(host, Opts), Port = proplists:get_value(port, Opts), Pid = proplists:get_value(from, Opts), + Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), - test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), - case rpc:call(Node, ssl, connect, [Host, Port, Options]) of + ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), + case rpc:call(Node, Transport, connect, [Host, Port, Options]) of {ok, Socket} -> Pid ! { connected, Socket }, - test_server:format("Client: connected~n", []), + ct:print("Client: connected~n", []), %% In special cases we want to know the client port, it will %% be indicated by sending {port, 0} in options list! send_selected_port(Pid, proplists:get_value(port, Options), Socket), {Module, Function, Args} = proplists:get_value(mfa, Opts), - test_server:format("Client: apply(~p,~p,~p)~n", + ct:print("Client: apply(~p,~p,~p)~n", [Module, Function, [Socket | Args]]), case rpc:call(Node, Module, Function, [Socket | Args]) of no_result_msg -> ok; Msg -> - test_server:format("Client Msg: ~p ~n", [Msg]), + ct:print("Client Msg: ~p ~n", [Msg]), Pid ! {self(), Msg} end, receive close -> - test_server:format("Client closing~n", []), - rpc:call(Node, ssl, close, [Socket]); + ct:print("Client closing~n", []), + rpc:call(Node, Transport, close, [Socket]); {ssl_closed, Socket} -> + ok; + {gen_tcp, closed} -> ok end; {error, Reason} -> - test_server:format("Client: connection failed: ~p ~n", [Reason]), + ct:print("Client: connection failed: ~p ~n", [Reason]), Pid ! {self(), {error, Reason}} end. close(Pid) -> - test_server:format("Close ~p ~n", [Pid]), + ct:print("Close ~p ~n", [Pid]), Monitor = erlang:monitor(process, Pid), Pid ! close, receive {'DOWN', Monitor, process, Pid, Reason} -> erlang:demonitor(Monitor), - test_server:format("Pid: ~p down due to:~p ~n", [Pid, Reason]) + ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason]) end. + +check_result(Server, {error, SReason} = ServerMsg, Client, {error, closed} = ClientMsg) -> + receive + {Server, {error, {SReason, _}}} -> + receive + {Client, ClientMsg} -> + ok; + Unexpected -> + Reason = {{expected, {Client, ClientMsg}}, + {got, Unexpected}}, + ct:fail(Reason) + end; + {Client, ClientMsg} -> + receive + {Server, {error, {SReason, _}}} -> + ok; + Unexpected -> + Reason = {{expected, {Server,{error, {SReason, 'term()'}}}, + {got, Unexpected}}}, + ct:fail(Reason) + end; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Server, ServerMsg, Client, ClientMsg); + + Unexpected -> + Reason = {{expected, {Client, ClientMsg}}, + {expected, {Server, {error, {SReason, 'term()'}}}, {got, Unexpected}}}, + ct:fail(Reason) + end; + +check_result(Server, {error, closed} = ServerMsg, Client, {error, CReson} = ClientMsg) -> + receive + {Server, ServerMsg} -> + receive + {Client, {error, {CReson, _}}} -> + ok; + Unexpected -> + Reason = {{expected, {Client, {error, {CReson, 'term()'}}}, + {got, Unexpected}}}, + ct:fail(Reason) + end; + {Client, {error, {CReson, _}}} -> + receive + {Server, ServerMsg} -> + ok; + Unexpected -> + Reason = {{expected, {Server, ServerMsg}}, + {got, Unexpected}}, + ct:fail(Reason) + end; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Server, ServerMsg, Client, ClientMsg); + + Unexpected -> + Reason = {{expected, {Client, {error, {CReson, 'term()'}}}, + {expected, {Server, ServerMsg}}, {got, Unexpected}}}, + ct:fail(Reason) + end; + check_result(Server, ServerMsg, Client, ClientMsg) -> receive {Server, ServerMsg} -> @@ -207,7 +273,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> Unexpected -> Reason = {{expected, {Client, ClientMsg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end; {Client, ClientMsg} -> receive @@ -216,7 +282,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> Unexpected -> Reason = {{expected, {Server, ClientMsg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end; {Port, {data,Debug}} when is_port(Port) -> io:format("openssl ~s~n",[Debug]), @@ -225,9 +291,25 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> Unexpected -> Reason = {{expected, {Client, ClientMsg}}, {expected, {Server, ServerMsg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end. +check_result(Pid, {error, Reason} = Err) when Reason == ecertfile; + Reason == ecacertfile; + Reason == ekeyfile; + Reason == edhfile -> + receive + {Pid, {error, {Reason, Str}}} when is_list(Str) -> + ok; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Pid, Err); + Unexpected -> + Reason = {{expected, {Pid, {error, {Reason, "'appropriate error string'"}}}}, + {got, Unexpected}}, + ct:fail(Reason) + end; + check_result(Pid, Msg) -> receive {Pid, Msg} -> @@ -238,7 +320,7 @@ check_result(Pid, Msg) -> Unexpected -> Reason = {{expected, {Pid, Msg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end. wait_for_result(Server, ServerMsg, Client, ClientMsg) -> @@ -405,33 +487,33 @@ run_upgrade_server(Opts) -> SslOptions = proplists:get_value(ssl_options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), + ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:print("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), try {ok, SslAcceptSocket} = case TimeOut of infinity -> - test_server:format("ssl:ssl_accept(~p, ~p)~n", + ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, SslOptions]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions]); _ -> - test_server:format("ssl:ssl_accept(~p, ~p, ~p)~n", + ct:print("ssl:ssl_accept(~p, ~p, ~p)~n", [AcceptSocket, SslOptions, TimeOut]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions, TimeOut]) end, {Module, Function, Args} = proplists:get_value(mfa, Opts), Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]), - test_server:format("Upgrade Server Msg: ~p ~n", [Msg]), + ct:print("Upgrade Server Msg: ~p ~n", [Msg]), Pid ! {self(), Msg}, receive close -> - test_server:format("Upgrade Server closing~n", []), + ct:print("Upgrade Server closing~n", []), rpc:call(Node, ssl, close, [SslAcceptSocket]) end catch error:{badmatch, Error} -> @@ -449,24 +531,24 @@ run_upgrade_client(Opts) -> TcpOptions = proplists:get_value(tcp_options, Opts), SslOptions = proplists:get_value(ssl_options, Opts), - test_server:format("gen_tcp:connect(~p, ~p, ~p)~n", + ct:print("gen_tcp:connect(~p, ~p, ~p)~n", [Host, Port, TcpOptions]), {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]), send_selected_port(Pid, Port, Socket), - test_server:format("ssl:connect(~p, ~p)~n", [Socket, SslOptions]), + ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]), {ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]), {Module, Function, Args} = proplists:get_value(mfa, Opts), - test_server:format("apply(~p, ~p, ~p)~n", + ct:print("apply(~p, ~p, ~p)~n", [Module, Function, [SslSocket | Args]]), Msg = rpc:call(Node, Module, Function, [SslSocket | Args]), - test_server:format("Upgrade Client Msg: ~p ~n", [Msg]), + ct:print("Upgrade Client Msg: ~p ~n", [Msg]), Pid ! {self(), Msg}, receive close -> - test_server:format("Upgrade Client closing~n", []), + ct:print("Upgrade Client closing~n", []), rpc:call(Node, ssl, close, [SslSocket]) end. @@ -485,20 +567,20 @@ run_upgrade_server_error(Opts) -> SslOptions = proplists:get_value(ssl_options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), + ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:print("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), Error = case TimeOut of infinity -> - test_server:format("ssl:ssl_accept(~p, ~p)~n", + ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, SslOptions]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions]); _ -> - test_server:format("ssl:ssl_accept(~p, ~p, ~p)~n", + ct:print("ssl:ssl_accept(~p, ~p, ~p)~n", [AcceptSocket, SslOptions, TimeOut]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions, TimeOut]) @@ -517,22 +599,31 @@ run_server_error(Opts) -> Port = proplists:get_value(port, Opts), Options = proplists:get_value(options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("ssl:listen(~p, ~p)~n", [Port, Options]), - case rpc:call(Node, ssl, listen, [Port, Options]) of - {ok, ListenSocket} -> + Transport = proplists:get_value(transport, Opts, ssl), + ct:print("ssl:listen(~p, ~p)~n", [Port, Options]), + case rpc:call(Node, Transport, listen, [Port, Options]) of + {ok, #sslsocket{} = ListenSocket} -> %% To make sure error_client will %% get {error, closed} and not {error, connection_refused} Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]), - case rpc:call(Node, ssl, transport_accept, [ListenSocket]) of + ct:print("ssl:transport_accept(~p)~n", [ListenSocket]), + case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of {error, _} = Error -> Pid ! {self(), Error}; {ok, AcceptSocket} -> - test_server:format("ssl:ssl_accept(~p)~n", [AcceptSocket]), + ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]), Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]), Pid ! {self(), Error} end; + {ok, ListenSocket} -> + Pid ! {listen, up}, + send_selected_port(Pid, Port, ListenSocket), + ct:print("~p:accept(~p)~n", [Transport, ListenSocket]), + case rpc:call(Node, Transport, accept, [ListenSocket]) of + {error, _} = Error -> + Pid ! {self(), Error} + end; Error -> %% Not really true but as this is an error test %% this is what we want. @@ -548,9 +639,10 @@ run_client_error(Opts) -> Host = proplists:get_value(host, Opts), Port = proplists:get_value(port, Opts), Pid = proplists:get_value(from, Opts), + Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), - test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), - Error = rpc:call(Node, ssl, connect, [Host, Port, Options]), + ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), + Error = rpc:call(Node, Transport, connect, [Host, Port, Options]), Pid ! {self(), Error}. inet_port(Pid) when is_pid(Pid)-> @@ -577,7 +669,7 @@ trigger_renegotiate(Socket, [ErlData, N]) -> trigger_renegotiate(Socket, ErlData, N, Id). trigger_renegotiate(Socket, _, 0, Id) -> - test_server:sleep(1000), + ct:sleep(1000), case ssl:session_info(Socket) of [{session_id, Id} | _ ] -> fail_session_not_renegotiated; @@ -670,7 +762,7 @@ der_to_pem(File, Entries) -> cipher_result(Socket, Result) -> Result = ssl:connection_info(Socket), - test_server:format("Successfull connect: ~p~n", [Result]), + ct:print("Successfull connect: ~p~n", [Result]), %% Importante to send two packets here %% to properly test "cipher state" handling ssl:send(Socket, "Hello\n"), @@ -751,3 +843,33 @@ sufficient_crypto_support('tlsv1.2') -> end; sufficient_crypto_support(_) -> true. + +send_recv_result_active(Socket) -> + ssl:send(Socket, "Hello world"), + receive + {ssl, Socket, "H"} -> + receive + {ssl, Socket, "ello world"} -> + ok + end; + {ssl, Socket, "Hello world"} -> + ok + end. + +send_recv_result(Socket) -> + ssl:send(Socket, "Hello world"), + {ok,"Hello world"} = ssl:recv(Socket, 11), + ok. + +send_recv_result_active_once(Socket) -> + ssl:send(Socket, "Hello world"), + receive + {ssl, Socket, "H"} -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, "ello world"} -> + ok + end; + {ssl, Socket, "Hello world"} -> + ok + end. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index d446014f7b..7c0c00bf36 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -16,7 +16,6 @@ %% %% %CopyrightEnd% %% - %% -module(ssl_to_openssl_SUITE). @@ -29,125 +28,15 @@ -define(TIMEOUT, 120000). -define(LONG_TIMEOUT, 600000). -define(SLEEP, 1000). --define(OPENSSL_RENEGOTIATE, "r\n"). +-define(OPENSSL_RENEGOTIATE, "R\n"). -define(OPENSSL_QUIT, "Q\n"). -define(OPENSSL_GARBAGE, "P\n"). -define(EXPIRE, 10). -%% Test server callback functions -%%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initialization before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- -init_per_suite(Config0) -> - Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2), - case os:find_executable("openssl") of - false -> - {skip, "Openssl not found"}; - _ -> - catch crypto:stop(), - try crypto:start() of - ok -> - application:start(public_key), - ssl:start(), - Result = - (catch make_certs:all(?config(data_dir, Config0), - ?config(priv_dir, Config0))), - test_server:format("Make certs ~p~n", [Result]), - Config1 = ssl_test_lib:make_dsa_cert(Config0), - Config = ssl_test_lib:cert_options(Config1), - [{watchdog, Dog} | Config] - catch _:_ -> - {skip, "Crypto did not start"} - end - end. - -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto). - -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%% Description: Initialization before each test case -%%-------------------------------------------------------------------- -init_per_testcase(expired_session, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), - ssl:stop(), - application:load(ssl), - application:set_env(ssl, session_lifetime, ?EXPIRE), - ssl:start(), - [{watchdog, Dog} | Config]; - -init_per_testcase(TestCase, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?TIMEOUT), - special_init(TestCase, [{watchdog, Dog} | Config]). - -special_init(TestCase, Config) - when TestCase == erlang_client_openssl_server_renegotiate; - TestCase == erlang_client_openssl_server_no_wrap_sequence_number; - TestCase == erlang_server_openssl_client_no_wrap_sequence_number - -> - check_sane_openssl_renegotaite(Config); - -special_init(ssl2_erlang_server_openssl_client, Config) -> - check_sane_openssl_sslv2(Config); - -special_init(_, Config) -> - Config. - %%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case +%% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- -end_per_testcase(reuse_session_expired, Config) -> - application:unset_env(ssl, session_lifetime), - end_per_testcase(default_action, Config); - -end_per_testcase(default_action, Config) -> - Dog = ?config(watchdog, Config), - case Dog of - undefined -> - ok; - _ -> - test_server:timetrap_cancel(Dog) - end; -end_per_testcase(_, Config) -> - end_per_testcase(default_action, Config). -%%-------------------------------------------------------------------- -%% Function: all(Clause) -> TestCases -%% Clause - atom() - suite | doc -%% TestCases - [Case] -%% Case - atom() -%% Name of a test case. -%% Description: Returns a list of all test cases in this test suite -%%-------------------------------------------------------------------- suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -161,9 +50,9 @@ all() -> groups() -> [{basic, [], basic_tests()}, - {'tlsv1.2', [], all_versions_tests()}, - {'tlsv1.1', [], all_versions_tests()}, - {'tlsv1', [], all_versions_tests()}, + {'tlsv1.2', [], all_versions_tests() ++ npn_tests()}, + {'tlsv1.1', [], all_versions_tests() ++ npn_tests()}, + {'tlsv1', [], all_versions_tests()++ npn_tests()}, {'sslv3', [], all_versions_tests()}]. basic_tests() -> @@ -179,16 +68,54 @@ all_versions_tests() -> erlang_server_openssl_client_dsa_cert, erlang_server_openssl_client_reuse_session, erlang_client_openssl_server_renegotiate, - erlang_client_openssl_server_no_wrap_sequence_number, - erlang_server_openssl_client_no_wrap_sequence_number, + erlang_client_openssl_server_nowrap_seqnum, + erlang_server_openssl_client_nowrap_seqnum, erlang_client_openssl_server_no_server_ca_cert, erlang_client_openssl_server_client_cert, erlang_server_openssl_client_client_cert, ciphers_rsa_signed_certs, ciphers_dsa_signed_certs, erlang_client_bad_openssl_server, - ssl2_erlang_server_openssl_client - ]. + expired_session, + ssl2_erlang_server_openssl_client]. + +npn_tests() -> + [erlang_client_openssl_server_npn, + erlang_server_openssl_client_npn, + erlang_server_openssl_client_npn_renegotiate, + erlang_client_openssl_server_npn_renegotiate, + erlang_server_openssl_client_npn_only_client, + erlang_server_openssl_client_npn_only_server, + erlang_client_openssl_server_npn_only_client, + erlang_client_openssl_server_npn_only_server]. + + +init_per_suite(Config0) -> + Dog = ct:timetrap(?LONG_TIMEOUT *2), + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + catch crypto:stop(), + try crypto:start() of + ok -> + application:start(public_key), + ssl:start(), + Result = + (catch make_certs:all(?config(data_dir, Config0), + ?config(priv_dir, Config0))), + ct:print("Make certs ~p~n", [Result]), + Config1 = ssl_test_lib:make_dsa_cert(Config0), + Config = ssl_test_lib:cert_options(Config1), + [{watchdog, Dog} | Config] + catch _:_ -> + {skip, "Crypto did not start"} + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). init_per_group(GroupName, Config) -> case ssl_test_lib:is_tls_version(GroupName) of @@ -208,13 +135,55 @@ init_per_group(GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(expired_session, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ct:timetrap(?EXPIRE * 1000 * 5), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, ?EXPIRE), + ssl:start(), + [{watchdog, Dog} | Config]; + +init_per_testcase(TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ct:timetrap(?TIMEOUT), + special_init(TestCase, [{watchdog, Dog} | Config]). + +special_init(TestCase, Config) + when TestCase == erlang_client_openssl_server_renegotiate; + TestCase == erlang_client_openssl_server_nowrap_seqnum; + TestCase == erlang_server_openssl_client_nowrap_seqnum + -> + check_sane_openssl_renegotaite(Config); + +special_init(ssl2_erlang_server_openssl_client, Config) -> + check_sane_openssl_sslv2(Config); + +special_init(TestCase, Config) + when TestCase == erlang_client_openssl_server_npn; + TestCase == erlang_server_openssl_client_npn; + TestCase == erlang_server_openssl_client_npn_renegotiate; + TestCase == erlang_client_openssl_server_npn_renegotiate; + TestCase == erlang_server_openssl_client_npn_only_server; + TestCase == erlang_server_openssl_client_npn_only_client; + TestCase == erlang_client_openssl_server_npn_only_client; + TestCase == erlang_client_openssl_server_npn_only_server -> + check_openssl_npn_support(Config); + +special_init(_, Config) -> + Config. + +end_per_testcase(reuse_session_expired, Config) -> + application:unset_env(ssl, session_lifetime), + Config; +end_per_testcase(_, Config) -> + Config. -%% Test cases starts here. %%-------------------------------------------------------------------- -basic_erlang_client_openssl_server(doc) -> - ["Test erlang client with openssl server"]; -basic_erlang_client_openssl_server(suite) -> - []; +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +basic_erlang_client_openssl_server() -> + [{doc,"Test erlang client with openssl server"}]. basic_erlang_client_openssl_server(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -231,7 +200,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -250,14 +219,11 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -basic_erlang_server_openssl_client(doc) -> - ["Test erlang server with openssl client"]; -basic_erlang_server_openssl_client(suite) -> - []; +basic_erlang_server_openssl_client() -> + [{doc,"Test erlang server with openssl client"}]. basic_erlang_server_openssl_client(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -275,7 +241,7 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ " -host localhost", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), port_command(OpenSslPort, Data), @@ -288,10 +254,8 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) -> process_flag(trap_exit, false), ok. %%-------------------------------------------------------------------- -erlang_client_openssl_server(doc) -> - ["Test erlang client with openssl server"]; -erlang_client_openssl_server(suite) -> - []; +erlang_client_openssl_server() -> + [{doc,"Test erlang client with openssl server"}]. erlang_client_openssl_server(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -308,7 +272,7 @@ erlang_client_openssl_server(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -327,15 +291,11 @@ erlang_client_openssl_server(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. - + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_server_openssl_client(doc) -> - ["Test erlang server with openssl client"]; -erlang_server_openssl_client(suite) -> - []; +erlang_server_openssl_client() -> + [{doc,"Test erlang server with openssl client"}]. erlang_server_openssl_client(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -354,7 +314,7 @@ erlang_server_openssl_client(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), port_command(OpenSslPort, Data), @@ -364,15 +324,12 @@ erlang_server_openssl_client(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_client_openssl_server_dsa_cert(doc) -> - ["Test erlang server with openssl client"]; -erlang_client_openssl_server_dsa_cert(suite) -> - []; +erlang_client_openssl_server_dsa_cert() -> + [{doc,"Test erlang server with openssl client"}]. erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_dsa_opts, Config), @@ -392,7 +349,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile ++ " -key " ++ KeyFile ++ " -Verify 2 -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -415,10 +372,8 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> process_flag(trap_exit, false), ok. %%-------------------------------------------------------------------- -erlang_server_openssl_client_dsa_cert(doc) -> - ["Test erlang server with openssl client"]; -erlang_server_openssl_client_dsa_cert(suite) -> - []; +erlang_server_openssl_client_dsa_cert() -> + [{doc,"Test erlang server with openssl client"}]. erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_dsa_opts, Config), @@ -441,7 +396,7 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> " -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile ++ " -key " ++ KeyFile ++ " -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), port_command(OpenSslPort, Data), @@ -451,16 +406,13 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_server_openssl_client_reuse_session(doc) -> - ["Test erlang server with openssl client that reconnects with the" - "same session id, to test reusing of sessions."]; -erlang_server_openssl_client_reuse_session(suite) -> - []; +erlang_server_openssl_client_reuse_session() -> + [{doc, "Test erlang server with openssl client that reconnects with the" + "same session id, to test reusing of sessions."}]. erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -479,7 +431,7 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost -reconnect", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -495,10 +447,8 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -erlang_client_openssl_server_renegotiate(doc) -> - ["Test erlang client when openssl server issuses a renegotiate"]; -erlang_client_openssl_server_renegotiate(suite) -> - []; +erlang_client_openssl_server_renegotiate() -> + [{doc,"Test erlang client when openssl server issuses a renegotiate"}]. erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -517,7 +467,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -531,7 +481,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> {options, ClientOpts}]), port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), port_command(OpensslPort, OpenSslData), ssl_test_lib:check_result(Client, ok), @@ -544,14 +494,12 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -erlang_client_openssl_server_no_wrap_sequence_number(doc) -> - ["Test that erlang client will renegotiate session when", +erlang_client_openssl_server_nowrap_seqnum() -> + [{doc, "Test that erlang client will renegotiate session when", "max sequence number celing is about to be reached. Although" "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."]; -erlang_client_openssl_server_no_wrap_sequence_number(suite) -> - []; -erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config) -> + " to lower treashold substantially."}]. +erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), ClientOpts = ?config(client_opts, Config), @@ -568,7 +516,7 @@ erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -587,18 +535,14 @@ erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_server_openssl_client_no_wrap_sequence_number(doc) -> - ["Test that erlang client will renegotiate session when", +erlang_server_openssl_client_nowrap_seqnum() -> + [{doc, "Test that erlang client will renegotiate session when", "max sequence number celing is about to be reached. Although" "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."]; - -erlang_server_openssl_client_no_wrap_sequence_number(suite) -> - []; -erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config) -> + " to lower treashold substantially."}]. +erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -618,7 +562,7 @@ erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -629,16 +573,14 @@ erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). + %%-------------------------------------------------------------------- -erlang_client_openssl_server_no_server_ca_cert(doc) -> - ["Test erlang client when openssl server sends a cert chain not" +erlang_client_openssl_server_no_server_ca_cert() -> + [{doc, "Test erlang client when openssl server sends a cert chain not" "including the ca cert. Explicitly test this even if it is" - "implicitly tested eleswhere."]; -erlang_client_openssl_server_no_server_ca_cert(suite) -> - []; + "implicitly tested eleswhere."}]. erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -655,7 +597,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -675,14 +617,11 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_client_openssl_server_client_cert(doc) -> - ["Test erlang client with openssl server when client sends cert"]; -erlang_client_openssl_server_client_cert(suite) -> - []; +erlang_client_openssl_server_client_cert() -> + [{doc,"Test erlang client with openssl server when client sends cert"}]. erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), @@ -701,7 +640,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile ++ " -key " ++ KeyFile ++ " -Verify 2", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -720,15 +659,12 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_server_openssl_client_client_cert(doc) -> - ["Test erlang server with openssl client when client sends cert"]; -erlang_server_openssl_client_client_cert(suite) -> - []; +erlang_server_openssl_client_client_cert() -> + [{doc,"Test erlang server with openssl client when client sends cert"}]. erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), @@ -755,7 +691,7 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), port_command(OpenSslPort, Data), @@ -765,16 +701,12 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> %% Clean close down! Server needs to be closed first !! close_port(OpenSslPort), ssl_test_lib:close(Server), - process_flag(trap_exit, false), - ok. - + process_flag(trap_exit, false). %%-------------------------------------------------------------------- -erlang_server_erlang_client_client_cert(doc) -> - ["Test erlang server with erlang client when client sends cert"]; -erlang_server_erlang_client_client_cert(suite) -> - []; +erlang_server_erlang_client_client_cert() -> + [{doc,"Test erlang server with erlang client when client sends cert"}]. erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), @@ -807,30 +739,22 @@ erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. -%%-------------------------------------------------------------------- + process_flag(trap_exit, false). -ciphers_rsa_signed_certs(doc) -> - ["Test cipher suites that uses rsa certs"]; - -ciphers_rsa_signed_certs(suite) -> - []; +%%-------------------------------------------------------------------- +ciphers_rsa_signed_certs() -> + [{doc,"Test cipher suites that uses rsa certs"}]. ciphers_rsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:rsa_suites(), run_suites(Ciphers, Version, Config, rsa). +%%-------------------------------------------------------------------- - -ciphers_dsa_signed_certs(doc) -> - ["Test cipher suites that uses dsa certs"]; - -ciphers_dsa_signed_certs(suite) -> - []; - +ciphers_dsa_signed_certs() -> + [{doc,"Test cipher suites that uses dsa certs"}]. ciphers_dsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), @@ -838,90 +762,9 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) -> Ciphers = ssl_test_lib:dsa_suites(), run_suites(Ciphers, Version, Config, dsa). -run_suites(Ciphers, Version, Config, Type) -> - {ClientOpts, ServerOpts} = - case Type of - rsa -> - {?config(client_opts, Config), - ?config(server_opts, Config)}; - dsa -> - {?config(client_opts, Config), - ?config(server_dsa_opts, Config)} - end, - - Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, - Ciphers), - case lists:flatten(Result) of - [] -> - ok; - Error -> - test_server:format("Cipher suite errors: ~p~n", [Error]), - test_server:fail(cipher_suite_failed_see_test_case_log) - end. - -cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> - process_flag(trap_exit, true), - test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), - {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - - wait_for_openssl_server(), - - ConnectionInfo = {ok, {Version, CipherSuite}}, - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, - {options, - [{ciphers,[CipherSuite]} | - ClientOpts]}]), - - port_command(OpenSslPort, "Hello\n"), - - receive - {Port, {data, _}} when is_port(Port) -> - ok - after 500 -> - test_server:format("Time out on openssl port, check that" - " the messages Hello and world are received" - " during close of port" , []), - ok - end, - - port_command(OpenSslPort, " world\n"), - - Result = ssl_test_lib:wait_for_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - close_port(OpenSslPort), - ssl_test_lib:close(Client), - - Return = case Result of - ok -> - []; - Error -> - [{CipherSuite, Error}] - end, - process_flag(trap_exit, false), - Return. - %%-------------------------------------------------------------------- -erlang_client_bad_openssl_server(doc) -> - [""]; -erlang_client_bad_openssl_server(suite) -> - []; +erlang_client_bad_openssl_server() -> + [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}]. erlang_client_bad_openssl_server(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), @@ -936,7 +779,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -952,7 +795,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> %% Send garbage port_command(OpensslPort, ?OPENSSL_GARBAGE), - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), Client0 ! server_sent_garbage, @@ -976,13 +819,9 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -expired_session(doc) -> - ["Test our ssl client handling of expired sessions. Will make" - "better code coverage of the ssl_manager module"]; - -expired_session(suite) -> - []; - +expired_session() -> + [{doc, "Test our ssl client handling of expired sessions. Will make" + "better code coverage of the ssl_manager module"}]. expired_session(Config) when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_opts, Config), @@ -996,7 +835,7 @@ expired_session(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -1011,7 +850,7 @@ expired_session(Config) when is_list(Config) -> ssl_test_lib:close(Client0), %% Make sure session is registered - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), Client1 = ssl_test_lib:start_client([{node, ClientNode}, @@ -1021,7 +860,7 @@ expired_session(Config) when is_list(Config) -> ssl_test_lib:close(Client1), %% Make sure session is unregistered due to expiration - test_server:sleep((?EXPIRE+1) * 1000), + ct:sleep((?EXPIRE+1) * 1000), Client2 = ssl_test_lib:start_client([{node, ClientNode}, @@ -1035,10 +874,9 @@ expired_session(Config) when is_list(Config) -> process_flag(trap_exit, false). %%-------------------------------------------------------------------- -ssl2_erlang_server_openssl_client(doc) -> - ["Test that ssl v2 clients are rejected"]; -ssl2_erlang_server_openssl_client(suite) -> - []; +ssl2_erlang_server_openssl_client() -> + [{doc,"Test that ssl v2 clients are rejected"}]. + ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -1055,23 +893,339 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ " -host localhost -ssl2 -msg", - test_server:format("openssl cmd: ~p~n", [Cmd]), + ct:print("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, {error,"protocol version"}), - + receive + {'EXIT', OpenSslPort, _} -> + ok + + end, + ssl_test_lib:check_result(Server, {error, {essl, "protocol version"}}), + process_flag(trap_exit, false). + +%%-------------------------------------------------------------------- +erlang_client_openssl_server_npn() -> + [{doc,"Test erlang client with openssl server doing npn negotiation"}]. + +erlang_client_openssl_server_npn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> + port_command(OpensslPort, Data), + + ssl_test_lib:check_result(Client, ok) + end), + ok. + +%%-------------------------------------------------------------------- +erlang_client_openssl_server_npn_renegotiate() -> + [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}]. + +erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> + port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, ok) + end), + ok. +%%-------------------------------------------------------------------------- +erlang_server_openssl_client_npn() -> + [{doc,"Test erlang server with openssl client and npn negotiation"}]. + +erlang_server_openssl_client_npn(Config) when is_list(Config) -> + + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, ok) + end), + ok. + +%%-------------------------------------------------------------------------- +erlang_server_openssl_client_npn_renegotiate() -> + [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}]. + +erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> + port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, ok) + end), + ok. +%%-------------------------------------------------------------------------- +erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_with_opts(Config, [], + "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) -> + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, ok) + end), + ok. + +%%-------------------------------------------------------------------------- + +erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_with_opts(Config, + [{client_preferred_next_protocols, + {client, [<<"spdy/2">>], <<"http/1.1">>}}], "", + Data, fun(Server, OpensslPort) -> + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, ok) + end), + ok. + +%%-------------------------------------------------------------------------- +erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "", + Data, fun(Server, OpensslPort) -> + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, ok) + end), + ok. + +erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2", + Data, fun(Server, OpensslPort) -> + port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, ok) + end), + ok. + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +run_suites(Ciphers, Version, Config, Type) -> + {ClientOpts, ServerOpts} = + case Type of + rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; + dsa -> + {?config(client_opts, Config), + ?config(server_dsa_opts, Config)} + end, + + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + ct:print("Cipher suite errors: ~p~n", [Error]), + ct:fail(cipher_suite_failed_see_test_case_log) + end. + +cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> + process_flag(trap_exit, true), + ct:print("Testing CipherSuite ~p~n", [CipherSuite]), + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", + + ct:print("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + wait_for_openssl_server(), + + ConnectionInfo = {ok, {Version, CipherSuite}}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, + {options, + [{ciphers,[CipherSuite]} | + ClientOpts]}]), + + port_command(OpenSslPort, "Hello\n"), + + receive + {Port, {data, _}} when is_port(Port) -> + ok + after 500 -> + ct:print("Time out on openssl port, check that" + " the messages Hello and world are received" + " during close of port" , []), + ok + end, + + port_command(OpenSslPort, " world\n"), + + Result = ssl_test_lib:wait_for_result(Client, ok), + %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), close_port(OpenSslPort), + ssl_test_lib:close(Client), + + Return = case Result of + ok -> + []; + Error -> + [{CipherSuite, Error}] + end, process_flag(trap_exit, false), - ok. + Return. -%%-------------------------------------------------------------------- +start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts0 = ?config(client_opts, Config), + ClientOpts = ErlangClientOpts ++ ClientOpts0, + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Cmd = "openssl s_server " ++ OpensslServerOpts ++ " -accept " ++ + integer_to_list(Port) ++ version_flag(Version) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile, + + ct:print("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + wait_for_openssl_server(), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, ClientOpts}]), + + Callback(Client, OpensslPort), + + %% Clean close down! Server needs to be closed first !! + close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false). + +start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts0 = ?config(client_opts, Config), + ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0], + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile, + + ct:print("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + wait_for_openssl_server(), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive_and_assert_npn, [<<"spdy/2">>, Data]}}, + {options, ClientOpts}]), + + Callback(Client, OpensslPort), + + %% Clean close down! Server needs to be closed first !! + close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false). + +start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts0 = ?config(server_opts, Config), + ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]}, ServerOpts0], + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive_and_assert_npn, [<<"spdy/2">>, Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -host localhost", + + ct:print("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + Callback(Server, OpenSslPort), + + ssl_test_lib:close(Server), + + close_port(OpenSslPort), + process_flag(trap_exit, false). + + +start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts0 = ?config(server_opts, Config), + ServerOpts = ErlangServerOpts ++ ServerOpts0, + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ + " -host localhost", + + ct:print("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + Callback(Server, OpenSslPort), + + ssl_test_lib:close(Server), + + close_port(OpenSslPort), + process_flag(trap_exit, false). + + +erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) -> + {ok, Protocol} = ssl:negotiated_next_protocol(Socket), + erlang_ssl_receive(Socket, Data), + {ok, Protocol} = ssl:negotiated_next_protocol(Socket), + ok. erlang_ssl_receive(Socket, Data) -> - test_server:format("Connection info: ~p~n", + ct:print("Connection info: ~p~n", [ssl:connection_info(Socket)]), receive {ssl, Socket, Data} -> @@ -1085,15 +1239,15 @@ erlang_ssl_receive(Socket, Data) -> io:format("openssl ~s~n",[Debug]), erlang_ssl_receive(Socket,Data); Other -> - test_server:fail({unexpected_message, Other}) + ct:fail({unexpected_message, Other}) after 4000 -> - test_server:fail({did_not_get, Data}) + ct:fail({did_not_get, Data}) end. connection_info(Socket, Version) -> case ssl:connection_info(Socket) of {ok, {Version, _} = Info} -> - test_server:format("Connection info: ~p~n", [Info]), + ct:print("Connection info: ~p~n", [Info]), ok; {ok, {OtherVersion, _}} -> {wrong_version, OtherVersion} @@ -1104,7 +1258,7 @@ connection_info_result(Socket) -> delayed_send(Socket, [ErlData, OpenSslData]) -> - test_server:sleep(?SLEEP), + ct:sleep(?SLEEP), ssl:send(Socket, ErlData), erlang_ssl_receive(Socket, OpenSslData). @@ -1156,7 +1310,7 @@ wait_for_openssl_server() -> %% it will be in accept. Parsing %% output is too error prone. (Even %% more so than sleep!) - test_server:sleep(?SLEEP) + ct:sleep(?SLEEP) end. version_flag(tlsv1) -> @@ -1168,6 +1322,15 @@ version_flag('tlsv1.2') -> version_flag(sslv3) -> " -ssl3 ". +check_openssl_npn_support(Config) -> + HelpText = os:cmd("openssl s_client --help"), + case string:str(HelpText, "nextprotoneg") of + 0 -> + {skip, "Openssl not compiled with nextprotoneg support"}; + _ -> + Config + end. + check_sane_openssl_renegotaite(Config) -> case os:cmd("openssl version") of "OpenSSL 0.9.8" ++ _ -> @@ -1179,11 +1342,27 @@ check_sane_openssl_renegotaite(Config) -> end. check_sane_openssl_sslv2(Config) -> - case os:cmd("openssl version") of - "OpenSSL 1." ++ _ -> - {skip, "sslv2 by default turned of in 1.*"}; - _ -> - Config + Port = open_port({spawn, "openssl s_client -ssl2 "}, [stderr_to_stdout]), + case supports_sslv2(Port) of + true -> + Config; + false -> + {skip, "sslv2 not supported by openssl"} + end. + +supports_sslv2(Port) -> + receive + {Port, {data, "unknown option -ssl2" ++ _}} -> + false; + {Port, {data, Data}} -> + case lists:member("error", string:tokens(Data, ":")) of + true -> + false; + false -> + supports_sslv2(Port) + end + after 500 -> + true end. check_sane_openssl_version(Version) -> diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index adfb29e639..cb73e86ede 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 5.1.2 +SSL_VSN = 5.2 |