call gssapi_set_username() for keyex method too
[openssh.git] / kexgssc.c
1 /*
2  * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "includes.h"
26
27 #ifdef GSSAPI
28
29 #include "includes.h"
30
31 #include <openssl/crypto.h>
32 #include <openssl/bn.h>
33
34 #include <string.h>
35
36 #include "xmalloc.h"
37 #include "buffer.h"
38 #include "ssh2.h"
39 #include "key.h"
40 #include "cipher.h"
41 #include "kex.h"
42 #include "log.h"
43 #include "packet.h"
44 #include "dh.h"
45
46 #include "ssh-gss.h"
47
48 void
49 kexgss_client(Kex *kex) {
50         gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
51         gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
52         Gssctxt *ctxt;
53         OM_uint32 maj_status, min_status, ret_flags;
54         u_int klen, kout, slen = 0, hashlen, strlen;
55         DH *dh; 
56         BIGNUM *dh_server_pub = NULL;
57         BIGNUM *shared_secret = NULL;
58         BIGNUM *p = NULL;
59         BIGNUM *g = NULL;       
60         u_char *kbuf, *hash;
61         u_char *serverhostkey = NULL;
62         u_char *empty = "";
63         char *msg;
64         char *lang;
65         int type = 0;
66         int first = 1;
67         int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
68
69         /* Initialise our GSSAPI world */       
70         ssh_gssapi_build_ctx(&ctxt);
71         if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) 
72             == GSS_C_NO_OID)
73                 fatal("Couldn't identify host exchange");
74
75         if (ssh_gssapi_import_name(ctxt, kex->gss_host))
76                 fatal("Couldn't import hostname");
77
78         if (kex->gss_client && 
79             ssh_gssapi_client_identity(ctxt, kex->gss_client))
80                 fatal("Couldn't acquire client credentials");
81
82         switch (kex->kex_type) {
83         case KEX_GSS_GRP1_SHA1:
84                 dh = dh_new_group1();
85                 break;
86         case KEX_GSS_GRP14_SHA1:
87                 dh = dh_new_group14();
88                 break;
89         case KEX_GSS_GEX_SHA1:
90                 debug("Doing group exchange\n");
91                 nbits = dh_estimate(kex->we_need * 8);
92                 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
93                 packet_put_int(min);
94                 packet_put_int(nbits);
95                 packet_put_int(max);
96
97                 packet_send();
98
99                 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
100
101                 if ((p = BN_new()) == NULL)
102                         fatal("BN_new() failed");
103                 packet_get_bignum2(p);
104                 if ((g = BN_new()) == NULL)
105                         fatal("BN_new() failed");
106                 packet_get_bignum2(g);
107                 packet_check_eom();
108
109                 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
110                         fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
111                             min, BN_num_bits(p), max);
112
113                 dh = dh_new_group(g, p);
114                 break;
115         default:
116                 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
117         }
118         
119         /* Step 1 - e is dh->pub_key */
120         dh_gen_key(dh, kex->we_need * 8);
121
122         /* This is f, we initialise it now to make life easier */
123         dh_server_pub = BN_new();
124         if (dh_server_pub == NULL)
125                 fatal("dh_server_pub == NULL");
126
127         token_ptr = GSS_C_NO_BUFFER;
128                          
129         do {
130                 debug("Calling gss_init_sec_context");
131                 
132                 maj_status = ssh_gssapi_init_ctx(ctxt,
133                     kex->gss_deleg_creds, token_ptr, &send_tok,
134                     &ret_flags);
135
136                 if (GSS_ERROR(maj_status)) {
137                         if (send_tok.length != 0) {
138                                 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
139                                 packet_put_string(send_tok.value,
140                                     send_tok.length);
141                         }
142                         fatal("gss_init_context failed");
143                 }
144
145                 /* If we've got an old receive buffer get rid of it */
146                 if (token_ptr != GSS_C_NO_BUFFER)
147                         xfree(recv_tok.value);
148
149                 if (maj_status == GSS_S_COMPLETE) {
150                         /* If mutual state flag is not true, kex fails */
151                         if (!(ret_flags & GSS_C_MUTUAL_FLAG))
152                                 fatal("Mutual authentication failed");
153
154                         /* If integ avail flag is not true kex fails */
155                         if (!(ret_flags & GSS_C_INTEG_FLAG))
156                                 fatal("Integrity check failed");
157                 }
158
159                 /* 
160                  * If we have data to send, then the last message that we
161                  * received cannot have been a 'complete'. 
162                  */
163                 if (send_tok.length != 0) {
164                         if (first) {
165                                 packet_start(SSH2_MSG_KEXGSS_INIT);
166                                 packet_put_string(send_tok.value,
167                                     send_tok.length);
168                                 packet_put_bignum2(dh->pub_key);
169                                 first = 0;
170                         } else {
171                                 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
172                                 packet_put_string(send_tok.value,
173                                     send_tok.length);
174                         }
175                         packet_send();
176                         gss_release_buffer(&min_status, &send_tok);
177
178                         /* If we've sent them data, they should reply */
179                         do {    
180                                 type = packet_read();
181                                 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
182                                         debug("Received KEXGSS_HOSTKEY");
183                                         if (serverhostkey)
184                                                 fatal("Server host key received more than once");
185                                         serverhostkey = 
186                                             packet_get_string(&slen);
187                                 }
188                         } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
189
190                         switch (type) {
191                         case SSH2_MSG_KEXGSS_CONTINUE:
192                                 debug("Received GSSAPI_CONTINUE");
193                                 if (maj_status == GSS_S_COMPLETE) 
194                                         fatal("GSSAPI Continue received from server when complete");
195                                 recv_tok.value = packet_get_string(&strlen);
196                                 recv_tok.length = strlen; 
197                                 break;
198                         case SSH2_MSG_KEXGSS_COMPLETE:
199                                 debug("Received GSSAPI_COMPLETE");
200                                 packet_get_bignum2(dh_server_pub);
201                                 msg_tok.value =  packet_get_string(&strlen);
202                                 msg_tok.length = strlen; 
203
204                                 /* Is there a token included? */
205                                 if (packet_get_char()) {
206                                         recv_tok.value=
207                                             packet_get_string(&strlen);
208                                         recv_tok.length = strlen;
209                                         /* If we're already complete - protocol error */
210                                         if (maj_status == GSS_S_COMPLETE)
211                                                 packet_disconnect("Protocol error: received token when complete");
212                                         } else {
213                                                 /* No token included */
214                                                 if (maj_status != GSS_S_COMPLETE)
215                                                         packet_disconnect("Protocol error: did not receive final token");
216                                 }
217                                 break;
218                         case SSH2_MSG_KEXGSS_ERROR:
219                                 debug("Received Error");
220                                 maj_status = packet_get_int();
221                                 min_status = packet_get_int();
222                                 msg = packet_get_string(NULL);
223                                 lang = packet_get_string(NULL);
224                                 fatal("GSSAPI Error: \n%.400s",msg);
225                         default:
226                                 packet_disconnect("Protocol error: didn't expect packet type %d",
227                                 type);
228                         }
229                         token_ptr = &recv_tok;
230                 } else {
231                         /* No data, and not complete */
232                         if (maj_status != GSS_S_COMPLETE)
233                                 fatal("Not complete, and no token output");
234                 }
235         } while (maj_status & GSS_S_CONTINUE_NEEDED);
236
237         /* 
238          * We _must_ have received a COMPLETE message in reply from the 
239          * server, which will have set dh_server_pub and msg_tok 
240          */
241
242         if (type != SSH2_MSG_KEXGSS_COMPLETE)
243                 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
244
245         /* Check f in range [1, p-1] */
246         if (!dh_pub_is_valid(dh, dh_server_pub))
247                 packet_disconnect("bad server public DH value");
248
249         /* compute K=f^x mod p */
250         klen = DH_size(dh);
251         kbuf = xmalloc(klen);
252         kout = DH_compute_key(kbuf, dh_server_pub, dh);
253         if (kout < 0)
254                 fatal("DH_compute_key: failed");
255
256         shared_secret = BN_new();
257         if (shared_secret == NULL)
258                 fatal("kexgss_client: BN_new failed");
259
260         if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
261                 fatal("kexdh_client: BN_bin2bn failed");
262
263         memset(kbuf, 0, klen);
264         xfree(kbuf);
265
266         switch (kex->kex_type) {
267         case KEX_GSS_GRP1_SHA1:
268         case KEX_GSS_GRP14_SHA1:
269                 kex_dh_hash( kex->client_version_string, 
270                     kex->server_version_string,
271                     buffer_ptr(&kex->my), buffer_len(&kex->my),
272                     buffer_ptr(&kex->peer), buffer_len(&kex->peer),
273                     (serverhostkey ? serverhostkey : empty), slen,
274                     dh->pub_key,        /* e */
275                     dh_server_pub,      /* f */
276                     shared_secret,      /* K */
277                     &hash, &hashlen
278                 );
279                 break;
280         case KEX_GSS_GEX_SHA1:
281                 kexgex_hash(
282                     kex->evp_md,
283                     kex->client_version_string,
284                     kex->server_version_string,
285                     buffer_ptr(&kex->my), buffer_len(&kex->my),
286                     buffer_ptr(&kex->peer), buffer_len(&kex->peer),
287                     (serverhostkey ? serverhostkey : empty), slen,
288                     min, nbits, max,
289                     dh->p, dh->g,
290                     dh->pub_key,
291                     dh_server_pub,
292                     shared_secret,
293                     &hash, &hashlen
294                 );
295                 break;
296         default:
297                 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
298         }
299
300         gssbuf.value = hash;
301         gssbuf.length = hashlen;
302
303         /* Verify that the hash matches the MIC we just got. */
304         if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
305                 packet_disconnect("Hash's MIC didn't verify");
306
307         xfree(msg_tok.value);
308
309         DH_free(dh);
310         if (serverhostkey)
311                 xfree(serverhostkey);
312         BN_clear_free(dh_server_pub);
313
314         /* save session id */
315         if (kex->session_id == NULL) {
316                 kex->session_id_len = hashlen;
317                 kex->session_id = xmalloc(kex->session_id_len);
318                 memcpy(kex->session_id, hash, kex->session_id_len);
319         }
320
321         if (kex->gss_deleg_creds)
322                 ssh_gssapi_credentials_updated(ctxt);
323
324         if (gss_kex_context == NULL)
325                 gss_kex_context = ctxt;
326         else
327                 ssh_gssapi_delete_ctx(&ctxt);
328
329         kex_derive_keys(kex, hash, hashlen, shared_secret);
330         BN_clear_free(shared_secret);
331         kex_finish(kex);
332 }
333
334 #endif /* GSSAPI */