Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for --tls-chain #60

Merged
merged 1 commit into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion doc/base.pod
Original file line number Diff line number Diff line change
Expand Up @@ -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<Net::SSLeay> 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

Expand Down Expand Up @@ -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 <chain-file>

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)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jetmore See here for my attempt at explaining the file format needed. Of course, you could assemble some temporary file from the ones passed with --tls-cert and --tls-chain instead and pass that to Net::SSLeay


=item --tls-get-peer-cert [<output-file>]

Get a copy of the TLS peer's certificate. If no argument is given, it will be displayed to C<STDOUT>. 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)
Expand Down
17 changes: 17 additions & 0 deletions swaks
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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",
Expand Down