diff options
Diffstat (limited to 'kexgsss.c')
-rw-r--r-- | kexgsss.c | 110 |
1 files changed, 81 insertions, 29 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2001-2004 Simon Wilkinson. All rights reserved. | 2 | * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved. |
3 | * | 3 | * |
4 | * Redistribution and use in source and binary forms, with or without | 4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions | 5 | * modification, are permitted provided that the following conditions |
@@ -53,21 +53,30 @@ kexgss_server(Kex *kex) | |||
53 | */ | 53 | */ |
54 | 54 | ||
55 | OM_uint32 ret_flags = 0; | 55 | OM_uint32 ret_flags = 0; |
56 | gss_buffer_desc gssbuf, send_tok, recv_tok, msg_tok; | 56 | gss_buffer_desc gssbuf, recv_tok, msg_tok; |
57 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
57 | Gssctxt *ctxt = NULL; | 58 | Gssctxt *ctxt = NULL; |
58 | unsigned int klen, kout; | 59 | u_int slen, klen, kout, hashlen; |
59 | unsigned char *kbuf, *hash; | 60 | u_char *kbuf, *hash; |
60 | DH *dh; | 61 | DH *dh; |
62 | int min = -1, max = -1, nbits = -1; | ||
61 | BIGNUM *shared_secret = NULL; | 63 | BIGNUM *shared_secret = NULL; |
62 | BIGNUM *dh_client_pub = NULL; | 64 | BIGNUM *dh_client_pub = NULL; |
63 | int type =0; | 65 | int type = 0; |
64 | u_int slen; | 66 | int gex; |
65 | gss_OID oid; | 67 | gss_OID oid; |
66 | 68 | ||
67 | /* Initialise GSSAPI */ | 69 | /* Initialise GSSAPI */ |
68 | 70 | ||
71 | /* If we're rekeying, privsep means that some of the private structures | ||
72 | * in the GSSAPI code are no longer available. This kludges them back | ||
73 | * into life | ||
74 | */ | ||
75 | if (!ssh_gssapi_oid_table_ok()) | ||
76 | ssh_gssapi_server_mechanisms(); | ||
77 | |||
69 | debug2("%s: Identifying %s", __func__, kex->name); | 78 | debug2("%s: Identifying %s", __func__, kex->name); |
70 | oid = ssh_gssapi_id_kex(NULL, kex->name); | 79 | oid = ssh_gssapi_id_kex(NULL, kex->name, &gex); |
71 | if (oid == NULL) | 80 | if (oid == NULL) |
72 | fatal("Unknown gssapi mechanism"); | 81 | fatal("Unknown gssapi mechanism"); |
73 | 82 | ||
@@ -76,6 +85,34 @@ kexgss_server(Kex *kex) | |||
76 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) | 85 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) |
77 | fatal("Unable to acquire credentials for the server"); | 86 | fatal("Unable to acquire credentials for the server"); |
78 | 87 | ||
88 | if (gex) { | ||
89 | debug("Doing group exchange"); | ||
90 | packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); | ||
91 | min = packet_get_int(); | ||
92 | nbits = packet_get_int(); | ||
93 | max = packet_get_int(); | ||
94 | min = MAX(DH_GRP_MIN, min); | ||
95 | max = MIN(DH_GRP_MAX, max); | ||
96 | packet_check_eom(); | ||
97 | if (max < min || nbits < min || max < nbits) | ||
98 | fatal("GSS_GEX, bad parameters: %d !< %d !< %d", | ||
99 | min, nbits, max); | ||
100 | dh = PRIVSEP(choose_dh(min, nbits, max)); | ||
101 | if (dh == NULL) | ||
102 | packet_disconnect("Protocol error: no matching group found"); | ||
103 | |||
104 | packet_start(SSH2_MSG_KEXGSS_GROUP); | ||
105 | packet_put_bignum2(dh->p); | ||
106 | packet_put_bignum2(dh->g); | ||
107 | packet_send(); | ||
108 | |||
109 | packet_write_wait(); | ||
110 | |||
111 | } else { | ||
112 | dh = dh_new_group1(); | ||
113 | } | ||
114 | dh_gen_key(dh, kex->we_need * 8); | ||
115 | |||
79 | do { | 116 | do { |
80 | debug("Wait SSH2_MSG_GSSAPI_INIT"); | 117 | debug("Wait SSH2_MSG_GSSAPI_INIT"); |
81 | type = packet_read(); | 118 | type = packet_read(); |
@@ -86,10 +123,9 @@ kexgss_server(Kex *kex) | |||
86 | recv_tok.value = packet_get_string(&slen); | 123 | recv_tok.value = packet_get_string(&slen); |
87 | recv_tok.length = slen; | 124 | recv_tok.length = slen; |
88 | 125 | ||
89 | dh_client_pub = BN_new(); | 126 | if ((dh_client_pub = BN_new()) == NULL) |
90 | |||
91 | if (dh_client_pub == NULL) | ||
92 | fatal("dh_client_pub == NULL"); | 127 | fatal("dh_client_pub == NULL"); |
128 | |||
93 | packet_get_bignum2(dh_client_pub); | 129 | packet_get_bignum2(dh_client_pub); |
94 | 130 | ||
95 | /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ | 131 | /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ |
@@ -107,8 +143,8 @@ kexgss_server(Kex *kex) | |||
107 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, | 143 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, |
108 | &send_tok, &ret_flags)); | 144 | &send_tok, &ret_flags)); |
109 | 145 | ||
110 | gss_release_buffer(&min_status, &recv_tok); | 146 | xfree(recv_tok.value); |
111 | 147 | ||
112 | if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) | 148 | if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) |
113 | fatal("Zero length token output when incomplete"); | 149 | fatal("Zero length token output when incomplete"); |
114 | 150 | ||
@@ -125,7 +161,7 @@ kexgss_server(Kex *kex) | |||
125 | } while (maj_status & GSS_S_CONTINUE_NEEDED); | 161 | } while (maj_status & GSS_S_CONTINUE_NEEDED); |
126 | 162 | ||
127 | if (GSS_ERROR(maj_status)) { | 163 | if (GSS_ERROR(maj_status)) { |
128 | if (send_tok.length>0) { | 164 | if (send_tok.length > 0) { |
129 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); | 165 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); |
130 | packet_put_string(send_tok.value, send_tok.length); | 166 | packet_put_string(send_tok.value, send_tok.length); |
131 | packet_send(); | 167 | packet_send(); |
@@ -139,9 +175,6 @@ kexgss_server(Kex *kex) | |||
139 | if (!(ret_flags & GSS_C_INTEG_FLAG)) | 175 | if (!(ret_flags & GSS_C_INTEG_FLAG)) |
140 | fatal("Integrity flag wasn't set"); | 176 | fatal("Integrity flag wasn't set"); |
141 | 177 | ||
142 | dh = dh_new_group1(); | ||
143 | dh_gen_key(dh, kex->we_need * 8); | ||
144 | |||
145 | if (!dh_pub_is_valid(dh, dh_client_pub)) | 178 | if (!dh_pub_is_valid(dh, dh_client_pub)) |
146 | packet_disconnect("bad client public DH value"); | 179 | packet_disconnect("bad client public DH value"); |
147 | 180 | ||
@@ -154,24 +187,42 @@ kexgss_server(Kex *kex) | |||
154 | memset(kbuf, 0, klen); | 187 | memset(kbuf, 0, klen); |
155 | xfree(kbuf); | 188 | xfree(kbuf); |
156 | 189 | ||
157 | /* The GSSAPI hash is identical to the Diffie Helman one */ | 190 | if (gex) { |
158 | hash = kex_dh_hash( | 191 | kexgex_hash( |
159 | kex->client_version_string, kex->server_version_string, | 192 | kex->evp_md, |
160 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | 193 | kex->client_version_string, kex->server_version_string, |
161 | buffer_ptr(&kex->my), buffer_len(&kex->my), | 194 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), |
162 | NULL, 0, /* Change this if we start sending host keys */ | 195 | buffer_ptr(&kex->my), buffer_len(&kex->my), |
163 | dh_client_pub, dh->pub_key, shared_secret | 196 | NULL, 0, |
164 | ); | 197 | min, nbits, max, |
198 | dh->p, dh->g, | ||
199 | dh_client_pub, | ||
200 | dh->pub_key, | ||
201 | shared_secret, | ||
202 | &hash, &hashlen | ||
203 | ); | ||
204 | } | ||
205 | else { | ||
206 | /* The GSSAPI hash is identical to the Diffie Helman one */ | ||
207 | kex_dh_hash( | ||
208 | kex->client_version_string, kex->server_version_string, | ||
209 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
210 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
211 | NULL, 0, /* Change this if we start sending host keys */ | ||
212 | dh_client_pub, dh->pub_key, shared_secret, | ||
213 | &hash, &hashlen | ||
214 | ); | ||
215 | } | ||
165 | BN_free(dh_client_pub); | 216 | BN_free(dh_client_pub); |
166 | 217 | ||
167 | if (kex->session_id == NULL) { | 218 | if (kex->session_id == NULL) { |
168 | kex->session_id_len = 20; | 219 | kex->session_id_len = hashlen; |
169 | kex->session_id = xmalloc(kex->session_id_len); | 220 | kex->session_id = xmalloc(kex->session_id_len); |
170 | memcpy(kex->session_id, hash, kex->session_id_len); | 221 | memcpy(kex->session_id, hash, kex->session_id_len); |
171 | } | 222 | } |
172 | 223 | ||
173 | gssbuf.value = hash; | 224 | gssbuf.value = hash; |
174 | gssbuf.length = 20; /* Hashlen appears to always be 20 */ | 225 | gssbuf.length = hashlen; |
175 | 226 | ||
176 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) | 227 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) |
177 | fatal("Couldn't get MIC"); | 228 | fatal("Couldn't get MIC"); |
@@ -180,7 +231,7 @@ kexgss_server(Kex *kex) | |||
180 | packet_put_bignum2(dh->pub_key); | 231 | packet_put_bignum2(dh->pub_key); |
181 | packet_put_string((char *)msg_tok.value,msg_tok.length); | 232 | packet_put_string((char *)msg_tok.value,msg_tok.length); |
182 | 233 | ||
183 | if (send_tok.length!=0) { | 234 | if (send_tok.length != 0) { |
184 | packet_put_char(1); /* true */ | 235 | packet_put_char(1); /* true */ |
185 | packet_put_string((char *)send_tok.value, send_tok.length); | 236 | packet_put_string((char *)send_tok.value, send_tok.length); |
186 | } else { | 237 | } else { |
@@ -188,7 +239,8 @@ kexgss_server(Kex *kex) | |||
188 | } | 239 | } |
189 | packet_send(); | 240 | packet_send(); |
190 | 241 | ||
191 | gss_release_buffer(&min_status, &send_tok); | 242 | gss_release_buffer(&min_status, &send_tok); |
243 | gss_release_buffer(&min_status, &msg_tok); | ||
192 | 244 | ||
193 | if (gss_kex_context == NULL) | 245 | if (gss_kex_context == NULL) |
194 | gss_kex_context = ctxt; | 246 | gss_kex_context = ctxt; |
@@ -197,7 +249,7 @@ kexgss_server(Kex *kex) | |||
197 | 249 | ||
198 | DH_free(dh); | 250 | DH_free(dh); |
199 | 251 | ||
200 | kex_derive_keys(kex, hash, shared_secret); | 252 | kex_derive_keys(kex, hash, hashlen, shared_secret); |
201 | BN_clear_free(shared_secret); | 253 | BN_clear_free(shared_secret); |
202 | kex_finish(kex); | 254 | kex_finish(kex); |
203 | } | 255 | } |