Skip to content
Permalink
Browse files
upstream commit
add ssh_config CertificateFile option to explicitly list
 a certificate; patch from Meghana Bhat on bz#2436; ok markus@

Upstream-ID: 58648ec53c510b41c1f46d8fe293aadc87229ab8
  • Loading branch information
djmdjm committed Oct 6, 2015
1 parent e3cbb06 commit 4e44a79
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 25 deletions.
@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.240 2015/08/21 23:53:08 djm Exp $ */
/* $OpenBSD: readconf.c,v 1.241 2015/09/24 06:15:11 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -135,6 +135,7 @@ typedef enum {
oPasswordAuthentication, oRSAAuthentication,
oChallengeResponseAuthentication, oXAuthLocation,
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
oCertificateFile,
oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
@@ -202,6 +203,7 @@ static struct {
{ "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile }, /* obsolete */
{ "identitiesonly", oIdentitiesOnly },
{ "certificatefile", oCertificateFile },
{ "hostname", oHostName },
{ "hostkeyalias", oHostKeyAlias },
{ "proxycommand", oProxyCommand },
@@ -365,6 +367,30 @@ clear_forwardings(Options *options)
options->tun_open = SSH_TUNMODE_NO;
}

void
add_certificate_file(Options *options, const char *path, int userprovided)
{
int i;

if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
fatal("Too many certificate files specified (max %d)",
SSH_MAX_CERTIFICATE_FILES);

/* Avoid registering duplicates */
for (i = 0; i < options->num_certificate_files; i++) {
if (options->certificate_file_userprovided[i] == userprovided &&
strcmp(options->certificate_files[i], path) == 0) {
debug2("%s: ignoring duplicate key %s", __func__, path);
return;
}
}

options->certificate_file_userprovided[options->num_certificate_files] =
userprovided;
options->certificate_files[options->num_certificate_files++] =
xstrdup(path);
}

void
add_identity_file(Options *options, const char *dir, const char *filename,
int userprovided)
@@ -981,6 +1007,24 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
}
break;

case oCertificateFile:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.",
filename, linenum);
if (*activep) {
intptr = &options->num_certificate_files;
if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
fatal("%.200s line %d: Too many certificate "
"files specified (max %d).",
filename, linenum,
SSH_MAX_CERTIFICATE_FILES);
}
add_certificate_file(options, arg,
flags & SSHCONF_USERCONF);
}
break;

case oXAuthLocation:
charptr=&options->xauth_location;
goto parse_string;
@@ -1625,6 +1669,7 @@ initialize_options(Options * options)
options->hostkeyalgorithms = NULL;
options->protocol = SSH_PROTO_UNKNOWN;
options->num_identity_files = 0;
options->num_certificate_files = 0;
options->hostname = NULL;
options->host_key_alias = NULL;
options->proxy_command = NULL;
@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.110 2015/07/10 06:21:53 markus Exp $ */
/* $OpenBSD: readconf.h,v 1.111 2015/09/24 06:15:11 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -95,6 +95,11 @@ typedef struct {
int identity_file_userprovided[SSH_MAX_IDENTITY_FILES];
struct sshkey *identity_keys[SSH_MAX_IDENTITY_FILES];

int num_certificate_files; /* Number of extra certificates for ssh. */
char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];

/* Local TCP/IP forward requests. */
int num_local_forwards;
struct Forward *local_forwards;
@@ -194,5 +199,6 @@ void dump_client_config(Options *o, const char *host);
void add_local_forward(Options *, const struct Forward *);
void add_remote_forward(Options *, const struct Forward *);
void add_identity_file(Options *, const char *, const char *, int);
void add_certificate_file(Options *, const char *, int);

#endif /* READCONF_H */
8 ssh.1
@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.362 2015/09/11 03:42:32 djm Exp $
.Dd $Mdocdate: September 11 2015 $
.\" $OpenBSD: ssh.1,v 1.363 2015/09/24 06:15:11 djm Exp $
.Dd $Mdocdate: September 24 2015 $
.Dt SSH 1
.Os
.Sh NAME
@@ -304,6 +304,9 @@ It is possible to have multiple
.Fl i
options (and multiple identities specified in
configuration files).
If no certificates have been explicitly specified by
.Cm CertificateFile
directive,
.Nm
will also try to load certificate information from the filename obtained
by appending
@@ -468,6 +471,7 @@ For full details of the options listed below, and their possible values, see
.It CanonicalizeHostname
.It CanonicalizeMaxDots
.It CanonicalizePermittedCNAMEs
.It CertificateFile
.It ChallengeResponseAuthentication
.It CheckHostIP
.It Cipher
65 ssh.c
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.425 2015/09/11 06:55:46 jmc Exp $ */
/* $OpenBSD: ssh.c,v 1.426 2015/09/24 06:15:11 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1354,6 +1354,10 @@ main(int ac, char **av)
options.identity_keys[i] = NULL;
}
}
for (i = 0; i < options.num_certificate_files; i++) {
free(options.certificate_files[i]);
options.certificate_files[i] = NULL;
}

exit_status = compat20 ? ssh_session2() : ssh_session();
packet_close();
@@ -1940,25 +1944,30 @@ ssh_session2(void)
options.escape_char : SSH_ESCAPECHAR_NONE, id);
}

/* Loads all IdentityFile and CertificateFile keys */
static void
load_public_identity_files(void)
{
char *filename, *cp, thishost[NI_MAXHOST];
char *pwdir = NULL, *pwname = NULL;
int i = 0;
Key *public;
struct passwd *pw;
u_int n_ids;
int i;
u_int n_ids, n_certs;
char *identity_files[SSH_MAX_IDENTITY_FILES];
Key *identity_keys[SSH_MAX_IDENTITY_FILES];
char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
#ifdef ENABLE_PKCS11
Key **keys;
int nkeys;
#endif /* PKCS11 */

n_ids = 0;
n_ids = n_certs = 0;
memset(identity_files, 0, sizeof(identity_files));
memset(identity_keys, 0, sizeof(identity_keys));
memset(certificate_files, 0, sizeof(certificate_files));
memset(certificates, 0, sizeof(certificates));

#ifdef ENABLE_PKCS11
if (options.pkcs11_provider != NULL &&
@@ -1990,6 +1999,7 @@ load_public_identity_files(void)
if (n_ids >= SSH_MAX_IDENTITY_FILES ||
strcasecmp(options.identity_files[i], "none") == 0) {
free(options.identity_files[i]);
options.identity_files[i] = NULL;
continue;
}
cp = tilde_expand_filename(options.identity_files[i],
@@ -2008,7 +2018,12 @@ load_public_identity_files(void)
if (++n_ids >= SSH_MAX_IDENTITY_FILES)
continue;

/* Try to add the certificate variant too */
/*
* If no certificates have been explicitly listed then try
* to add the default certificate variant too.
*/
if (options.num_certificate_files != 0)
continue;
xasprintf(&cp, "%s-cert", filename);
public = key_load_public(cp, NULL);
debug("identity file %s type %d", cp,
@@ -2025,14 +2040,50 @@ load_public_identity_files(void)
continue;
}
identity_keys[n_ids] = public;
/* point to the original path, most likely the private key */
identity_files[n_ids] = xstrdup(filename);
identity_files[n_ids] = cp;
n_ids++;
}

if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES)
fatal("%s: too many certificates", __func__);
for (i = 0; i < options.num_certificate_files; i++) {
cp = tilde_expand_filename(options.certificate_files[i],
original_real_uid);
filename = percent_expand(cp, "d", pwdir,
"u", pwname, "l", thishost, "h", host,
"r", options.user, (char *)NULL);
free(cp);

public = key_load_public(filename, NULL);
debug("certificate file %s type %d", filename,
public ? public->type : -1);
free(options.certificate_files[i]);
options.certificate_files[i] = NULL;
if (public == NULL) {
free(filename);
continue;
}
if (!key_is_cert(public)) {
debug("%s: key %s type %s is not a certificate",
__func__, filename, key_type(public));
key_free(public);
free(filename);
continue;
}
certificate_files[n_certs] = filename;
certificates[n_certs] = public;
++n_certs;
}

options.num_identity_files = n_ids;
memcpy(options.identity_files, identity_files, sizeof(identity_files));
memcpy(options.identity_keys, identity_keys, sizeof(identity_keys));

options.num_certificate_files = n_certs;
memcpy(options.certificate_files,
certificate_files, sizeof(certificate_files));
memcpy(options.certificates, certificates, sizeof(certificates));

explicit_bzero(pwname, strlen(pwname));
free(pwname);
explicit_bzero(pwdir, strlen(pwdir));
8 ssh.h
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh.h,v 1.81 2015/08/04 05:23:06 djm Exp $ */
/* $OpenBSD: ssh.h,v 1.82 2015/09/24 06:15:11 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -18,6 +18,12 @@
/* Default port number. */
#define SSH_DEFAULT_PORT 22

/*
* Maximum number of certificate files that can be specified
* in configuration files or on the command line.
*/
#define SSH_MAX_CERTIFICATE_FILES 100

/*
* Maximum number of RSA authentication identity files that can be specified
* in configuration files or on the command line.
@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.220 2015/09/22 08:33:23 sobrado Exp $
.Dd $Mdocdate: September 22 2015 $
.\" $OpenBSD: ssh_config.5,v 1.221 2015/09/24 06:15:11 djm Exp $
.Dd $Mdocdate: September 24 2015 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@@ -325,6 +325,41 @@ to be canonicalized to names in the
or
.Dq *.c.example.com
domains.
.It Cm CertificateFile
Specifies a file from which the user's certificate is read.
A corresponding private key must be provided separately in order
to use this certificate either
from an
.Cm IdentityFile
directive or
.Fl i
flag to
.Xr ssh 1 ,
via
.Xr ssh-agent 1 ,
or via a
.Cm PKCS11Provider .
.Pp
The file name may use the tilde
syntax to refer to a user's home directory or one of the following
escape characters:
.Ql %d
(local user's home directory),
.Ql %u
(local user name),
.Ql %l
(local host name),
.Ql %h
(remote host name) or
.Ql %r
(remote user name).
.Pp
It is possible to have multiple certificate files specified in
configuration files; these certificates will be tried in sequence.
Multiple
.Cm CertificateFile
directives will add to the list of certificates used for
authentication.
.It Cm ChallengeResponseAuthentication
Specifies whether to use challenge-response authentication.
The argument to this keyword must be
@@ -869,9 +904,13 @@ specifications).
.It Cm IdentitiesOnly
Specifies that
.Xr ssh 1
should only use the authentication identity files configured in the
should only use the authentication identity and certificate files explicitly
configured in the
.Nm
files,
files
or passed on the
.Xr ssh 1
command-line,
even if
.Xr ssh-agent 1
or a
@@ -901,6 +940,8 @@ Additionally, any identities represented by the authentication agent
will be used for authentication unless
.Cm IdentitiesOnly
is set.
If no certificates have been explicitly specified by
.Cm CertificateFile ,
.Xr ssh 1
will try to load certificate information from the filename obtained by
appending
@@ -934,6 +975,11 @@ differs from that of other configuration directives).
may be used in conjunction with
.Cm IdentitiesOnly
to select which identities in an agent are offered during authentication.
.Cm IdentityFile
may also be used in conjunction with
.Cm CertificateFile
in order to provide any certificate also needed for authentication with
the identity.
.It Cm IgnoreUnknown
Specifies a pattern-list of unknown options to be ignored if they are
encountered in configuration parsing.

0 comments on commit 4e44a79

Please sign in to comment.