diff options
-rw-r--r-- | readconf.c | 47 | ||||
-rw-r--r-- | readconf.h | 8 | ||||
-rw-r--r-- | ssh.1 | 8 | ||||
-rw-r--r-- | ssh.c | 65 | ||||
-rw-r--r-- | ssh.h | 8 | ||||
-rw-r--r-- | ssh_config.5 | 54 | ||||
-rw-r--r-- | sshconnect2.c | 61 |
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 | ||
368 | void | 370 | void |
371 | add_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 | |||
394 | void | ||
369 | add_identity_file(Options *options, const char *dir, const char *filename, | 395 | add_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); | |||
194 | void add_local_forward(Options *, const struct Forward *); | 199 | void add_local_forward(Options *, const struct Forward *); |
195 | void add_remote_forward(Options *, const struct Forward *); | 200 | void add_remote_forward(Options *, const struct Forward *); |
196 | void add_identity_file(Options *, const char *, const char *, int); | 201 | void add_identity_file(Options *, const char *, const char *, int); |
202 | void add_certificate_file(Options *, const char *, int); | ||
197 | 203 | ||
198 | #endif /* READCONF_H */ | 204 | #endif /* READCONF_H */ |
@@ -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 |
305 | options (and multiple identities specified in | 305 | options (and multiple identities specified in |
306 | configuration files). | 306 | configuration files). |
307 | If no certificates have been explicitly specified by | ||
308 | .Cm CertificateFile | ||
309 | directive, | ||
307 | .Nm | 310 | .Nm |
308 | will also try to load certificate information from the filename obtained | 311 | will also try to load certificate information from the filename obtained |
309 | by appending | 312 | by 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 |
@@ -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 */ | ||
1943 | static void | 1948 | static void |
1944 | load_public_identity_files(void) | 1949 | load_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)); |
@@ -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 | |||
325 | or | 325 | or |
326 | .Dq *.c.example.com | 326 | .Dq *.c.example.com |
327 | domains. | 327 | domains. |
328 | .It Cm CertificateFile | ||
329 | Specifies a file from which the user's certificate is read. | ||
330 | A corresponding private key must be provided separately in order | ||
331 | to use this certificate either | ||
332 | from an | ||
333 | .Cm IdentityFile | ||
334 | directive or | ||
335 | .Fl i | ||
336 | flag to | ||
337 | .Xr ssh 1 , | ||
338 | via | ||
339 | .Xr ssh-agent 1 , | ||
340 | or via a | ||
341 | .Cm PKCS11Provider . | ||
342 | .Pp | ||
343 | The file name may use the tilde | ||
344 | syntax to refer to a user's home directory or one of the following | ||
345 | escape 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 | ||
357 | It is possible to have multiple certificate files specified in | ||
358 | configuration files; these certificates will be tried in sequence. | ||
359 | Multiple | ||
360 | .Cm CertificateFile | ||
361 | directives will add to the list of certificates used for | ||
362 | authentication. | ||
328 | .It Cm ChallengeResponseAuthentication | 363 | .It Cm ChallengeResponseAuthentication |
329 | Specifies whether to use challenge-response authentication. | 364 | Specifies whether to use challenge-response authentication. |
330 | The argument to this keyword must be | 365 | The argument to this keyword must be |
@@ -869,9 +904,13 @@ specifications). | |||
869 | .It Cm IdentitiesOnly | 904 | .It Cm IdentitiesOnly |
870 | Specifies that | 905 | Specifies that |
871 | .Xr ssh 1 | 906 | .Xr ssh 1 |
872 | should only use the authentication identity files configured in the | 907 | should only use the authentication identity and certificate files explicitly |
908 | configured in the | ||
873 | .Nm | 909 | .Nm |
874 | files, | 910 | files |
911 | or passed on the | ||
912 | .Xr ssh 1 | ||
913 | command-line, | ||
875 | even if | 914 | even if |
876 | .Xr ssh-agent 1 | 915 | .Xr ssh-agent 1 |
877 | or a | 916 | or a |
@@ -901,6 +940,8 @@ Additionally, any identities represented by the authentication agent | |||
901 | will be used for authentication unless | 940 | will be used for authentication unless |
902 | .Cm IdentitiesOnly | 941 | .Cm IdentitiesOnly |
903 | is set. | 942 | is set. |
943 | If no certificates have been explicitly specified by | ||
944 | .Cm CertificateFile , | ||
904 | .Xr ssh 1 | 945 | .Xr ssh 1 |
905 | will try to load certificate information from the filename obtained by | 946 | will try to load certificate information from the filename obtained by |
906 | appending | 947 | appending |
@@ -934,6 +975,11 @@ differs from that of other configuration directives). | |||
934 | may be used in conjunction with | 975 | may be used in conjunction with |
935 | .Cm IdentitiesOnly | 976 | .Cm IdentitiesOnly |
936 | to select which identities in an agent are offered during authentication. | 977 | to select which identities in an agent are offered during authentication. |
978 | .Cm IdentityFile | ||
979 | may also be used in conjunction with | ||
980 | .Cm CertificateFile | ||
981 | in order to provide any certificate also needed for authentication with | ||
982 | the identity. | ||
937 | .It Cm IgnoreUnknown | 983 | .It Cm IgnoreUnknown |
938 | Specifies a pattern-list of unknown options to be ignored if they are | 984 | Specifies a pattern-list of unknown options to be ignored if they are |
939 | encountered in configuration parsing. | 985 | encountered 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 | |||
1001 | sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | 1001 | sign_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 | */ |
1187 | static void | 1218 | static void |
1188 | pubkey_prepare(Authctxt *authctxt) | 1219 | pubkey_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) |