summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2008-11-05 16:20:46 +1100
committerDamien Miller <djm@mindrot.org>2008-11-05 16:20:46 +1100
commit01ed2272a1545336173bf3aef66fbccc3494c8d8 (patch)
treea77f115d3b8964f0b6fcc604f9dea87d15143d7e /sshconnect2.c
parent6f66d34308af787613d5525729953665f26367ee (diff)
- djm@cvs.openbsd.org 2008/11/04 08:22:13
[auth.h auth2.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h] [readconf.c readconf.h servconf.c servconf.h ssh2.h ssh_config.5] [sshconnect2.c sshd_config.5 jpake.c jpake.h schnorr.c auth2-jpake.c] [Makefile.in] Add support for an experimental zero-knowledge password authentication method using the J-PAKE protocol described in F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling", 16th Workshop on Security Protocols, Cambridge, April 2008. This method allows password-based authentication without exposing the password to the server. Instead, the client and server exchange cryptographic proofs to demonstrate of knowledge of the password while revealing nothing useful to an attacker or compromised endpoint. This is experimental, work-in-progress code and is presently compiled-time disabled (turn on -DJPAKE in Makefile.inc). "just commit it. It isn't too intrusive." deraadt@
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c303
1 files changed, 301 insertions, 2 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 7d0c5e825..a762eec3b 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,6 +1,7 @@
1/* $OpenBSD: sshconnect2.c,v 1.169 2008/11/01 04:50:08 djm Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.170 2008/11/04 08:22:13 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 * 5 *
5 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -67,6 +68,7 @@
67#include "msg.h" 68#include "msg.h"
68#include "pathnames.h" 69#include "pathnames.h"
69#include "uidswap.h" 70#include "uidswap.h"
71#include "jpake.h"
70 72
71#ifdef GSSAPI 73#ifdef GSSAPI
72#include "ssh-gss.h" 74#include "ssh-gss.h"
@@ -201,6 +203,7 @@ struct Authctxt {
201struct Authmethod { 203struct Authmethod {
202 char *name; /* string to compare against server's list */ 204 char *name; /* string to compare against server's list */
203 int (*userauth)(Authctxt *authctxt); 205 int (*userauth)(Authctxt *authctxt);
206 void (*cleanup)(Authctxt *authctxt);
204 int *enabled; /* flag in option struct that enables method */ 207 int *enabled; /* flag in option struct that enables method */
205 int *batch_flag; /* flag in option struct that disables method */ 208 int *batch_flag; /* flag in option struct that disables method */
206}; 209};
@@ -212,12 +215,18 @@ void input_userauth_error(int, u_int32_t, void *);
212void input_userauth_info_req(int, u_int32_t, void *); 215void input_userauth_info_req(int, u_int32_t, void *);
213void input_userauth_pk_ok(int, u_int32_t, void *); 216void input_userauth_pk_ok(int, u_int32_t, void *);
214void input_userauth_passwd_changereq(int, u_int32_t, void *); 217void input_userauth_passwd_changereq(int, u_int32_t, void *);
218void input_userauth_jpake_server_step1(int, u_int32_t, void *);
219void input_userauth_jpake_server_step2(int, u_int32_t, void *);
220void input_userauth_jpake_server_confirm(int, u_int32_t, void *);
215 221
216int userauth_none(Authctxt *); 222int userauth_none(Authctxt *);
217int userauth_pubkey(Authctxt *); 223int userauth_pubkey(Authctxt *);
218int userauth_passwd(Authctxt *); 224int userauth_passwd(Authctxt *);
219int userauth_kbdint(Authctxt *); 225int userauth_kbdint(Authctxt *);
220int userauth_hostbased(Authctxt *); 226int userauth_hostbased(Authctxt *);
227int userauth_jpake(Authctxt *);
228
229void userauth_jpake_cleanup(Authctxt *);
221 230
222#ifdef GSSAPI 231#ifdef GSSAPI
223int userauth_gssapi(Authctxt *authctxt); 232int userauth_gssapi(Authctxt *authctxt);
@@ -243,30 +252,43 @@ Authmethod authmethods[] = {
243#ifdef GSSAPI 252#ifdef GSSAPI
244 {"gssapi-with-mic", 253 {"gssapi-with-mic",
245 userauth_gssapi, 254 userauth_gssapi,
255 NULL,
246 &options.gss_authentication, 256 &options.gss_authentication,
247 NULL}, 257 NULL},
248#endif 258#endif
249 {"hostbased", 259 {"hostbased",
250 userauth_hostbased, 260 userauth_hostbased,
261 NULL,
251 &options.hostbased_authentication, 262 &options.hostbased_authentication,
252 NULL}, 263 NULL},
253 {"publickey", 264 {"publickey",
254 userauth_pubkey, 265 userauth_pubkey,
266 NULL,
255 &options.pubkey_authentication, 267 &options.pubkey_authentication,
256 NULL}, 268 NULL},
269#ifdef JPAKE
270 {"jpake-01@openssh.com",
271 userauth_jpake,
272 userauth_jpake_cleanup,
273 &options.zero_knowledge_password_authentication,
274 &options.batch_mode},
275#endif
257 {"keyboard-interactive", 276 {"keyboard-interactive",
258 userauth_kbdint, 277 userauth_kbdint,
278 NULL,
259 &options.kbd_interactive_authentication, 279 &options.kbd_interactive_authentication,
260 &options.batch_mode}, 280 &options.batch_mode},
261 {"password", 281 {"password",
262 userauth_passwd, 282 userauth_passwd,
283 NULL,
263 &options.password_authentication, 284 &options.password_authentication,
264 &options.batch_mode}, 285 &options.batch_mode},
265 {"none", 286 {"none",
266 userauth_none, 287 userauth_none,
267 NULL, 288 NULL,
289 NULL,
268 NULL}, 290 NULL},
269 {NULL, NULL, NULL, NULL} 291 {NULL, NULL, NULL, NULL, NULL}
270}; 292};
271 293
272void 294void
@@ -334,6 +356,9 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
334void 356void
335userauth(Authctxt *authctxt, char *authlist) 357userauth(Authctxt *authctxt, char *authlist)
336{ 358{
359 if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
360 authctxt->method->cleanup(authctxt);
361
337 if (authctxt->methoddata) { 362 if (authctxt->methoddata) {
338 xfree(authctxt->methoddata); 363 xfree(authctxt->methoddata);
339 authctxt->methoddata = NULL; 364 authctxt->methoddata = NULL;
@@ -851,6 +876,209 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
851 &input_userauth_passwd_changereq); 876 &input_userauth_passwd_changereq);
852} 877}
853 878
879#ifdef JPAKE
880static char *
881pw_encrypt(const char *password, const char *crypt_scheme, const char *salt)
882{
883 /* OpenBSD crypt(3) handles all of these */
884 if (strcmp(crypt_scheme, "crypt") == 0 ||
885 strcmp(crypt_scheme, "bcrypt") == 0 ||
886 strcmp(crypt_scheme, "md5crypt") == 0 ||
887 strcmp(crypt_scheme, "crypt-extended") == 0)
888 return xstrdup(crypt(password, salt));
889 error("%s: unsupported password encryption scheme \"%.100s\"",
890 __func__, crypt_scheme);
891 return NULL;
892}
893
894static BIGNUM *
895jpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme,
896 const char *salt)
897{
898 char prompt[256], *password, *crypted;
899 u_char *secret;
900 u_int secret_len;
901 BIGNUM *ret;
902
903 snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ",
904 authctxt->server_user, authctxt->host);
905 password = read_passphrase(prompt, 0);
906
907 if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) {
908 logit("Disabling %s authentication", authctxt->method->name);
909 authctxt->method->enabled = NULL;
910 /* Continue with an empty password to fail gracefully */
911 crypted = xstrdup("");
912 }
913
914#ifdef JPAKE_DEBUG
915 debug3("%s: salt = %s", __func__, salt);
916 debug3("%s: scheme = %s", __func__, crypt_scheme);
917 debug3("%s: crypted = %s", __func__, crypted);
918#endif
919
920 if (hash_buffer(crypted, strlen(crypted), EVP_sha256(),
921 &secret, &secret_len) != 0)
922 fatal("%s: hash_buffer", __func__);
923
924 bzero(password, strlen(password));
925 bzero(crypted, strlen(crypted));
926 xfree(password);
927 xfree(crypted);
928
929 if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL)
930 fatal("%s: BN_bin2bn (secret)", __func__);
931 bzero(secret, secret_len);
932 xfree(secret);
933
934 return ret;
935}
936
937/* ARGSUSED */
938void
939input_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt)
940{
941 Authctxt *authctxt = ctxt;
942 struct jpake_ctx *pctx = authctxt->methoddata;
943 u_char *x3_proof, *x4_proof, *x2_s_proof;
944 u_int x3_proof_len, x4_proof_len, x2_s_proof_len;
945 char *crypt_scheme, *salt;
946
947 /* Disable this message */
948 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL);
949
950 if ((pctx->g_x3 = BN_new()) == NULL ||
951 (pctx->g_x4 = BN_new()) == NULL)
952 fatal("%s: BN_new", __func__);
953
954 /* Fetch step 1 values */
955 crypt_scheme = packet_get_string(NULL);
956 salt = packet_get_string(NULL);
957 pctx->server_id = packet_get_string(&pctx->server_id_len);
958 packet_get_bignum2(pctx->g_x3);
959 packet_get_bignum2(pctx->g_x4);
960 x3_proof = packet_get_string(&x3_proof_len);
961 x4_proof = packet_get_string(&x4_proof_len);
962 packet_check_eom();
963
964 JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__));
965
966 /* Obtain password and derive secret */
967 pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt);
968 bzero(crypt_scheme, strlen(crypt_scheme));
969 bzero(salt, strlen(salt));
970 xfree(crypt_scheme);
971 xfree(salt);
972 JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__));
973
974 /* Calculate step 2 values */
975 jpake_step2(pctx->grp, pctx->s, pctx->g_x1,
976 pctx->g_x3, pctx->g_x4, pctx->x2,
977 pctx->server_id, pctx->server_id_len,
978 pctx->client_id, pctx->client_id_len,
979 x3_proof, x3_proof_len,
980 x4_proof, x4_proof_len,
981 &pctx->a,
982 &x2_s_proof, &x2_s_proof_len);
983
984 bzero(x3_proof, x3_proof_len);
985 bzero(x4_proof, x4_proof_len);
986 xfree(x3_proof);
987 xfree(x4_proof);
988
989 JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__));
990
991 /* Send values for step 2 */
992 packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2);
993 packet_put_bignum2(pctx->a);
994 packet_put_string(x2_s_proof, x2_s_proof_len);
995 packet_send();
996
997 bzero(x2_s_proof, x2_s_proof_len);
998 xfree(x2_s_proof);
999
1000 /* Expect step 2 packet from peer */
1001 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2,
1002 input_userauth_jpake_server_step2);
1003}
1004
1005/* ARGSUSED */
1006void
1007input_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt)
1008{
1009 Authctxt *authctxt = ctxt;
1010 struct jpake_ctx *pctx = authctxt->methoddata;
1011 u_char *x4_s_proof;
1012 u_int x4_s_proof_len;
1013
1014 /* Disable this message */
1015 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL);
1016
1017 if ((pctx->b = BN_new()) == NULL)
1018 fatal("%s: BN_new", __func__);
1019
1020 /* Fetch step 2 values */
1021 packet_get_bignum2(pctx->b);
1022 x4_s_proof = packet_get_string(&x4_s_proof_len);
1023 packet_check_eom();
1024
1025 JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__));
1026
1027 /* Derive shared key and calculate confirmation hash */
1028 jpake_key_confirm(pctx->grp, pctx->s, pctx->b,
1029 pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4,
1030 pctx->client_id, pctx->client_id_len,
1031 pctx->server_id, pctx->server_id_len,
1032 session_id2, session_id2_len,
1033 x4_s_proof, x4_s_proof_len,
1034 &pctx->k,
1035 &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len);
1036
1037 bzero(x4_s_proof, x4_s_proof_len);
1038 xfree(x4_s_proof);
1039
1040 JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__));
1041
1042 /* Send key confirmation proof */
1043 packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM);
1044 packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len);
1045 packet_send();
1046
1047 /* Expect confirmation from peer */
1048 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM,
1049 input_userauth_jpake_server_confirm);
1050}
1051
1052/* ARGSUSED */
1053void
1054input_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt)
1055{
1056 Authctxt *authctxt = ctxt;
1057 struct jpake_ctx *pctx = authctxt->methoddata;
1058
1059 /* Disable this message */
1060 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL);
1061
1062 pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len);
1063 packet_check_eom();
1064
1065 JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__));
1066
1067 /* Verify expected confirmation hash */
1068 if (jpake_check_confirm(pctx->k,
1069 pctx->server_id, pctx->server_id_len,
1070 session_id2, session_id2_len,
1071 pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1)
1072 debug("%s: %s success", __func__, authctxt->method->name);
1073 else {
1074 debug("%s: confirmation mismatch", __func__);
1075 /* XXX stash this so if auth succeeds then we can warn/kill */
1076 }
1077
1078 userauth_jpake_cleanup(authctxt);
1079}
1080#endif /* JPAKE */
1081
854static int 1082static int
855identity_sign(Identity *id, u_char **sigp, u_int *lenp, 1083identity_sign(Identity *id, u_char **sigp, u_int *lenp,
856 u_char *data, u_int datalen) 1084 u_char *data, u_int datalen)
@@ -1425,6 +1653,76 @@ userauth_hostbased(Authctxt *authctxt)
1425 return 1; 1653 return 1;
1426} 1654}
1427 1655
1656#ifdef JPAKE
1657int
1658userauth_jpake(Authctxt *authctxt)
1659{
1660 struct jpake_ctx *pctx;
1661 u_char *x1_proof, *x2_proof;
1662 u_int x1_proof_len, x2_proof_len;
1663 static int attempt = 0; /* XXX share with userauth_password's? */
1664
1665 if (attempt++ >= options.number_of_password_prompts)
1666 return 0;
1667 if (attempt != 1)
1668 error("Permission denied, please try again.");
1669
1670 if (authctxt->methoddata != NULL)
1671 fatal("%s: authctxt->methoddata already set (%p)",
1672 __func__, authctxt->methoddata);
1673
1674 authctxt->methoddata = pctx = jpake_new();
1675
1676 /*
1677 * Send request immediately, to get the protocol going while
1678 * we do the initial computations.
1679 */
1680 packet_start(SSH2_MSG_USERAUTH_REQUEST);
1681 packet_put_cstring(authctxt->server_user);
1682 packet_put_cstring(authctxt->service);
1683 packet_put_cstring(authctxt->method->name);
1684 packet_send();
1685 packet_write_wait();
1686
1687 jpake_step1(pctx->grp,
1688 &pctx->client_id, &pctx->client_id_len,
1689 &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2,
1690 &x1_proof, &x1_proof_len,
1691 &x2_proof, &x2_proof_len);
1692
1693 JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__));
1694
1695 packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1);
1696 packet_put_string(pctx->client_id, pctx->client_id_len);
1697 packet_put_bignum2(pctx->g_x1);
1698 packet_put_bignum2(pctx->g_x2);
1699 packet_put_string(x1_proof, x1_proof_len);
1700 packet_put_string(x2_proof, x2_proof_len);
1701 packet_send();
1702
1703 bzero(x1_proof, x1_proof_len);
1704 bzero(x2_proof, x2_proof_len);
1705 xfree(x1_proof);
1706 xfree(x2_proof);
1707
1708 /* Expect step 1 packet from peer */
1709 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1,
1710 input_userauth_jpake_server_step1);
1711
1712 return 1;
1713}
1714
1715void
1716userauth_jpake_cleanup(Authctxt *authctxt)
1717{
1718 debug3("%s: clean up", __func__);
1719 if (authctxt->methoddata != NULL) {
1720 jpake_free(authctxt->methoddata);
1721 authctxt->methoddata = NULL;
1722 }
1723}
1724#endif /* JPAKE */
1725
1428/* find auth method */ 1726/* find auth method */
1429 1727
1430/* 1728/*
@@ -1526,3 +1824,4 @@ authmethods_get(void)
1526 buffer_free(&b); 1824 buffer_free(&b);
1527 return list; 1825 return list;
1528} 1826}
1827