1 /*
2 * ProFTPD - mod_sftp 'publickey' user authentication
3 * Copyright (c) 2008-2021 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 */
24
25 #include "mod_sftp.h"
26 #include "ssh2.h"
27 #include "packet.h"
28 #include "msg.h"
29 #include "auth.h"
30 #include "session.h"
31 #include "keys.h"
32 #include "keystore.h"
33 #include "interop.h"
34 #include "blacklist.h"
35
36 /* This array tracks the fingerprints of publickeys that have been
37 * successfully verified. In any given session, the same publickey CANNOT
38 * be used twice for authentication; this supports authentication chains
39 * like "publickey+publickey", requiring clients to authenticate using multiple
40 * different publickeys.
41 */
42 static array_header *publickey_fps = NULL;
43
44 static const char *trace_channel = "ssh2";
45
send_pubkey_ok(const char * algo,const unsigned char * pubkey_data,uint32_t pubkey_len)46 static int send_pubkey_ok(const char *algo, const unsigned char *pubkey_data,
47 uint32_t pubkey_len) {
48 struct ssh2_packet *pkt;
49 unsigned char *buf, *ptr;
50 uint32_t buflen, bufsz;
51 int res;
52
53 /* Make sure to allocate a buffer large enough to hold the publickey
54 * data we're sending back.
55 */
56 bufsz = buflen = pubkey_len + 1024;
57
58 pkt = sftp_ssh2_packet_create(sftp_pool);
59
60 buflen = bufsz;
61 ptr = buf = palloc(pkt->pool, bufsz);
62
63 sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_PK_OK);
64 sftp_msg_write_string(&buf, &buflen, algo);
65 sftp_msg_write_data(&buf, &buflen, pubkey_data, pubkey_len, TRUE);
66
67 pkt->payload = ptr;
68 pkt->payload_len = (bufsz - buflen);
69
70 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "sending publickey OK");
71
72 res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt);
73 if (res < 0) {
74 destroy_pool(pkt->pool);
75 return -1;
76 }
77
78 destroy_pool(pkt->pool);
79 return 0;
80 }
81
sftp_auth_publickey(struct ssh2_packet * pkt,cmd_rec * pass_cmd,const char * orig_user,const char * user,const char * service,unsigned char ** buf,uint32_t * buflen,int * send_userauth_fail)82 int sftp_auth_publickey(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
83 const char *orig_user, const char *user, const char *service,
84 unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) {
85 register unsigned int i;
86 int fp_algo_id = 0, have_signature, res;
87 enum sftp_key_type_e pubkey_type;
88 unsigned char *pubkey_data;
89 char *pubkey_algo = NULL;
90 const char *fp = NULL, *fp_algo = NULL;
91 uint32_t pubkey_len;
92 struct passwd *pw;
93
94 if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) {
95 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
96 "authentication request for user '%s' blocked by '%s' handler",
97 orig_user, (char *) pass_cmd->argv[0]);
98
99 pr_log_auth(PR_LOG_NOTICE,
100 "USER %s (Login failed): blocked by '%s' handler", orig_user,
101 (char *) pass_cmd->argv[0]);
102
103 pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
104 pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
105
106 *send_userauth_fail = TRUE;
107 errno = EPERM;
108 return 0;
109 }
110
111 have_signature = sftp_msg_read_bool(pkt->pool, buf, buflen);
112
113 if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) {
114 pubkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen);
115 }
116 pubkey_len = sftp_msg_read_int(pkt->pool, buf, buflen);
117 pubkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, pubkey_len);
118
119 if (pubkey_algo == NULL) {
120 /* The client did not send the string identifying the public key algorithm.
121 * Thus we need to extract the algorithm string from the public key data.
122 */
123 pubkey_algo = sftp_msg_read_string(pkt->pool, &pubkey_data, &pubkey_len);
124 }
125
126 pr_trace_msg(trace_channel, 9, "client sent '%s' public key %s",
127 pubkey_algo, have_signature ? "with signature" : "without signature");
128
129 if (strncmp(pubkey_algo, "ssh-rsa", 8) == 0) {
130 pubkey_type = SFTP_KEY_RSA;
131
132 #ifdef HAVE_SHA256_OPENSSL
133 } else if (strncmp(pubkey_algo, "rsa-sha2-256", 13) == 0) {
134 pubkey_type = SFTP_KEY_RSA_SHA256;
135 #endif /* HAVE_SHA256_OPENSSL */
136
137 #ifdef HAVE_SHA512_OPENSSL
138 } else if (strncmp(pubkey_algo, "rsa-sha2-512", 13) == 0) {
139 pubkey_type = SFTP_KEY_RSA_SHA512;
140 #endif /* HAVE_SHA512_OPENSSL */
141
142 } else if (strncmp(pubkey_algo, "ssh-dss", 8) == 0) {
143 pubkey_type = SFTP_KEY_DSA;
144
145 #if defined(PR_USE_OPENSSL_ECC)
146 } else if (strncmp(pubkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
147 pubkey_type = SFTP_KEY_ECDSA_256;
148
149 } else if (strncmp(pubkey_algo, "ecdsa-sha2-nistp384", 20) == 0) {
150 pubkey_type = SFTP_KEY_ECDSA_384;
151
152 } else if (strncmp(pubkey_algo, "ecdsa-sha2-nistp521", 20) == 0) {
153 pubkey_type = SFTP_KEY_ECDSA_521;
154 #endif /* PR_USE_OPENSSL_ECC */
155
156 #if defined(PR_USE_SODIUM)
157 } else if (strncmp(pubkey_algo, "ssh-ed25519", 12) == 0) {
158 pubkey_type = SFTP_KEY_ED25519;
159 #endif /* PR_USE_SODIUM */
160
161 /* XXX This is where we would add support for X509 public keys, e.g.:
162 *
163 * x509v3-ssh-dss
164 * x509v3-ssh-rsa
165 * x509v3-sign (older)
166 *
167 */
168
169 } else {
170 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
171 "unsupported public key algorithm '%s' requested, rejecting request",
172 pubkey_algo);
173
174 pr_log_auth(PR_LOG_NOTICE,
175 "USER %s (Login failed): unsupported public key algorithm '%s' requested",
176 user, pubkey_algo);
177
178 *send_userauth_fail = TRUE;
179 errno = EINVAL;
180 return 0;
181 }
182
183 res = sftp_keys_verify_pubkey_type(pkt->pool, pubkey_data, pubkey_len,
184 pubkey_type);
185 if (res != TRUE) {
186 int xerrno = errno;
187
188 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
189 "unable to verify that given public key matches given '%s' algorithm",
190 pubkey_algo);
191
192 if (res < 0) {
193 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
194 "error verifying public key algorithm '%s': %s", pubkey_algo,
195 strerror(xerrno));
196 }
197
198 *send_userauth_fail = TRUE;
199 errno = EINVAL;
200 return 0;
201 }
202
203 #ifdef OPENSSL_FIPS
204 if (FIPS_mode()) {
205 # if defined(HAVE_SHA256_OPENSSL)
206 fp_algo_id = SFTP_KEYS_FP_DIGEST_SHA256;
207 fp_algo = "SHA256";
208 # else
209 fp_algo_id = SFTP_KEYS_FP_DIGEST_SHA1;
210 fp_algo = "SHA1";
211 # endif /* HAVE_SHA256_OPENSSL */
212
213 fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len,
214 fp_algo_id);
215 if (fp != NULL) {
216 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
217 "public key %s fingerprint: %s", fp_algo, fp);
218
219 } else {
220 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
221 "error obtaining public key %s fingerprint: %s", fp_algo,
222 strerror(errno));
223 fp_algo = NULL;
224 }
225
226 } else {
227 #endif /* OPENSSL_FIPS */
228 #if defined(HAVE_SHA256_OPENSSL)
229 fp_algo_id = SFTP_KEYS_FP_DIGEST_SHA256;
230 fp_algo = "SHA256";
231 #else
232 fp_algo_id = SFTP_KEYS_FP_DIGEST_MD5;
233 fp_algo = "MD5";
234 #endif /* HAVE_SHA256_OPENSSL */
235
236 fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len,
237 fp_algo_id);
238 if (fp != NULL) {
239 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
240 "public key %s fingerprint: %s", fp_algo, fp);
241
242 } else {
243 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
244 "error obtaining public key %s fingerprint: %s", fp_algo,
245 strerror(errno));
246 fp_algo = NULL;
247 }
248 #ifdef OPENSSL_FIPS
249 }
250 #endif /* OPENSSL_FIPS */
251
252 if (fp != NULL) {
253 const char *k, *v;
254
255 /* Log the fingerprint (and fingerprinting algorithm used), for
256 * debugging/auditing; make it available via environment variable as well.
257 */
258
259 k = pstrdup(session.pool, "SFTP_USER_PUBLICKEY_ALGO");
260 v = pstrdup(session.pool, pubkey_algo);
261 pr_env_unset(session.pool, k);
262 pr_env_set(session.pool, k, v);
263 (void) pr_table_add(session.notes, k, v, 0);
264
265 k = pstrdup(session.pool, "SFTP_USER_PUBLICKEY_FINGERPRINT");
266 v = pstrdup(session.pool, fp);
267 pr_env_unset(session.pool, k);
268 pr_env_set(session.pool, k, v);
269 (void) pr_table_add(session.notes, k, v, 0);
270
271 k = pstrdup(session.pool, "SFTP_USER_PUBLICKEY_FINGERPRINT_ALGO");
272 v = pstrdup(session.pool, fp_algo);
273 pr_env_unset(session.pool, k);
274 pr_env_set(session.pool, k, v);
275 (void) pr_table_add(session.notes, k, v, 0);
276 }
277
278 pw = pr_auth_getpwnam(pkt->pool, user);
279 if (pw == NULL) {
280 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
281 "no account for user '%s' found", user);
282
283 pr_log_auth(PR_LOG_NOTICE,
284 "USER %s: no such user found from %s [%s] to %s:%d", user,
285 session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr),
286 pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port);
287
288 *send_userauth_fail = TRUE;
289 errno = ENOENT;
290 return 0;
291 }
292
293 if (!have_signature) {
294 /* We don't perform the actual authentication just yet; we need to
295 * let the client know that the pubkey algorithms are acceptable.
296 */
297 if (send_pubkey_ok(pubkey_algo, pubkey_data, pubkey_len) < 0) {
298 return -1;
299 }
300
301 return 0;
302
303 } else {
304 const unsigned char *id;
305 unsigned char *buf2, *ptr2, *signature_data;
306 uint32_t buflen2, bufsz2, id_len, signature_len;
307
308 /* XXX This should become a more generic "is this key data
309 * usable/acceptable?" check (and take the pubkey_type parameter), so that
310 * that is where we would check the validity/usability of an X509v3 cert
311 * (if a cert), or if the key is on the blacklist (if a key).
312 */
313
314 if (sftp_blacklist_reject_key(pkt->pool, pubkey_data, pubkey_len)) {
315 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): requested public "
316 "key is blacklisted", user);
317
318 *send_userauth_fail = TRUE;
319 errno = EPERM;
320 return 0;
321 }
322
323 signature_len = sftp_msg_read_int(pkt->pool, buf, buflen);
324 signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len);
325
326 /* The client signed the request as well; we need to authenticate the
327 * user with the given pubkey now. If that succeeds, we use the
328 * signature to verify the request. And if that succeeds, then we're
329 * done authenticating.
330 */
331
332 /* XXX Need to pass the pubkey_type here as well, so that the
333 * verification routines can handle different databases of keys/certs.
334 *
335 * For X509v3 certs, we will want a way to enforce/restrict which
336 * user names can be used with the provided cert. Perhaps a database
337 * mapping cert fingerprints to user names/UIDs? Configurable callback
338 * check (HOOK?), for modules to enforce.
339 */
340
341 if (sftp_keystore_verify_user_key(pkt->pool, user, pubkey_data,
342 pubkey_len) < 0) {
343 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): authentication "
344 "via '%s' public key failed", user, pubkey_algo);
345
346 *send_userauth_fail = TRUE;
347 errno = EACCES;
348 return 0;
349 }
350
351 /* Make sure the signature matches as well. */
352
353 id_len = sftp_session_get_id(&id);
354
355 /* Make sure to allocate a buffer large enough to hold the publickey
356 * signature and data we want to send back.
357 */
358 bufsz2 = buflen2 = pubkey_len + 1024;
359 ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2);
360
361 sftp_msg_write_data(&buf2, &buflen2, id, id_len, TRUE);
362 sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST);
363 sftp_msg_write_string(&buf2, &buflen2, orig_user);
364
365 if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_PUBKEY_SIG)) {
366 sftp_msg_write_string(&buf2, &buflen2, service);
367
368 } else {
369 sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth");
370 }
371
372 if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) {
373 sftp_msg_write_string(&buf2, &buflen2, "publickey");
374 sftp_msg_write_bool(&buf2, &buflen2, TRUE);
375 sftp_msg_write_string(&buf2, &buflen2, pubkey_algo);
376
377 } else {
378 sftp_msg_write_bool(&buf2, &buflen2, TRUE);
379 }
380
381 sftp_msg_write_data(&buf2, &buflen2, pubkey_data, pubkey_len, TRUE);
382
383 if (sftp_keys_verify_signed_data(pkt->pool, pubkey_algo, pubkey_data,
384 pubkey_len, signature_data, signature_len, (unsigned char *) ptr2,
385 (bufsz2 - buflen2)) < 0) {
386 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
387 "failed to verify '%s' signature on public key auth request for "
388 "user '%s'", pubkey_algo, orig_user);
389
390 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): signature "
391 "verification of '%s' public key failed", user, pubkey_algo);
392
393 *send_userauth_fail = TRUE;
394 errno = EACCES;
395 return 0;
396 }
397 }
398
399 /* Make sure the user is authorized to login. Normally this is checked
400 * as part of the password verification process, but in the case of
401 * publickey authentication, there is no password to verify.
402 */
403
404 if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) {
405 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
406 "authentication for user '%s' failed: User not authorized", user);
407 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized "
408 "for login", user);
409 *send_userauth_fail = TRUE;
410 errno = EACCES;
411 return 0;
412 }
413
414 /* Check the key fingerprint against any previously used keys, to see if the
415 * same key is being reused.
416 */
417 for (i = 0; i < publickey_fps->nelts; i++) {
418 char *fpi;
419
420 fpi = ((char **) publickey_fps->elts)[i];
421 if (strcmp(fp, fpi) == 0) {
422 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
423 "publickey request reused previously verified publickey "
424 "(fingerprint %s), rejecting", fp);
425
426 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): public key request "
427 "reused previously verified public key (fingerprint %s)", user, fp);
428
429 *send_userauth_fail = TRUE;
430 errno = EACCES;
431 return 0;
432 }
433 }
434
435 /* Store the fingerprint for future checking. */
436 *((char **) push_array(publickey_fps)) = pstrdup(sftp_pool, fp);
437
438 return 1;
439 }
440
sftp_auth_publickey_init(pool * p)441 int sftp_auth_publickey_init(pool *p) {
442 publickey_fps = make_array(p, 0, sizeof(char *));
443
444 return 0;
445 }
446