View | Details | Raw Unified | Return to bug 2322
Collapse All | Expand All

(-)usr.bin/ssh/auth.h (+7 lines)
Lines 37-42 Link Here
37
#include <krb5.h>
37
#include <krb5.h>
38
#endif
38
#endif
39
39
40
struct sshkey;
41
40
typedef struct Authctxt Authctxt;
42
typedef struct Authctxt Authctxt;
41
typedef struct Authmethod Authmethod;
43
typedef struct Authmethod Authmethod;
42
typedef struct KbdintDevice KbdintDevice;
44
typedef struct KbdintDevice KbdintDevice;
Lines 66-71 struct Authctxt { Link Here
66
	char		*krb5_ticket_file;
68
	char		*krb5_ticket_file;
67
#endif
69
#endif
68
	void		*methoddata;
70
	void		*methoddata;
71
72
	struct sshkey	**prev_userkeys;
73
	u_int		 nprev_userkeys;
69
};
74
};
70
/*
75
/*
71
 * Every authentication method has to handle authentication requests for
76
 * Every authentication method has to handle authentication requests for
Lines 114-119 int hostbased_key_allowed(struct passwd Link Here
114
int	 user_key_allowed(struct passwd *, Key *);
119
int	 user_key_allowed(struct passwd *, Key *);
115
void	 pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
120
void	 pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
116
	    __attribute__((__format__ (printf, 3, 4)));
121
	    __attribute__((__format__ (printf, 3, 4)));
122
void	 auth2_record_userkey(Authctxt *, struct sshkey *);
123
int	 auth2_userkey_already_used(Authctxt *, struct sshkey *);
117
124
118
struct stat;
125
struct stat;
119
int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
126
int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
(-)usr.bin/ssh/auth2-pubkey.c (-1 / +39 lines)
Lines 38-43 Link Here
38
#include <string.h>
38
#include <string.h>
39
#include <time.h>
39
#include <time.h>
40
#include <unistd.h>
40
#include <unistd.h>
41
#include <limits.h>
41
42
42
#include "xmalloc.h"
43
#include "xmalloc.h"
43
#include "ssh.h"
44
#include "ssh.h"
Lines 119-124 userauth_pubkey(Authctxt *authctxt) Link Here
119
		    "signature scheme");
120
		    "signature scheme");
120
		goto done;
121
		goto done;
121
	}
122
	}
123
	if (auth2_userkey_already_used(authctxt, key)) {
124
		logit("refusing previously-used %s key", key_type(key));
125
		goto done;
126
	}
122
	if (have_sig) {
127
	if (have_sig) {
123
		sig = packet_get_string(&slen);
128
		sig = packet_get_string(&slen);
124
		packet_check_eom();
129
		packet_check_eom();
Lines 156-163 userauth_pubkey(Authctxt *authctxt) Link Here
156
		authenticated = 0;
161
		authenticated = 0;
157
		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
162
		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
158
		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
163
		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
159
		    buffer_len(&b))) == 1)
164
		    buffer_len(&b))) == 1) {
160
			authenticated = 1;
165
			authenticated = 1;
166
			/* Record the successful key to prevent reuse */
167
			auth2_record_userkey(authctxt, key);
168
			key = NULL; /* Don't free below */
169
		}
161
		buffer_free(&b);
170
		buffer_free(&b);
162
		free(sig);
171
		free(sig);
163
	} else {
172
	} else {
Lines 675-680 user_key_allowed(struct passwd *pw, Key Link Here
675
	}
684
	}
676
685
677
	return success;
686
	return success;
687
}
688
689
/* Records a public key in the list of previously-successful keys */
690
void
691
auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
692
{
693
	struct sshkey **tmp;
694
695
	if (authctxt->nprev_userkeys >= INT_MAX ||
696
	    (tmp = reallocarray(authctxt->prev_userkeys,
697
	    authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL)
698
		fatal("%s: reallocarray failed", __func__);
699
	authctxt->prev_userkeys = tmp;
700
	authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
701
	authctxt->nprev_userkeys++;
702
}
703
704
/* Checks whether a key has already been used successfully for authentication */
705
int
706
auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
707
{
708
	u_int i;
709
710
	for (i = 0; i < authctxt->nprev_userkeys; i++) {
711
		if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
712
			return 1;
713
		}
714
	}
715
	return 0;
678
}
716
}
679
717
680
Authmethod method_pubkey = {
718
Authmethod method_pubkey = {
(-)usr.bin/ssh/monitor.c (-1 / +7 lines)
Lines 884-889 mm_answer_keyallowed(int sock, Buffer *m Link Here
884
		switch (type) {
884
		switch (type) {
885
		case MM_USERKEY:
885
		case MM_USERKEY:
886
			allowed = options.pubkey_authentication &&
886
			allowed = options.pubkey_authentication &&
887
			    !auth2_userkey_already_used(authctxt, key) &&
887
			    user_key_allowed(authctxt->pw, key);
888
			    user_key_allowed(authctxt->pw, key);
888
			pubkey_auth_info(authctxt, key, NULL);
889
			pubkey_auth_info(authctxt, key, NULL);
889
			auth_method = "publickey";
890
			auth_method = "publickey";
Lines 1111-1117 mm_answer_keyverify(int sock, Buffer *m) Link Here
1111
	debug3("%s: key %p signature %s",
1112
	debug3("%s: key %p signature %s",
1112
	    __func__, key, (verified == 1) ? "verified" : "unverified");
1113
	    __func__, key, (verified == 1) ? "verified" : "unverified");
1113
1114
1114
	key_free(key);
1115
	/* If auth was successful then record key to ensure it isn't reused */
1116
	if (verified == 1)
1117
		auth2_record_userkey(authctxt, key);
1118
	else
1119
		key_free(key);
1120
1115
	free(blob);
1121
	free(blob);
1116
	free(signature);
1122
	free(signature);
1117
	free(data);
1123
	free(data);
(-)usr.bin/ssh/sshd_config.5 (+12 lines)
Lines 210-215 would restrict keyboard interactive auth Link Here
210
.Dq bsdauth
210
.Dq bsdauth
211
device.
211
device.
212
.Pp
212
.Pp
213
If the
214
.Dq publickey
215
method is listed more than one,
216
.Xr sshd 8
217
verifies that keys that have been successfully are not reused for subsequent
218
authentications.
219
For example, an
220
.Cm AuthenticationMethods
221
of
222
.Dq publickey,publickey
223
will require successful authentication using two different public keys.
224
.Pp
213
This option is only available for SSH protocol 2 and will yield a fatal
225
This option is only available for SSH protocol 2 and will yield a fatal
214
error if enabled if protocol 1 is also enabled.
226
error if enabled if protocol 1 is also enabled.
215
Note that each authentication method listed should also be explicitly enabled
227
Note that each authentication method listed should also be explicitly enabled
(-)regress/usr.bin/ssh/Makefile (-1 / +2 lines)
Lines 58-64 LTESTS= connect \ Link Here
58
		keys-command \
58
		keys-command \
59
		forward-control \
59
		forward-control \
60
		integrity \
60
		integrity \
61
		krl
61
		krl \
62
		multipubkey
62
63
63
INTEROP_TESTS=	putty-transfer putty-ciphers putty-kex conch-ciphers
64
INTEROP_TESTS=	putty-transfer putty-ciphers putty-kex conch-ciphers
64
#INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp
65
#INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp
(-)regress/usr.bin/ssh/multipubkey.sh (+66 lines)
Added Link Here
1
#	$OpenBSD$
2
#	Placed in the Public Domain.
3
4
tid="multiple pubkey"
5
6
rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/user_key*
7
rm -f $OBJ/authorized_principals_$USER $OBJ/cert_user_key*
8
9
mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig
10
mv $OBJ/ssh_proxy $OBJ/ssh_proxy.orig
11
12
# Create a CA key
13
${SSHKEYGEN} -q -N '' -t ed25519  -f $OBJ/user_ca_key ||\
14
	fatal "ssh-keygen failed"
15
16
# Make some keys and a certificate.
17
${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key1 || \
18
	fatal "ssh-keygen failed"
19
${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key2 || \
20
	fatal "ssh-keygen failed"
21
${SSHKEYGEN} -q -s $OBJ/user_ca_key -I "regress user key for $USER" \
22
	-z $$ -n ${USER},mekmitasdigoat $OBJ/user_key1 ||
23
		fail "couldn't sign user_key1"
24
# Copy the private key alongside the cert to allow better control of when
25
# it is offered.
26
mv $OBJ/user_key1-cert.pub $OBJ/cert_user_key1.pub
27
cp -p $OBJ/user_key1 $OBJ/cert_user_key1
28
29
grep -v IdentityFile $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy
30
31
opts="-oProtocol=2 -F $OBJ/ssh_proxy -oIdentitiesOnly=yes"
32
opts="$opts -i $OBJ/cert_user_key1 -i $OBJ/user_key1 -i $OBJ/user_key2"
33
34
for privsep in no yes; do
35
	(
36
		grep -v "Protocol"  $OBJ/sshd_proxy.orig
37
		echo "Protocol 2"
38
		echo "UsePrivilegeSeparation $privsep"
39
		echo "AuthenticationMethods publickey,publickey"
40
		echo "TrustedUserCAKeys $OBJ/user_ca_key.pub"
41
		echo "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u"
42
 	) > $OBJ/sshd_proxy
43
44
	# Single key should fail.
45
	rm -f $OBJ/authorized_principals_$USER
46
	cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER
47
	${SSH} $opts proxy true && fail "ssh succeeded with key"
48
49
	# Single key with same-public cert should fail.
50
	echo mekmitasdigoat > $OBJ/authorized_principals_$USER
51
	cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER
52
	${SSH} $opts proxy true && fail "ssh succeeded with key+cert"
53
54
	# Multiple plain keys should succeed.
55
	rm -f $OBJ/authorized_principals_$USER
56
	cat $OBJ/user_key1.pub $OBJ/user_key2.pub > \
57
	    $OBJ/authorized_keys_$USER
58
	${SSH} $opts proxy true || fail "ssh failed with multiple keys"
59
	# Cert and different key should succeed
60
61
	# Key and different-public cert should succeed.
62
	echo mekmitasdigoat > $OBJ/authorized_principals_$USER
63
	cat $OBJ/user_key2.pub > $OBJ/authorized_keys_$USER
64
	${SSH} $opts proxy true || fail "ssh failed with key/cert"
65
done
66

Return to bug 2322