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