summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--readconf.c47
-rw-r--r--readconf.h8
-rw-r--r--ssh.18
-rw-r--r--ssh.c65
-rw-r--r--ssh.h8
-rw-r--r--ssh_config.554
-rw-r--r--sshconnect2.c61
7 files changed, 226 insertions, 25 deletions
diff --git a/readconf.c b/readconf.c
index 354e292d3..09888b14d 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.240 2015/08/21 23:53:08 djm Exp $ */ 1/* $OpenBSD: readconf.c,v 1.241 2015/09/24 06:15:11 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -135,6 +135,7 @@ typedef enum {
135 oPasswordAuthentication, oRSAAuthentication, 135 oPasswordAuthentication, oRSAAuthentication,
136 oChallengeResponseAuthentication, oXAuthLocation, 136 oChallengeResponseAuthentication, oXAuthLocation,
137 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 137 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
138 oCertificateFile,
138 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 139 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
139 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 140 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
140 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 141 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
@@ -202,6 +203,7 @@ static struct {
202 { "identityfile", oIdentityFile }, 203 { "identityfile", oIdentityFile },
203 { "identityfile2", oIdentityFile }, /* obsolete */ 204 { "identityfile2", oIdentityFile }, /* obsolete */
204 { "identitiesonly", oIdentitiesOnly }, 205 { "identitiesonly", oIdentitiesOnly },
206 { "certificatefile", oCertificateFile },
205 { "hostname", oHostName }, 207 { "hostname", oHostName },
206 { "hostkeyalias", oHostKeyAlias }, 208 { "hostkeyalias", oHostKeyAlias },
207 { "proxycommand", oProxyCommand }, 209 { "proxycommand", oProxyCommand },
@@ -366,6 +368,30 @@ clear_forwardings(Options *options)
366} 368}
367 369
368void 370void
371add_certificate_file(Options *options, const char *path, int userprovided)
372{
373 int i;
374
375 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
376 fatal("Too many certificate files specified (max %d)",
377 SSH_MAX_CERTIFICATE_FILES);
378
379 /* Avoid registering duplicates */
380 for (i = 0; i < options->num_certificate_files; i++) {
381 if (options->certificate_file_userprovided[i] == userprovided &&
382 strcmp(options->certificate_files[i], path) == 0) {
383 debug2("%s: ignoring duplicate key %s", __func__, path);
384 return;
385 }
386 }
387
388 options->certificate_file_userprovided[options->num_certificate_files] =
389 userprovided;
390 options->certificate_files[options->num_certificate_files++] =
391 xstrdup(path);
392}
393
394void
369add_identity_file(Options *options, const char *dir, const char *filename, 395add_identity_file(Options *options, const char *dir, const char *filename,
370 int userprovided) 396 int userprovided)
371{ 397{
@@ -981,6 +1007,24 @@ parse_time:
981 } 1007 }
982 break; 1008 break;
983 1009
1010 case oCertificateFile:
1011 arg = strdelim(&s);
1012 if (!arg || *arg == '\0')
1013 fatal("%.200s line %d: Missing argument.",
1014 filename, linenum);
1015 if (*activep) {
1016 intptr = &options->num_certificate_files;
1017 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1018 fatal("%.200s line %d: Too many certificate "
1019 "files specified (max %d).",
1020 filename, linenum,
1021 SSH_MAX_CERTIFICATE_FILES);
1022 }
1023 add_certificate_file(options, arg,
1024 flags & SSHCONF_USERCONF);
1025 }
1026 break;
1027
984 case oXAuthLocation: 1028 case oXAuthLocation:
985 charptr=&options->xauth_location; 1029 charptr=&options->xauth_location;
986 goto parse_string; 1030 goto parse_string;
@@ -1625,6 +1669,7 @@ initialize_options(Options * options)
1625 options->hostkeyalgorithms = NULL; 1669 options->hostkeyalgorithms = NULL;
1626 options->protocol = SSH_PROTO_UNKNOWN; 1670 options->protocol = SSH_PROTO_UNKNOWN;
1627 options->num_identity_files = 0; 1671 options->num_identity_files = 0;
1672 options->num_certificate_files = 0;
1628 options->hostname = NULL; 1673 options->hostname = NULL;
1629 options->host_key_alias = NULL; 1674 options->host_key_alias = NULL;
1630 options->proxy_command = NULL; 1675 options->proxy_command = NULL;
diff --git a/readconf.h b/readconf.h
index bb2d55283..6d6927f06 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.110 2015/07/10 06:21:53 markus Exp $ */ 1/* $OpenBSD: readconf.h,v 1.111 2015/09/24 06:15:11 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -95,6 +95,11 @@ typedef struct {
95 int identity_file_userprovided[SSH_MAX_IDENTITY_FILES]; 95 int identity_file_userprovided[SSH_MAX_IDENTITY_FILES];
96 struct sshkey *identity_keys[SSH_MAX_IDENTITY_FILES]; 96 struct sshkey *identity_keys[SSH_MAX_IDENTITY_FILES];
97 97
98 int num_certificate_files; /* Number of extra certificates for ssh. */
99 char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
100 int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
101 struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
102
98 /* Local TCP/IP forward requests. */ 103 /* Local TCP/IP forward requests. */
99 int num_local_forwards; 104 int num_local_forwards;
100 struct Forward *local_forwards; 105 struct Forward *local_forwards;
@@ -194,5 +199,6 @@ void dump_client_config(Options *o, const char *host);
194void add_local_forward(Options *, const struct Forward *); 199void add_local_forward(Options *, const struct Forward *);
195void add_remote_forward(Options *, const struct Forward *); 200void add_remote_forward(Options *, const struct Forward *);
196void add_identity_file(Options *, const char *, const char *, int); 201void add_identity_file(Options *, const char *, const char *, int);
202void add_certificate_file(Options *, const char *, int);
197 203
198#endif /* READCONF_H */ 204#endif /* READCONF_H */
diff --git a/ssh.1 b/ssh.1
index 495b78711..b08fa7975 100644
--- a/ssh.1
+++ b/ssh.1
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh.1,v 1.362 2015/09/11 03:42:32 djm Exp $ 36.\" $OpenBSD: ssh.1,v 1.363 2015/09/24 06:15:11 djm Exp $
37.Dd $Mdocdate: September 11 2015 $ 37.Dd $Mdocdate: September 24 2015 $
38.Dt SSH 1 38.Dt SSH 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -304,6 +304,9 @@ It is possible to have multiple
304.Fl i 304.Fl i
305options (and multiple identities specified in 305options (and multiple identities specified in
306configuration files). 306configuration files).
307If no certificates have been explicitly specified by
308.Cm CertificateFile
309directive,
307.Nm 310.Nm
308will also try to load certificate information from the filename obtained 311will also try to load certificate information from the filename obtained
309by appending 312by appending
@@ -468,6 +471,7 @@ For full details of the options listed below, and their possible values, see
468.It CanonicalizeHostname 471.It CanonicalizeHostname
469.It CanonicalizeMaxDots 472.It CanonicalizeMaxDots
470.It CanonicalizePermittedCNAMEs 473.It CanonicalizePermittedCNAMEs
474.It CertificateFile
471.It ChallengeResponseAuthentication 475.It ChallengeResponseAuthentication
472.It CheckHostIP 476.It CheckHostIP
473.It Cipher 477.It Cipher
diff --git a/ssh.c b/ssh.c
index 91911d3d5..a6e4de3ea 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.425 2015/09/11 06:55:46 jmc Exp $ */ 1/* $OpenBSD: ssh.c,v 1.426 2015/09/24 06:15:11 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1354,6 +1354,10 @@ main(int ac, char **av)
1354 options.identity_keys[i] = NULL; 1354 options.identity_keys[i] = NULL;
1355 } 1355 }
1356 } 1356 }
1357 for (i = 0; i < options.num_certificate_files; i++) {
1358 free(options.certificate_files[i]);
1359 options.certificate_files[i] = NULL;
1360 }
1357 1361
1358 exit_status = compat20 ? ssh_session2() : ssh_session(); 1362 exit_status = compat20 ? ssh_session2() : ssh_session();
1359 packet_close(); 1363 packet_close();
@@ -1940,25 +1944,30 @@ ssh_session2(void)
1940 options.escape_char : SSH_ESCAPECHAR_NONE, id); 1944 options.escape_char : SSH_ESCAPECHAR_NONE, id);
1941} 1945}
1942 1946
1947/* Loads all IdentityFile and CertificateFile keys */
1943static void 1948static void
1944load_public_identity_files(void) 1949load_public_identity_files(void)
1945{ 1950{
1946 char *filename, *cp, thishost[NI_MAXHOST]; 1951 char *filename, *cp, thishost[NI_MAXHOST];
1947 char *pwdir = NULL, *pwname = NULL; 1952 char *pwdir = NULL, *pwname = NULL;
1948 int i = 0;
1949 Key *public; 1953 Key *public;
1950 struct passwd *pw; 1954 struct passwd *pw;
1951 u_int n_ids; 1955 int i;
1956 u_int n_ids, n_certs;
1952 char *identity_files[SSH_MAX_IDENTITY_FILES]; 1957 char *identity_files[SSH_MAX_IDENTITY_FILES];
1953 Key *identity_keys[SSH_MAX_IDENTITY_FILES]; 1958 Key *identity_keys[SSH_MAX_IDENTITY_FILES];
1959 char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
1960 struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
1954#ifdef ENABLE_PKCS11 1961#ifdef ENABLE_PKCS11
1955 Key **keys; 1962 Key **keys;
1956 int nkeys; 1963 int nkeys;
1957#endif /* PKCS11 */ 1964#endif /* PKCS11 */
1958 1965
1959 n_ids = 0; 1966 n_ids = n_certs = 0;
1960 memset(identity_files, 0, sizeof(identity_files)); 1967 memset(identity_files, 0, sizeof(identity_files));
1961 memset(identity_keys, 0, sizeof(identity_keys)); 1968 memset(identity_keys, 0, sizeof(identity_keys));
1969 memset(certificate_files, 0, sizeof(certificate_files));
1970 memset(certificates, 0, sizeof(certificates));
1962 1971
1963#ifdef ENABLE_PKCS11 1972#ifdef ENABLE_PKCS11
1964 if (options.pkcs11_provider != NULL && 1973 if (options.pkcs11_provider != NULL &&
@@ -1990,6 +1999,7 @@ load_public_identity_files(void)
1990 if (n_ids >= SSH_MAX_IDENTITY_FILES || 1999 if (n_ids >= SSH_MAX_IDENTITY_FILES ||
1991 strcasecmp(options.identity_files[i], "none") == 0) { 2000 strcasecmp(options.identity_files[i], "none") == 0) {
1992 free(options.identity_files[i]); 2001 free(options.identity_files[i]);
2002 options.identity_files[i] = NULL;
1993 continue; 2003 continue;
1994 } 2004 }
1995 cp = tilde_expand_filename(options.identity_files[i], 2005 cp = tilde_expand_filename(options.identity_files[i],
@@ -2008,7 +2018,12 @@ load_public_identity_files(void)
2008 if (++n_ids >= SSH_MAX_IDENTITY_FILES) 2018 if (++n_ids >= SSH_MAX_IDENTITY_FILES)
2009 continue; 2019 continue;
2010 2020
2011 /* Try to add the certificate variant too */ 2021 /*
2022 * If no certificates have been explicitly listed then try
2023 * to add the default certificate variant too.
2024 */
2025 if (options.num_certificate_files != 0)
2026 continue;
2012 xasprintf(&cp, "%s-cert", filename); 2027 xasprintf(&cp, "%s-cert", filename);
2013 public = key_load_public(cp, NULL); 2028 public = key_load_public(cp, NULL);
2014 debug("identity file %s type %d", cp, 2029 debug("identity file %s type %d", cp,
@@ -2025,14 +2040,50 @@ load_public_identity_files(void)
2025 continue; 2040 continue;
2026 } 2041 }
2027 identity_keys[n_ids] = public; 2042 identity_keys[n_ids] = public;
2028 /* point to the original path, most likely the private key */ 2043 identity_files[n_ids] = cp;
2029 identity_files[n_ids] = xstrdup(filename);
2030 n_ids++; 2044 n_ids++;
2031 } 2045 }
2046
2047 if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES)
2048 fatal("%s: too many certificates", __func__);
2049 for (i = 0; i < options.num_certificate_files; i++) {
2050 cp = tilde_expand_filename(options.certificate_files[i],
2051 original_real_uid);
2052 filename = percent_expand(cp, "d", pwdir,
2053 "u", pwname, "l", thishost, "h", host,
2054 "r", options.user, (char *)NULL);
2055 free(cp);
2056
2057 public = key_load_public(filename, NULL);
2058 debug("certificate file %s type %d", filename,
2059 public ? public->type : -1);
2060 free(options.certificate_files[i]);
2061 options.certificate_files[i] = NULL;
2062 if (public == NULL) {
2063 free(filename);
2064 continue;
2065 }
2066 if (!key_is_cert(public)) {
2067 debug("%s: key %s type %s is not a certificate",
2068 __func__, filename, key_type(public));
2069 key_free(public);
2070 free(filename);
2071 continue;
2072 }
2073 certificate_files[n_certs] = filename;
2074 certificates[n_certs] = public;
2075 ++n_certs;
2076 }
2077
2032 options.num_identity_files = n_ids; 2078 options.num_identity_files = n_ids;
2033 memcpy(options.identity_files, identity_files, sizeof(identity_files)); 2079 memcpy(options.identity_files, identity_files, sizeof(identity_files));
2034 memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); 2080 memcpy(options.identity_keys, identity_keys, sizeof(identity_keys));
2035 2081
2082 options.num_certificate_files = n_certs;
2083 memcpy(options.certificate_files,
2084 certificate_files, sizeof(certificate_files));
2085 memcpy(options.certificates, certificates, sizeof(certificates));
2086
2036 explicit_bzero(pwname, strlen(pwname)); 2087 explicit_bzero(pwname, strlen(pwname));
2037 free(pwname); 2088 free(pwname);
2038 explicit_bzero(pwdir, strlen(pwdir)); 2089 explicit_bzero(pwdir, strlen(pwdir));
diff --git a/ssh.h b/ssh.h
index 39c7e18af..80eaeb3ed 100644
--- a/ssh.h
+++ b/ssh.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.h,v 1.81 2015/08/04 05:23:06 djm Exp $ */ 1/* $OpenBSD: ssh.h,v 1.82 2015/09/24 06:15:11 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -19,6 +19,12 @@
19#define SSH_DEFAULT_PORT 22 19#define SSH_DEFAULT_PORT 22
20 20
21/* 21/*
22 * Maximum number of certificate files that can be specified
23 * in configuration files or on the command line.
24 */
25#define SSH_MAX_CERTIFICATE_FILES 100
26
27/*
22 * Maximum number of RSA authentication identity files that can be specified 28 * Maximum number of RSA authentication identity files that can be specified
23 * in configuration files or on the command line. 29 * in configuration files or on the command line.
24 */ 30 */
diff --git a/ssh_config.5 b/ssh_config.5
index 54c42ab80..39cf932d3 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh_config.5,v 1.220 2015/09/22 08:33:23 sobrado Exp $ 36.\" $OpenBSD: ssh_config.5,v 1.221 2015/09/24 06:15:11 djm Exp $
37.Dd $Mdocdate: September 22 2015 $ 37.Dd $Mdocdate: September 24 2015 $
38.Dt SSH_CONFIG 5 38.Dt SSH_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -325,6 +325,41 @@ to be canonicalized to names in the
325or 325or
326.Dq *.c.example.com 326.Dq *.c.example.com
327domains. 327domains.
328.It Cm CertificateFile
329Specifies a file from which the user's certificate is read.
330A corresponding private key must be provided separately in order
331to use this certificate either
332from an
333.Cm IdentityFile
334directive or
335.Fl i
336flag to
337.Xr ssh 1 ,
338via
339.Xr ssh-agent 1 ,
340or via a
341.Cm PKCS11Provider .
342.Pp
343The file name may use the tilde
344syntax to refer to a user's home directory or one of the following
345escape characters:
346.Ql %d
347(local user's home directory),
348.Ql %u
349(local user name),
350.Ql %l
351(local host name),
352.Ql %h
353(remote host name) or
354.Ql %r
355(remote user name).
356.Pp
357It is possible to have multiple certificate files specified in
358configuration files; these certificates will be tried in sequence.
359Multiple
360.Cm CertificateFile
361directives will add to the list of certificates used for
362authentication.
328.It Cm ChallengeResponseAuthentication 363.It Cm ChallengeResponseAuthentication
329Specifies whether to use challenge-response authentication. 364Specifies whether to use challenge-response authentication.
330The argument to this keyword must be 365The argument to this keyword must be
@@ -869,9 +904,13 @@ specifications).
869.It Cm IdentitiesOnly 904.It Cm IdentitiesOnly
870Specifies that 905Specifies that
871.Xr ssh 1 906.Xr ssh 1
872should only use the authentication identity files configured in the 907should only use the authentication identity and certificate files explicitly
908configured in the
873.Nm 909.Nm
874files, 910files
911or passed on the
912.Xr ssh 1
913command-line,
875even if 914even if
876.Xr ssh-agent 1 915.Xr ssh-agent 1
877or a 916or a
@@ -901,6 +940,8 @@ Additionally, any identities represented by the authentication agent
901will be used for authentication unless 940will be used for authentication unless
902.Cm IdentitiesOnly 941.Cm IdentitiesOnly
903is set. 942is set.
943If no certificates have been explicitly specified by
944.Cm CertificateFile ,
904.Xr ssh 1 945.Xr ssh 1
905will try to load certificate information from the filename obtained by 946will try to load certificate information from the filename obtained by
906appending 947appending
@@ -934,6 +975,11 @@ differs from that of other configuration directives).
934may be used in conjunction with 975may be used in conjunction with
935.Cm IdentitiesOnly 976.Cm IdentitiesOnly
936to select which identities in an agent are offered during authentication. 977to select which identities in an agent are offered during authentication.
978.Cm IdentityFile
979may also be used in conjunction with
980.Cm CertificateFile
981in order to provide any certificate also needed for authentication with
982the identity.
937.It Cm IgnoreUnknown 983.It Cm IgnoreUnknown
938Specifies a pattern-list of unknown options to be ignored if they are 984Specifies a pattern-list of unknown options to be ignored if they are
939encountered in configuration parsing. 985encountered in configuration parsing.
diff --git a/sshconnect2.c b/sshconnect2.c
index 775103185..e82188392 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect2.c,v 1.226 2015/07/30 00:01:34 djm Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.227 2015/09/24 06:15:11 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Damien Miller. All rights reserved. 4 * Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -1001,18 +1001,17 @@ static int
1001sign_and_send_pubkey(Authctxt *authctxt, Identity *id) 1001sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
1002{ 1002{
1003 Buffer b; 1003 Buffer b;
1004 Identity *private_id;
1004 u_char *blob, *signature; 1005 u_char *blob, *signature;
1005 u_int bloblen;
1006 size_t slen; 1006 size_t slen;
1007 u_int skip = 0; 1007 u_int bloblen, skip = 0;
1008 int ret = -1; 1008 int matched, ret = -1, have_sig = 1;
1009 int have_sig = 1;
1010 char *fp; 1009 char *fp;
1011 1010
1012 if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, 1011 if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
1013 SSH_FP_DEFAULT)) == NULL) 1012 SSH_FP_DEFAULT)) == NULL)
1014 return 0; 1013 return 0;
1015 debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); 1014 debug3("%s: %s %s", __func__, key_type(id->key), fp);
1016 free(fp); 1015 free(fp);
1017 1016
1018 if (key_to_blob(id->key, &blob, &bloblen) == 0) { 1017 if (key_to_blob(id->key, &blob, &bloblen) == 0) {
@@ -1044,6 +1043,36 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
1044 } 1043 }
1045 buffer_put_string(&b, blob, bloblen); 1044 buffer_put_string(&b, blob, bloblen);
1046 1045
1046 /*
1047 * If the key is an certificate, try to find a matching private key
1048 * and use it to complete the signature.
1049 * If no such private key exists, return failure and continue with
1050 * other methods of authentication.
1051 */
1052 if (key_is_cert(id->key)) {
1053 matched = 0;
1054 TAILQ_FOREACH(private_id, &authctxt->keys, next) {
1055 if (sshkey_equal_public(id->key, private_id->key) &&
1056 id->key->type != private_id->key->type) {
1057 id = private_id;
1058 matched = 1;
1059 break;
1060 }
1061 }
1062 if (matched) {
1063 debug2("%s: using private key \"%s\"%s for "
1064 "certificate", __func__, id->filename,
1065 id->agent_fd != -1 ? " from agent" : "");
1066 } else {
1067 /* XXX maybe verbose/error? */
1068 debug("%s: no private key for certificate "
1069 "\"%s\"", __func__, id->filename);
1070 free(blob);
1071 buffer_free(&b);
1072 return 0;
1073 }
1074 }
1075
1047 /* generate signature */ 1076 /* generate signature */
1048 ret = identity_sign(id, &signature, &slen, 1077 ret = identity_sign(id, &signature, &slen,
1049 buffer_ptr(&b), buffer_len(&b), datafellows); 1078 buffer_ptr(&b), buffer_len(&b), datafellows);
@@ -1180,9 +1209,11 @@ load_identity_file(char *filename, int userprovided)
1180 1209
1181/* 1210/*
1182 * try keys in the following order: 1211 * try keys in the following order:
1183 * 1. agent keys that are found in the config file 1212 * 1. certificates listed in the config file
1184 * 2. other agent keys 1213 * 2. other input certificates
1185 * 3. keys that are only listed in the config file 1214 * 3. agent keys that are found in the config file
1215 * 4. other agent keys
1216 * 5. keys that are only listed in the config file
1186 */ 1217 */
1187static void 1218static void
1188pubkey_prepare(Authctxt *authctxt) 1219pubkey_prepare(Authctxt *authctxt)
@@ -1236,6 +1267,18 @@ pubkey_prepare(Authctxt *authctxt)
1236 free(id); 1267 free(id);
1237 } 1268 }
1238 } 1269 }
1270 /* list of certificates specified by user */
1271 for (i = 0; i < options.num_certificate_files; i++) {
1272 key = options.certificates[i];
1273 if (!key_is_cert(key) || key->cert == NULL ||
1274 key->cert->type != SSH2_CERT_TYPE_USER)
1275 continue;
1276 id = xcalloc(1, sizeof(*id));
1277 id->key = key;
1278 id->filename = xstrdup(options.certificate_files[i]);
1279 id->userprovided = options.certificate_file_userprovided[i];
1280 TAILQ_INSERT_TAIL(preferred, id, next);
1281 }
1239 /* list of keys supported by the agent */ 1282 /* list of keys supported by the agent */
1240 if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { 1283 if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
1241 if (r != SSH_ERR_AGENT_NOT_PRESENT) 1284 if (r != SSH_ERR_AGENT_NOT_PRESENT)