diff --git a/NEWS b/NEWS index 5ba9777..5c74ce1 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ Network timeout handling has been added. A Maildir sub-folder naming style without extra dots has been added. +Support for TLS client certificates was added. + [1.2.0] The 'isync' compatibility wrapper is now deprecated. diff --git a/src/drv_imap.c b/src/drv_imap.c index f27e58e..86dd22c 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -2779,6 +2779,20 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) } } else if (!strcasecmp( "SystemCertificates", cfg->cmd )) { server->sconf.system_certs = parse_bool( cfg ); + } else if (!strcasecmp( "ClientCertificate", cfg->cmd )) { + server->sconf.client_certfile = expand_strdup( cfg->val ); + if (access( server->sconf.client_certfile, R_OK )) { + sys_error( "%s:%d: ClientCertificate '%s'", + cfg->file, cfg->line, server->sconf.client_certfile ); + cfg->err = 1; + } + } else if (!strcasecmp( "ClientKey", cfg->cmd )) { + server->sconf.client_keyfile = expand_strdup( cfg->val ); + if (access( server->sconf.client_keyfile, R_OK )) { + sys_error( "%s:%d: ClientKey '%s'", + cfg->file, cfg->line, server->sconf.client_keyfile ); + cfg->err = 1; + } } else if (!strcasecmp( "SSLType", cfg->cmd )) { if (!strcasecmp( "None", cfg->val )) { server->ssl_type = SSL_None; diff --git a/src/mbsync.1 b/src/mbsync.1 index cb190a2..daa8d41 100644 --- a/src/mbsync.1 +++ b/src/mbsync.1 @@ -378,6 +378,18 @@ Note that the system's default certificate store is always used and should not be specified here. .. .TP +\fBClientCertificate\fR \fIpath\fR +File containing a client certificate to send to the server. +\fBClientKey\fR should also be specified. +.br +Note that client certificate verification is usually not required, +so it is unlikely that you need this option. +.. +.TP +\fBClientKey\fR \fIpath\fR +File containing the private key corresponding to \fBClientCertificate\fR. +.. +.TP \fBPipelineDepth\fR \fIdepth\fR Maximum number of IMAP commands which can be simultaneously in flight. Setting this to \fI1\fR disables pipelining. diff --git a/src/socket.c b/src/socket.c index 27bc8cd..33372d4 100644 --- a/src/socket.c +++ b/src/socket.c @@ -230,6 +230,17 @@ init_ssl_ctx( const server_conf_t *conf ) SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL ); + if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) { + error( "Error while loading client certificate file '%s': %s\n", + conf->client_certfile, ERR_error_string( ERR_get_error(), 0 ) ); + return 0; + } + if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) { + error( "Error while loading client private key '%s': %s\n", + conf->client_keyfile, ERR_error_string( ERR_get_error(), 0 ) ); + return 0; + } + mconf->ssl_ctx_valid = 1; return 1; } diff --git a/src/socket.h b/src/socket.h index bbbc56b..1a089cd 100644 --- a/src/socket.h +++ b/src/socket.h @@ -50,6 +50,8 @@ typedef struct server_conf { int timeout; #ifdef HAVE_LIBSSL char *cert_file; + char *client_certfile; + char *client_keyfile; char system_certs; char ssl_versions;