1/* Part of SWI-Prolog 2 3 Author: Jan van der Steen, Matt Lilley and Jan Wielemaker, 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2004-2017, SWI-Prolog Foundation 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(ssl, 37 [ load_certificate/2, % +Stream, -Certificate 38 load_private_key/3, % +Stream, +Password, -Key 39 load_public_key/2, % +Stream, -Key 40 load_crl/2, % +Stream, -Crl 41 system_root_certificates/1, % -List 42 cert_accept_any/5, % +SSL, +ProblemCertificate, 43 % +AllCertificates, +FirstCertificate, 44 % +Error 45 ssl_context/3, % +Role, -Config, :Options 46 ssl_add_certificate_key/4, % +Config, +Cert, +Key, -Config 47 ssl_set_options/3, % +Config0, -Config, +Options 48 ssl_negotiate/5, % +Config, +PlainRead, +PlainWrite, 49 % -SSLRead, -SSLWrite 50 ssl_peer_certificate/2, % +Stream, -Certificate 51 ssl_peer_certificate_chain/2, % +Stream, -Certificates 52 ssl_session/2, % +Stream, -Session 53 ssl_secure_ciphers/1 % -Ciphers 54 ]). 55:- use_module(library(option)). 56:- use_module(library(settings)). 57:- use_module(library(crypto), []). % force initialization of libcrypto 58 59:- use_foreign_library(foreign(ssl4pl)). 60 61:- meta_predicate 62 ssl_context( , , ), 63 ssl_set_options( , , ). 64 65:- predicate_options(ssl_context/3, 3, 66 [ host(atom), 67 port(integer), 68 certificate_file(atom), 69 key_file(atom), 70 certificate_key_pairs(any), 71 password(any), 72 cipher_list(any), 73 ecdh_curve(any), 74 pem_password_hook(callable), 75 cacert_file(any), 76 crl(any), 77 require_crl(boolean), 78 cert_verify_hook(callable), 79 peer_cert(boolean), 80 close_parent(boolean), 81 close_notify(boolean), 82 sni_hook(callable) 83 ]). 84 85/** <module> Secure Socket Layer (SSL) library 86 87An SSL server and client can be built with the (abstracted) 88predicate calls from the table below. The `tcp_` predicates 89are provided by library(socket). The predicate ssl_context/3 90defines properties of the SSL connection, while ssl_negotiate/5 91establishes the SSL connection based on the wire streams created 92by the TCP predicates and the context. 93 94 | *The SSL Server* | *The SSL Client* | 95 | ssl_context/3 | ssl_context/3 | 96 | tcp_socket/1 | | 97 | tcp_accept/3 | tcp_connect/3 | 98 | tcp_open_socket/3 | stream_pair/3 | 99 | ssl_negotiate/5 | ssl_negotiate/5 | 100 101The library is abstracted to communication over streams, and is not 102reliant on those streams being directly attached to sockets. The `tcp_` 103calls here are simply the most common way to use the library. Other 104two-way communication channels such as (named), pipes can just as 105easily be used. 106 107@see library(socket), library(http/http_open), library(crypto) 108*/ 109 110:- setting(secure_ciphers, atom, 111 'EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256:EECDH+CHACHA20:EDH+CHACHA20', 112 "Default set of ciphers considered secure"). 113 114%! ssl_context(+Role, -SSL, :Options) is det. 115% 116% Create an SSL context. The context defines several properties 117% of the SSL connection such as involved keys, preferred 118% encryption, and passwords. After establishing a context, an SSL 119% connection can be negotiated using ssl_negotiate/5, turning two 120% arbitrary plain Prolog streams into encrypted streams. This 121% predicate processes the options below. 122% 123% * host(+HostName) 124% For the client, the host to which it connects. This option 125% _should_ be specified when Role is `client`. Otherwise, 126% certificate verification may fail when negotiating a 127% secure connection. 128% * certificate_file(+FileName) 129% Specify where the certificate file can be found. This can be the 130% same as the key_file(+FileName) option. A server _must_ have at 131% least one certificate before clients can connect. A client 132% _must_ have a certificate only if the server demands the client 133% to identify itself with a client certificate using the 134% peer_cert(true) option. If a certificate is provided, it is 135% necessary to also provide a matching _private key_ via the 136% key_file/1 option. To configure multiple certificates, use the 137% option certificate_key_pairs/1 instead. Alternatively, use 138% ssl_add_certificate_key/4 to add certificates and keys to an 139% existing context. 140% * key_file(+FileName) 141% Specify where the private key that matches the certificate can 142% be found. If the key is encrypted with a password, this must 143% be supplied using the password(+Text) or 144% =|pem_password_hook(:Goal)|= option. 145% * certificate_key_pairs(+Pairs) 146% Alternative method for specifying certificates and keys. The 147% argument is a list of _pairs_ of the form Certificate-Key, 148% where each component is a string or an atom that holds, 149% respectively, the PEM-encoded certificate and key. To each 150% certificate, further certificates of the chain can be 151% appended. Multiple types of certificates can be present at 152% the same time to enable different ciphers. Using multiple 153% certificate types with completely independent certificate 154% chains requires OpenSSL 1.0.2 or greater. 155% * password(+Text) 156% Specify the password the private key is protected with (if 157% any). If you do not want to store the password you can also 158% specify an application defined handler to return the password 159% (see next option). Text is either an atom or string. Using 160% a string is preferred as strings are volatile and local 161% resources. 162% * pem_password_hook(:Goal) 163% In case a password is required to access the private key the 164% supplied predicate will be called to fetch it. The hook is 165% called as call(Goal, +SSL, -Password) and typically unifies 166% `Password` with a _string_ containing the password. 167% * require_crl(+Boolean) 168% If true (default is false), then all certificates will be 169% considered invalid unless they can be verified as not being 170% revoked. You can do this explicity by passing a list of CRL 171% filenames via the crl/1 option, or by doing it yourself in 172% the cert_verify_hook. If you specify require_crl(true) and 173% provide neither of these options, verification will necessarily 174% fail 175% * crl(+ListOfFileNames) 176% Provide a list of filenames of PEM-encoded CRLs that will be 177% given to the context to attempt to establish that a chain of 178% certificates is not revoked. You must also set require_crl(true) 179% if you want CRLs to actually be checked by OpenSSL. 180% * cacert_file(+FileName) 181% Specify a file containing certificate keys of _trusted_ 182% certificates. The peer is trusted if its certificate is 183% signed (ultimately) by one of the provided certificates. Using 184% the FileName `system(root_certificates)` uses a list of 185% trusted root certificates as provided by the OS. See 186% system_root_certificates/1 for details. 187% 188% Additional verification of the peer certificate as well as 189% accepting certificates that are not trusted by the given set 190% can be realised using the hook 191% cert_verify_hook(:Goal). 192% * cert_verify_hook(:Goal) 193% The predicate ssl_negotiate/5 calls Goal as follows: 194% 195% == 196% call(Goal, +SSL, 197% +ProblemCertificate, +AllCertificates, +FirstCertificate, 198% +Error) 199% == 200% 201% In case the certificate was verified by one of the provided 202% certifications from the `cacert_file` option, Error is unified 203% with the atom `verified`. Otherwise it contains the error 204% string passed from OpenSSL. Access will be granted iff the 205% predicate succeeds. See load_certificate/2 for a description 206% of the certificate terms. See cert_accept_any/5 for a dummy 207% implementation that accepts any certificate. 208% * cipher_list(+Atom) 209% Specify a cipher preference list (one or more cipher strings 210% separated by colons, commas or spaces). 211% * ecdh_curve(+Atom) 212% Specify a curve for ECDHE ciphers. If this option is not 213% specified, the OpenSSL default parameters are used. With 214% OpenSSL prior to 1.1.0, `prime256v1` is used by default. 215% * peer_cert(+Boolean) 216% Trigger the request of our peer's certificate while 217% establishing the SSL layer. This option is automatically 218% turned on in a client SSL socket. It can be used in a server 219% to ask the client to identify itself using an SSL certificate. 220% * close_parent(+Boolean) 221% If `true`, close the raw streams if the SSL streams are closed. 222% Default is `false`. 223% * close_notify(+Boolean) 224% If `true` (default is `false`), the server sends TLS 225% `close_notify` when closing the connection. In addition, 226% this mitigates _truncation attacks_ for both client and 227% server role: If EOF is encountered without having received a 228% TLS shutdown, an exception is raised. Well-designed 229% protocols are self-terminating, and this attack is therefore 230% very rarely a concern. 231% * min_protocol_version(+Atom) 232% Set the _minimum_ protocol version that can be negotiated. 233% Atom is one of `sslv3`, `tlsv1`, `tlsv1_1` and `tlsv1_2`. 234% This option is available with OpenSSL 1.1.0 and later, and 235% should be used instead of `disable_ssl_methods/1`. 236% * max_protocol_version(+Atom) 237% Set the _maximum_ protocol version that can be negotiated. 238% Atom is one of `sslv3`, `tlsv1`, `tlsv1_1` and `tlsv1_2`. 239% This option is available with OpenSSL 1.1.0 and later, and 240% should be used instead of `disable_ssl_methods/1`. 241% * disable_ssl_methods(+List) 242% A list of methods to disable. Unsupported methods will be 243% ignored. Methods include `sslv2`, `sslv3`, `sslv23`, 244% `tlsv1`, `tlsv1_1` and `tlsv1_2`. This option is deprecated 245% starting with OpenSSL 1.1.0. Use min_protocol_version/1 and 246% max_protocol_version/1 instead. 247% * ssl_method(+Method) 248% Specify the explicit Method to use when negotiating. For 249% allowed values, see the list for `disable_ssl_methods` above. 250% Using this option is discouraged. When using OpenSSL 1.1.0 251% or later, this option is ignored, and a version-flexible method 252% is used to negotiate the connection. Using version-specific 253% methods is deprecated in recent OpenSSL versions, and this 254% option will become obsolete and ignored in the future. 255% * sni_hook(:Goal) 256% This option provides Server Name Indication (SNI) for SSL 257% servers. This means that depending on the host to which a 258% client connects, different options (certificates etc.) can 259% be used for the server. This TLS extension allows you to host 260% different domains using the same IP address and physical 261% machine. When a TLS connection is negotiated with a client 262% that has provided a host name via SNI, the hook is called as 263% follows: 264% 265% == 266% call(Goal, +SSL0, +HostName, -SSL) 267% == 268% 269% Given the current context SSL0, and the host name of the 270% client request, the predicate computes SSL which is used as 271% the context for negotiating the connection. The first solution 272% is used. If the predicate fails, the default options are 273% used, which are those of the encompassing ssl_context/3 274% call. In that case, if no default certificate and key are 275% specified, the client connection is rejected. 276% 277% @arg Role is one of `server` or `client` and denotes whether the 278% SSL instance will have a server or client role in the 279% established connection. 280% @arg SSL is a SWI-Prolog _blob_ of type `ssl_context`, i.e., the 281% type-test for an SSL context is `blob(SSL, ssl_context)`. 282 283ssl_context(Role, SSL, Module:Options) :- 284 select_option(ssl_method(Method), Options, O1, sslv23), 285 '_ssl_context'(Role, SSL, Module:O1, Method). 286 287%! ssl_add_certificate_key(+SSL0, +Certificate, +Key, -SSL) 288% 289% Add an additional certificate/key pair to SSL0, yielding SSL. 290% Certificate and Key are either strings or atoms that hold the 291% PEM-encoded certificate plus certificate chain and private key, 292% respectively. Using strings is preferred for security reasons. 293% 294% This predicate allows dual-stack RSA and ECDSA servers (for 295% example), and is an alternative for using the 296% `certificate_key_pairs/1` option. As of OpenSSL 1.0.2, multiple 297% certificate types with completely independent certificate chains 298% are supported. If a certificate of the same type is added 299% repeatedly to a context, the result is undefined. Currently, up to 300% 12 additional certificates of different types are admissible. 301 302ssl_add_certificate_key(SSL0, Cert, Key, SSL) :- 303 ssl_copy_context(SSL0, SSL), 304 '_ssl_add_certificate_key'(SSL, Cert, Key). 305 306ssl_copy_context(SSL0, SSL) :- 307 ssl_context(server, SSL, []), 308 '_ssl_init_from_context'(SSL0, SSL). 309 310%! ssl_set_options(+SSL0, -SSL, +Options) 311% 312% SSL is the same as SSL0, except for the options specified in 313% Options. The following options are supported: close_notify/1, 314% close_parent/1, host/1, peer_cert/1, ecdh_curve/1, 315% min_protocol_version/1, max_protocol_version/1, 316% disable_ssl_methods/1, sni_hook/1, cert_verify_hook/1. See 317% ssl_context/3 for more information about these options. This 318% predicate allows you to tweak existing SSL contexts, which can be 319% useful in hooks when creating servers with the HTTP 320% infrastructure. 321 322ssl_set_options(SSL0, SSL, Options) :- 323 ssl_copy_context(SSL0, SSL), 324 '_ssl_set_options'(SSL, Options). 325 326%! ssl_negotiate(+SSL, 327%! +PlainRead, +PlainWrite, 328%! -SSLRead, -SSLWrite) is det. 329% 330% Once a connection is established and a read/write stream pair is 331% available, (PlainRead and PlainWrite), this predicate can be 332% called to negotiate an SSL session over the streams. If the 333% negotiation is successful, SSLRead and SSLWrite are returned. 334% 335% After a successful handshake and finishing the communication the 336% user must close SSLRead and SSLWrite, for example using 337% call_cleanup(close(SSLWrite), close(SSLRead)). If the SSL 338% _context_ (created with ssl_context/3 has the option 339% close_parent(true) (default `false`), closing SSLRead and 340% SSLWrite also closes the original PlainRead and PlainWrite 341% streams. Otherwise these must be closed explicitly by the user. 342% 343% @error ssl_error(Code, LibName, FuncName, Reason) is raised 344% if the negotiation fails. The streams PlainRead and PlainWrite 345% are *not* closed, but an unknown amount of data may have been 346% read and written. 347 348%! ssl_peer_certificate(+Stream, -Certificate) is semidet. 349% 350% True if the peer certificate is provided (this is always the 351% case for a client connection) and Certificate unifies with the 352% peer certificate. The example below uses this to obtain the 353% _Common Name_ of the peer after establishing an https client 354% connection: 355% 356% == 357% http_open(HTTPS_url, In, []), 358% ssl_peer_certificate(In, Cert), 359% memberchk(subject(Subject), Cert), 360% memberchk('CN' = CommonName), Subject) 361% == 362 363%! ssl_peer_certificate_chain(+Stream, -Certificates) is det. 364% 365% Certificates is the certificate chain provided by the peer, 366% represented as a list of certificates. 367 368%! ssl_session(+Stream, -Session) is det. 369% 370% Retrieves (debugging) properties from the SSL context associated 371% with Stream. If Stream is not an SSL stream, the predicate 372% raises a domain error. Session is a list of properties, 373% containing the members described below. Except for `Version`, 374% all information are byte arrays that are represented as Prolog 375% strings holding characters in the range 0..255. 376% 377% * ssl_version(Version) 378% The negotiated version of the session as an integer. 379% * cipher(Cipher) 380% The negotiated cipher for this connection. 381% * session_key(Key) 382% The key material used in SSLv2 connections (if present). 383% * master_key(Key) 384% The key material comprising the master secret. This is 385% generated from the server_random, client_random and pre-master 386% key. 387% * client_random(Random) 388% The random data selected by the client during handshaking. 389% * server_random(Random) 390% The random data selected by the server during handshaking. 391% * session_id(SessionId) 392% The SSLv3 session ID. Note that if ECDHE is being used (which 393% is the default for newer versions of OpenSSL), this data will 394% not actually be sent to the server. 395 396%! load_certificate(+Stream, -Certificate) is det. 397% 398% Loads a certificate from a PEM- or DER-encoded stream, returning 399% a term which will unify with the same certificate if presented 400% in cert_verify_hook. A certificate is a list containing the 401% following terms: issuer_name/1, hash/1, signature/1, 402% signature_algorithm/1, version/1, notbefore/1, notafter/1, 403% serial/1, subject/1 and key/1. subject/1 and issuer_name/1 are 404% both lists of =/2 terms representing the name. With OpenSSL 405% 1.0.2 and greater, to_be_signed/1 is also available, yielding 406% the hexadecimal representation of the TBS (to-be-signed) portion 407% of the certificate. 408% 409% Note that the OpenSSL `CA.pl` utility creates certificates that 410% have a human readable textual representation in front of the PEM 411% representation. You can use the following to skip to the 412% certificate if you know it is a PEM certificate: 413% 414% == 415% skip_to_pem_cert(In) :- 416% repeat, 417% ( peek_char(In, '-') 418% -> ! 419% ; skip(In, 0'\n), 420% at_end_of_stream(In), ! 421% ). 422% == 423 424%! load_crl(+Stream, -CRL) is det. 425% 426% Loads a CRL from a PEM- or DER-encoded stream, returning a term 427% containing terms hash/1, signature/1, issuer_name/1 and 428% revocations/1, which is a list of revoked/2 terms. Each 429% revoked/2 term is of the form revoked(+Serial, DateOfRevocation) 430 431%! system_root_certificates(-List) is det. 432% 433% List is a list of trusted root certificates as provided by the 434% OS. This is the list used by ssl_context/3 when using the option 435% `system(root_certificates)`. The list is obtained using an OS 436% specific process. The current implementation is as follows: 437% 438% - On Windows, CertOpenSystemStore() is used to import 439% the `"ROOT"` certificates from the OS. 440% - On MacOSX, the trusted keys are loaded from the 441% _SystemRootCertificates_ key chain. The Apple API 442% for this requires the SSL interface to be compiled 443% with an XCode compiler, i.e., *not* with native gcc. 444% - Otherwise, certificates are loaded from a file defined 445% by the Prolog flag `system_cacert_filename`. The initial 446% value of this flag is operating system dependent. For 447% security reasons, the flag can only be set prior to using 448% the SSL library. For example: 449% 450% == 451% :- use_module(library(ssl)). 452% :- set_prolog_flag(system_cacert_filename, 453% '/home/jan/ssl/ca-bundle.crt'). 454% == 455 456%! load_private_key(+Stream, +Password, -PrivateKey) is det. 457% 458% Load a private key PrivateKey from the given stream Stream, 459% using Password to decrypt the key if it is encrypted. Note that 460% the password is currently only supported for PEM files. 461% DER-encoded keys which are password protected will not load. The 462% key must be an RSA or EC key. DH and DSA keys are not supported, 463% and PrivateKey will be bound to an atom (dh_key or dsa_key) if 464% you try and load such a key. Otherwise PrivateKey will be 465% unified with private_key(KeyTerm) where KeyTerm is an rsa/8 term 466% representing an RSA key, or ec/3 for EC keys. 467 468%! load_public_key(+Stream, -PublicKey) is det. 469% 470% Load a public key PublicKey from the given stream Stream. 471% Supports loading both DER- and PEM-encoded keys. The key must be 472% an RSA or EC key. DH and DSA keys are not supported, and 473% PublicKey will be bound to an atom (dh_key or dsa_key) if you 474% try and load such a key. Otherwise PublicKey will be unified 475% with public_key(KeyTerm) where KeyTerm is an rsa/8 term 476% representing an RSA key, or ec/3 for EC keys. 477 478 479%! cert_accept_any(+SSL, 480%! +ProblemCertificate, +AllCertificates, +FirstCertificate, 481%! +Error) is det. 482% 483% Implementation for the hook `cert_verify_hook(:Hook)` that 484% accepts _any_ certificate. This is intended for http_open/3 if 485% no certificate verification is desired as illustrated below. 486% 487% == 488% http_open('https:/...', In, 489% [ cert_verify_hook(cert_accept_any) 490% ]) 491% == 492 493cert_accept_any(_SSL, 494 _ProblemCertificate, _AllCertificates, _FirstCertificate, 495 _Error). 496 497%! ssl_secure_ciphers(-Ciphers:atom) is det. 498% 499% Secure ciphers must guarantee forward secrecy, and must mitigate all 500% known critical attacks. As of 2017, using the following ciphers 501% allows you to obtain grade A on https://www.ssllabs.com. For A+, you 502% must also enable HTTP Strict Transport Security (HSTS) by sending a 503% suitable header field in replies. 504% 505% Note that obsolete ciphers *must* be disabled to reliably prevent 506% protocol downgrade attacks. 507% 508% The Ciphers list is read from the setting `ssl:secure_ciphers` and 509% can be controlled using set_setting/2 and other predicates from 510% library(settings). 511% 512% *BEWARE*: This list must be changed when attacks on these ciphers 513% become known! Keep an eye on this setting and adapt it 514% as necessary in the future. 515 516ssl_secure_ciphers(Cs) :- 517 setting(secure_ciphers, Cs). 518 519 520 /******************************* 521 * MESSAGES * 522 *******************************/ 523 524:- multifile 525 prolog:error_message//1. 526 527prologerror_message(ssl_error(ID, _Library, Function, Reason)) --> 528 [ 'SSL(~w) ~w: ~w'-[ID, Function, Reason] ]