diff options
-rw-r--r-- | ssh-agent.1 | 17 | ||||
-rw-r--r-- | ssh-agent.c | 43 |
2 files changed, 50 insertions, 10 deletions
diff --git a/ssh-agent.1 b/ssh-agent.1 index c4b50bbdf..372adbe7c 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: ssh-agent.1,v 1.62 2015/11/15 23:54:15 jmc Exp $ | 1 | .\" $OpenBSD: ssh-agent.1,v 1.63 2016/11/30 03:07:37 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 |
@@ -34,7 +34,7 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .Dd $Mdocdate: November 15 2015 $ | 37 | .Dd $Mdocdate: November 30 2016 $ |
38 | .Dt SSH-AGENT 1 | 38 | .Dt SSH-AGENT 1 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -47,6 +47,7 @@ | |||
47 | .Op Fl a Ar bind_address | 47 | .Op Fl a Ar bind_address |
48 | .Op Fl E Ar fingerprint_hash | 48 | .Op Fl E Ar fingerprint_hash |
49 | .Op Fl t Ar life | 49 | .Op Fl t Ar life |
50 | .Op Fl P Ar pkcs11_whitelist | ||
50 | .Op Ar command Op Ar arg ... | 51 | .Op Ar command Op Ar arg ... |
51 | .Nm ssh-agent | 52 | .Nm ssh-agent |
52 | .Op Fl c | s | 53 | .Op Fl c | s |
@@ -121,6 +122,18 @@ The default is | |||
121 | Kill the current agent (given by the | 122 | Kill the current agent (given by the |
122 | .Ev SSH_AGENT_PID | 123 | .Ev SSH_AGENT_PID |
123 | environment variable). | 124 | environment variable). |
125 | .It Fl P | ||
126 | Specify a pattern-list of acceptable paths for PKCS#11 shared libraries | ||
127 | that may be added using the | ||
128 | .Fl s | ||
129 | option to | ||
130 | .Xr ssh-add 1 . | ||
131 | The default is to allow loading PKCS#11 libraries from | ||
132 | .Dq /usr/lib/*,/usr/local/lib/* . | ||
133 | PKCS#11 libraries that do not match the whitelist will be refused. | ||
134 | See PATTERNS in | ||
135 | .Xr ssh_config 5 | ||
136 | for a description of pattern-list syntax. | ||
124 | .It Fl s | 137 | .It Fl s |
125 | Generate Bourne shell commands on | 138 | Generate Bourne shell commands on |
126 | .Dv stdout . | 139 | .Dv stdout . |
diff --git a/ssh-agent.c b/ssh-agent.c index fd5f2b35d..395213553 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.214 2016/09/12 01:22:38 deraadt Exp $ */ | 1 | /* $OpenBSD: ssh-agent.c,v 1.215 2016/11/30 03:07:37 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 |
@@ -82,11 +82,16 @@ | |||
82 | #include "misc.h" | 82 | #include "misc.h" |
83 | #include "digest.h" | 83 | #include "digest.h" |
84 | #include "ssherr.h" | 84 | #include "ssherr.h" |
85 | #include "match.h" | ||
85 | 86 | ||
86 | #ifdef ENABLE_PKCS11 | 87 | #ifdef ENABLE_PKCS11 |
87 | #include "ssh-pkcs11.h" | 88 | #include "ssh-pkcs11.h" |
88 | #endif | 89 | #endif |
89 | 90 | ||
91 | #ifndef DEFAULT_PKCS11_WHITELIST | ||
92 | # define DEFAULT_PKCS11_WHITELIST "/usr/lib/*,/usr/local/lib/*" | ||
93 | #endif | ||
94 | |||
90 | typedef enum { | 95 | typedef enum { |
91 | AUTH_UNUSED, | 96 | AUTH_UNUSED, |
92 | AUTH_SOCKET, | 97 | AUTH_SOCKET, |
@@ -134,6 +139,9 @@ pid_t cleanup_pid = 0; | |||
134 | char socket_name[PATH_MAX]; | 139 | char socket_name[PATH_MAX]; |
135 | char socket_dir[PATH_MAX]; | 140 | char socket_dir[PATH_MAX]; |
136 | 141 | ||
142 | /* PKCS#11 path whitelist */ | ||
143 | static char *pkcs11_whitelist; | ||
144 | |||
137 | /* locking */ | 145 | /* locking */ |
138 | #define LOCK_SIZE 32 | 146 | #define LOCK_SIZE 32 |
139 | #define LOCK_SALT_SIZE 16 | 147 | #define LOCK_SALT_SIZE 16 |
@@ -737,7 +745,7 @@ no_identities(SocketEntry *e, u_int type) | |||
737 | static void | 745 | static void |
738 | process_add_smartcard_key(SocketEntry *e) | 746 | process_add_smartcard_key(SocketEntry *e) |
739 | { | 747 | { |
740 | char *provider = NULL, *pin; | 748 | char *provider = NULL, *pin, canonical_provider[PATH_MAX]; |
741 | int r, i, version, count = 0, success = 0, confirm = 0; | 749 | int r, i, version, count = 0, success = 0, confirm = 0; |
742 | u_int seconds; | 750 | u_int seconds; |
743 | time_t death = 0; | 751 | time_t death = 0; |
@@ -769,10 +777,21 @@ process_add_smartcard_key(SocketEntry *e) | |||
769 | goto send; | 777 | goto send; |
770 | } | 778 | } |
771 | } | 779 | } |
780 | if (realpath(provider, canonical_provider) == NULL) { | ||
781 | verbose("failed PKCS#11 add of \"%.100s\": realpath: %s", | ||
782 | provider, strerror(errno)); | ||
783 | goto send; | ||
784 | } | ||
785 | if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) { | ||
786 | verbose("refusing PKCS#11 add of \"%.100s\": " | ||
787 | "provider not whitelisted", canonical_provider); | ||
788 | goto send; | ||
789 | } | ||
790 | debug("%s: add %.100s", __func__, canonical_provider); | ||
772 | if (lifetime && !death) | 791 | if (lifetime && !death) |
773 | death = monotime() + lifetime; | 792 | death = monotime() + lifetime; |
774 | 793 | ||
775 | count = pkcs11_add_provider(provider, pin, &keys); | 794 | count = pkcs11_add_provider(canonical_provider, pin, &keys); |
776 | for (i = 0; i < count; i++) { | 795 | for (i = 0; i < count; i++) { |
777 | k = keys[i]; | 796 | k = keys[i]; |
778 | version = k->type == KEY_RSA1 ? 1 : 2; | 797 | version = k->type == KEY_RSA1 ? 1 : 2; |
@@ -780,8 +799,8 @@ process_add_smartcard_key(SocketEntry *e) | |||
780 | if (lookup_identity(k, version) == NULL) { | 799 | if (lookup_identity(k, version) == NULL) { |
781 | id = xcalloc(1, sizeof(Identity)); | 800 | id = xcalloc(1, sizeof(Identity)); |
782 | id->key = k; | 801 | id->key = k; |
783 | id->provider = xstrdup(provider); | 802 | id->provider = xstrdup(canonical_provider); |
784 | id->comment = xstrdup(provider); /* XXX */ | 803 | id->comment = xstrdup(canonical_provider); /* XXX */ |
785 | id->death = death; | 804 | id->death = death; |
786 | id->confirm = confirm; | 805 | id->confirm = confirm; |
787 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); | 806 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
@@ -1172,7 +1191,7 @@ usage(void) | |||
1172 | { | 1191 | { |
1173 | fprintf(stderr, | 1192 | fprintf(stderr, |
1174 | "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n" | 1193 | "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n" |
1175 | " [-t life] [command [arg ...]]\n" | 1194 | " [-P pkcs11_whitelist] [-t life] [command [arg ...]]\n" |
1176 | " ssh-agent [-c | -s] -k\n"); | 1195 | " ssh-agent [-c | -s] -k\n"); |
1177 | exit(1); | 1196 | exit(1); |
1178 | } | 1197 | } |
@@ -1213,7 +1232,7 @@ main(int ac, char **av) | |||
1213 | __progname = ssh_get_progname(av[0]); | 1232 | __progname = ssh_get_progname(av[0]); |
1214 | seed_rng(); | 1233 | seed_rng(); |
1215 | 1234 | ||
1216 | while ((ch = getopt(ac, av, "cDdksE:a:t:")) != -1) { | 1235 | while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) { |
1217 | switch (ch) { | 1236 | switch (ch) { |
1218 | case 'E': | 1237 | case 'E': |
1219 | fingerprint_hash = ssh_digest_alg_by_name(optarg); | 1238 | fingerprint_hash = ssh_digest_alg_by_name(optarg); |
@@ -1228,6 +1247,11 @@ main(int ac, char **av) | |||
1228 | case 'k': | 1247 | case 'k': |
1229 | k_flag++; | 1248 | k_flag++; |
1230 | break; | 1249 | break; |
1250 | case 'P': | ||
1251 | if (pkcs11_whitelist != NULL) | ||
1252 | fatal("-P option already specified"); | ||
1253 | pkcs11_whitelist = xstrdup(optarg); | ||
1254 | break; | ||
1231 | case 's': | 1255 | case 's': |
1232 | if (c_flag) | 1256 | if (c_flag) |
1233 | usage(); | 1257 | usage(); |
@@ -1262,6 +1286,9 @@ main(int ac, char **av) | |||
1262 | if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag)) | 1286 | if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag)) |
1263 | usage(); | 1287 | usage(); |
1264 | 1288 | ||
1289 | if (pkcs11_whitelist == NULL) | ||
1290 | pkcs11_whitelist = xstrdup(DEFAULT_PKCS11_WHITELIST); | ||
1291 | |||
1265 | if (ac == 0 && !c_flag && !s_flag) { | 1292 | if (ac == 0 && !c_flag && !s_flag) { |
1266 | shell = getenv("SHELL"); | 1293 | shell = getenv("SHELL"); |
1267 | if (shell != NULL && (len = strlen(shell)) > 2 && | 1294 | if (shell != NULL && (len = strlen(shell)) > 2 && |
@@ -1409,7 +1436,7 @@ skip: | |||
1409 | signal(SIGTERM, cleanup_handler); | 1436 | signal(SIGTERM, cleanup_handler); |
1410 | nalloc = 0; | 1437 | nalloc = 0; |
1411 | 1438 | ||
1412 | if (pledge("stdio cpath unix id proc exec", NULL) == -1) | 1439 | if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1) |
1413 | fatal("%s: pledge: %s", __progname, strerror(errno)); | 1440 | fatal("%s: pledge: %s", __progname, strerror(errno)); |
1414 | platform_pledge_agent(); | 1441 | platform_pledge_agent(); |
1415 | 1442 | ||