diff --git a/doc/base.pod b/doc/base.pod index 77f87b0d..68e059b4 100644 --- a/doc/base.pod +++ b/doc/base.pod @@ -483,7 +483,7 @@ Tell Swaks to use the system-default method of determining the current user's us These are options related to encrypting the transaction. These have been tested and confirmed to work with all three transport methods. The L module is used to perform encryption when it is requested. If this module is not loadable Swaks will either ignore the TLS request or error out, depending on whether the request was optional. STARTTLS is defined as an extension in the ESMTP protocol and will be unavailable if C<--protocol> is set to a variation of plain SMTP. Because it is not defined in the protocol itself, C<--tls-on-connect> is available for any protocol type if the target supports it. -A local certificate is not required for a TLS connection to be negotiated. However, some servers use client certificate checking to verify that the client is allowed to connect. Swaks can be told to use a specific local certificate using the C<--tls-cert> and C<--tls-key> options. +A local certificate is not required for a TLS connection to be negotiated. However, some servers use client certificate checking to verify that the client is allowed to connect. Swaks can be told to use a specific local certificate using the C<--tls-cert> and C<--tls-key> options, and optionally to use a certificate chain using the C<--tls-chain> option. =over 4 @@ -545,6 +545,10 @@ Provide a path to a file containing the local certificate Swaks should use if TL Provide a path to a file containing the local private key Swaks should use if TLS is negotiated. The file path argument is required. As currently implemented the certificate in the file must be in PEM format. Contact the author if there's a compelling need for ASN1. If this option is set, C<--tls-cert> is also required. (Arg-Required) +=item --tls-chain + +Provide a path to a file containing the local certificate chain (starting with the certificate followed by the necessary intermediate CA certificates) Swaks should use if TLS is negotiated. The file path argument is required. As currently implemented the certificate in the file must be in PEM format. Contact the author if there's a compelling need for ASN1. If this option is set, C<--tls-cert> and C<--tls-key> are also required. (Arg-Required) + =item --tls-get-peer-cert [] Get a copy of the TLS peer's certificate. If no argument is given, it will be displayed to C. If an argument is given it is assumed to be a filesystem path specifying where the certificate should be written. The saved certificate can then be examined using standard tools such as the openssl command. If a file is specified its contents will be overwritten. (Arg-Optional) diff --git a/swaks b/swaks index 5b57fd70..fbe9c6d8 100755 --- a/swaks +++ b/swaks @@ -530,6 +530,13 @@ sub start_tls { } } if ($G::tls_cert && $G::tls_key) { + if ($G::tls_chain) { + if (!Net::SSLeay::CTX_use_certificate_chain_file($t{con}, $G::tls_chain)) { + $t{res} = "Unable to set chain file $G::tls_chain to SSL CTX: " + . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error()); + return(0); + } + } if (!Net::SSLeay::CTX_use_certificate_file($t{con}, $G::tls_cert, &Net::SSLeay::FILETYPE_PEM)) { $t{res} = "Unable to add cert file $G::tls_cert to SSL CTX: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error()); @@ -1949,6 +1956,10 @@ sub get_option_struct { { opts => ['tls-key'], suffix => '=s', cfgs => OP_ARG_REQ, okey => 'tls_key', type => 'scalar', }, + # local chain to present to server + { opts => ['tls-chain'], suffix => '=s', + cfgs => OP_ARG_REQ, + okey => 'tls_chain', type => 'scalar', }, # tls protocol to use { opts => ['tls-protocol', 'tlsp'], suffix => '=s', cfgs => OP_ARG_REQ, @@ -3343,11 +3354,16 @@ sub process_args { $G::tls_sni_hostname = get_arg('tls_sni_hostname', $o); $G::tls_cipher = get_arg('tls_cipher', $o); $G::tls_cert = get_arg('tls_cert', $o); + $G::tls_chain = get_arg('tls_chain', $o); $G::tls_key = get_arg('tls_key', $o); if (($G::tls_cert || $G::tls_key) && !($G::tls_cert && $G::tls_key)) { ptrans(12, "--tls-cert and --tls-key require each other. Exiting"); exit(1); } + if (($G::tls_chain) && !($G::tls_cert && $G::tls_key)) { + ptrans(12, "--tls-chain requires also --tls-cert and --tls-key. Exiting"); + exit(1); + } if (($G::tls_ca_path = get_arg('tls_ca_path', $o)) && !-f $G::tls_ca_path && !-d $G::tls_ca_path) { ptrans(12, "--tls-ca-path: $G::tls_ca_path is not a valid file or directory. Exiting."); exit(1); @@ -3873,6 +3889,7 @@ sub get_running_state { " peer cert = $G::tls_get_peer_cert", " local cert = $G::tls_cert", " local key = $G::tls_key", + " local chain = $G::tls_chain", " local cipher list = $G::tls_cipher", " ca path = $G::tls_ca_path", " sni string = $G::tls_sni_hostname",