xref: /freebsd/crypto/heimdal/lib/gssapi/ntlm/crypto.c (revision c6879c6c14eedbd060ba588a3129a6c60ebbe783)
1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov  * Copyright (c) 2006 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34ae771770SStanislav Sedov #include "ntlm.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson uint32_t
37c19800e8SDoug Rabson _krb5_crc_update (const char *p, size_t len, uint32_t res);
38c19800e8SDoug Rabson void
39c19800e8SDoug Rabson _krb5_crc_init_table(void);
40c19800e8SDoug Rabson 
41c19800e8SDoug Rabson /*
42c19800e8SDoug Rabson  *
43c19800e8SDoug Rabson  */
44c19800e8SDoug Rabson 
45c19800e8SDoug Rabson static void
encode_le_uint32(uint32_t n,unsigned char * p)46c19800e8SDoug Rabson encode_le_uint32(uint32_t n, unsigned char *p)
47c19800e8SDoug Rabson {
48c19800e8SDoug Rabson   p[0] = (n >> 0)  & 0xFF;
49c19800e8SDoug Rabson   p[1] = (n >> 8)  & 0xFF;
50c19800e8SDoug Rabson   p[2] = (n >> 16) & 0xFF;
51c19800e8SDoug Rabson   p[3] = (n >> 24) & 0xFF;
52c19800e8SDoug Rabson }
53c19800e8SDoug Rabson 
54c19800e8SDoug Rabson 
55c19800e8SDoug Rabson static void
decode_le_uint32(const void * ptr,uint32_t * n)56c19800e8SDoug Rabson decode_le_uint32(const void *ptr, uint32_t *n)
57c19800e8SDoug Rabson {
58c19800e8SDoug Rabson     const unsigned char *p = ptr;
59c19800e8SDoug Rabson     *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
60c19800e8SDoug Rabson }
61c19800e8SDoug Rabson 
62c19800e8SDoug Rabson /*
63c19800e8SDoug Rabson  *
64c19800e8SDoug Rabson  */
65c19800e8SDoug Rabson 
66c19800e8SDoug Rabson const char a2i_signmagic[] =
67c19800e8SDoug Rabson     "session key to server-to-client signing key magic constant";
68c19800e8SDoug Rabson const char a2i_sealmagic[] =
69c19800e8SDoug Rabson     "session key to server-to-client sealing key magic constant";
70c19800e8SDoug Rabson const char i2a_signmagic[] =
71c19800e8SDoug Rabson     "session key to client-to-server signing key magic constant";
72c19800e8SDoug Rabson const char i2a_sealmagic[] =
73c19800e8SDoug Rabson     "session key to client-to-server sealing key magic constant";
74c19800e8SDoug Rabson 
75c19800e8SDoug Rabson 
76c19800e8SDoug Rabson void
_gss_ntlm_set_key(struct ntlmv2_key * key,int acceptor,int sealsign,unsigned char * data,size_t len)77c19800e8SDoug Rabson _gss_ntlm_set_key(struct ntlmv2_key *key, int acceptor, int sealsign,
78c19800e8SDoug Rabson 		  unsigned char *data, size_t len)
79c19800e8SDoug Rabson {
80c19800e8SDoug Rabson     unsigned char out[16];
81ae771770SStanislav Sedov     EVP_MD_CTX *ctx;
82c19800e8SDoug Rabson     const char *signmagic;
83c19800e8SDoug Rabson     const char *sealmagic;
84c19800e8SDoug Rabson 
85c19800e8SDoug Rabson     if (acceptor) {
86c19800e8SDoug Rabson 	signmagic = a2i_signmagic;
87c19800e8SDoug Rabson 	sealmagic = a2i_sealmagic;
88c19800e8SDoug Rabson     } else {
89c19800e8SDoug Rabson 	signmagic = i2a_signmagic;
90c19800e8SDoug Rabson 	sealmagic = i2a_sealmagic;
91c19800e8SDoug Rabson     }
92c19800e8SDoug Rabson 
93c19800e8SDoug Rabson     key->seq = 0;
94c19800e8SDoug Rabson 
95ae771770SStanislav Sedov     ctx = EVP_MD_CTX_create();
96ae771770SStanislav Sedov     EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
97ae771770SStanislav Sedov     EVP_DigestUpdate(ctx, data, len);
98ae771770SStanislav Sedov     EVP_DigestUpdate(ctx, signmagic, strlen(signmagic) + 1);
99ae771770SStanislav Sedov     EVP_DigestFinal_ex(ctx, key->signkey, NULL);
100c19800e8SDoug Rabson 
101ae771770SStanislav Sedov     EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
102ae771770SStanislav Sedov     EVP_DigestUpdate(ctx, data, len);
103ae771770SStanislav Sedov     EVP_DigestUpdate(ctx, sealmagic, strlen(sealmagic) + 1);
104ae771770SStanislav Sedov     EVP_DigestFinal_ex(ctx, out, NULL);
105ae771770SStanislav Sedov     EVP_MD_CTX_destroy(ctx);
106c19800e8SDoug Rabson 
107c19800e8SDoug Rabson     RC4_set_key(&key->sealkey, 16, out);
108c19800e8SDoug Rabson     if (sealsign)
109c19800e8SDoug Rabson 	key->signsealkey = &key->sealkey;
110c19800e8SDoug Rabson }
111c19800e8SDoug Rabson 
112c19800e8SDoug Rabson /*
113c19800e8SDoug Rabson  *
114c19800e8SDoug Rabson  */
115c19800e8SDoug Rabson 
116c19800e8SDoug Rabson static OM_uint32
v1_sign_message(gss_buffer_t in,RC4_KEY * signkey,uint32_t seq,unsigned char out[16])117c19800e8SDoug Rabson v1_sign_message(gss_buffer_t in,
118c19800e8SDoug Rabson 		RC4_KEY *signkey,
119c19800e8SDoug Rabson 		uint32_t seq,
120c19800e8SDoug Rabson 		unsigned char out[16])
121c19800e8SDoug Rabson {
122c19800e8SDoug Rabson     unsigned char sigature[12];
123c19800e8SDoug Rabson     uint32_t crc;
124c19800e8SDoug Rabson 
125c19800e8SDoug Rabson     _krb5_crc_init_table();
126c19800e8SDoug Rabson     crc = _krb5_crc_update(in->value, in->length, 0);
127c19800e8SDoug Rabson 
128c19800e8SDoug Rabson     encode_le_uint32(0, &sigature[0]);
129c19800e8SDoug Rabson     encode_le_uint32(crc, &sigature[4]);
130c19800e8SDoug Rabson     encode_le_uint32(seq, &sigature[8]);
131c19800e8SDoug Rabson 
132c19800e8SDoug Rabson     encode_le_uint32(1, out); /* version */
133c19800e8SDoug Rabson     RC4(signkey, sizeof(sigature), sigature, out + 4);
134c19800e8SDoug Rabson 
135c19800e8SDoug Rabson     if (RAND_bytes(out + 4, 4) != 1)
136c19800e8SDoug Rabson 	return GSS_S_UNAVAILABLE;
137c19800e8SDoug Rabson 
138c19800e8SDoug Rabson     return 0;
139c19800e8SDoug Rabson }
140c19800e8SDoug Rabson 
141c19800e8SDoug Rabson 
142c19800e8SDoug Rabson static OM_uint32
v2_sign_message(gss_buffer_t in,unsigned char signkey[16],RC4_KEY * sealkey,uint32_t seq,unsigned char out[16])143c19800e8SDoug Rabson v2_sign_message(gss_buffer_t in,
144c19800e8SDoug Rabson 		unsigned char signkey[16],
145c19800e8SDoug Rabson 		RC4_KEY *sealkey,
146c19800e8SDoug Rabson 		uint32_t seq,
147c19800e8SDoug Rabson 		unsigned char out[16])
148c19800e8SDoug Rabson {
149c19800e8SDoug Rabson     unsigned char hmac[16];
150c19800e8SDoug Rabson     unsigned int hmaclen;
151*e4456411SJohn Baldwin     HMAC_CTX *c;
152c19800e8SDoug Rabson 
153*e4456411SJohn Baldwin     c = HMAC_CTX_new();
154*e4456411SJohn Baldwin     if (c == NULL)
155*e4456411SJohn Baldwin 	return GSS_S_FAILURE;
156*e4456411SJohn Baldwin     HMAC_Init_ex(c, signkey, 16, EVP_md5(), NULL);
157c19800e8SDoug Rabson 
158c19800e8SDoug Rabson     encode_le_uint32(seq, hmac);
159*e4456411SJohn Baldwin     HMAC_Update(c, hmac, 4);
160*e4456411SJohn Baldwin     HMAC_Update(c, in->value, in->length);
161*e4456411SJohn Baldwin     HMAC_Final(c, hmac, &hmaclen);
162*e4456411SJohn Baldwin     HMAC_CTX_free(c);
163c19800e8SDoug Rabson 
164c19800e8SDoug Rabson     encode_le_uint32(1, &out[0]);
165c19800e8SDoug Rabson     if (sealkey)
166c19800e8SDoug Rabson 	RC4(sealkey, 8, hmac, &out[4]);
167c19800e8SDoug Rabson     else
168c19800e8SDoug Rabson 	memcpy(&out[4], hmac, 8);
169c19800e8SDoug Rabson 
170c19800e8SDoug Rabson     memset(&out[12], 0, 4);
171c19800e8SDoug Rabson 
172c19800e8SDoug Rabson     return GSS_S_COMPLETE;
173c19800e8SDoug Rabson }
174c19800e8SDoug Rabson 
175c19800e8SDoug Rabson static OM_uint32
v2_verify_message(gss_buffer_t in,unsigned char signkey[16],RC4_KEY * sealkey,uint32_t seq,const unsigned char checksum[16])176c19800e8SDoug Rabson v2_verify_message(gss_buffer_t in,
177c19800e8SDoug Rabson 		  unsigned char signkey[16],
178c19800e8SDoug Rabson 		  RC4_KEY *sealkey,
179c19800e8SDoug Rabson 		  uint32_t seq,
180c19800e8SDoug Rabson 		  const unsigned char checksum[16])
181c19800e8SDoug Rabson {
182c19800e8SDoug Rabson     OM_uint32 ret;
183c19800e8SDoug Rabson     unsigned char out[16];
184c19800e8SDoug Rabson 
185c19800e8SDoug Rabson     ret = v2_sign_message(in, signkey, sealkey, seq, out);
186c19800e8SDoug Rabson     if (ret)
187c19800e8SDoug Rabson 	return ret;
188c19800e8SDoug Rabson 
189c19800e8SDoug Rabson     if (memcmp(checksum, out, 16) != 0)
190c19800e8SDoug Rabson 	return GSS_S_BAD_MIC;
191c19800e8SDoug Rabson 
192c19800e8SDoug Rabson     return GSS_S_COMPLETE;
193c19800e8SDoug Rabson }
194c19800e8SDoug Rabson 
195c19800e8SDoug Rabson static OM_uint32
v2_seal_message(const gss_buffer_t in,unsigned char signkey[16],uint32_t seq,RC4_KEY * sealkey,gss_buffer_t out)196c19800e8SDoug Rabson v2_seal_message(const gss_buffer_t in,
197c19800e8SDoug Rabson 		unsigned char signkey[16],
198c19800e8SDoug Rabson 		uint32_t seq,
199c19800e8SDoug Rabson 		RC4_KEY *sealkey,
200c19800e8SDoug Rabson 		gss_buffer_t out)
201c19800e8SDoug Rabson {
202c19800e8SDoug Rabson     unsigned char *p;
203c19800e8SDoug Rabson     OM_uint32 ret;
204c19800e8SDoug Rabson 
205c19800e8SDoug Rabson     if (in->length + 16 < in->length)
206c19800e8SDoug Rabson 	return EINVAL;
207c19800e8SDoug Rabson 
208c19800e8SDoug Rabson     p = malloc(in->length + 16);
209c19800e8SDoug Rabson     if (p == NULL)
210c19800e8SDoug Rabson 	return ENOMEM;
211c19800e8SDoug Rabson 
212c19800e8SDoug Rabson     RC4(sealkey, in->length, in->value, p);
213c19800e8SDoug Rabson 
214c19800e8SDoug Rabson     ret = v2_sign_message(in, signkey, sealkey, seq, &p[in->length]);
215c19800e8SDoug Rabson     if (ret) {
216c19800e8SDoug Rabson 	free(p);
217c19800e8SDoug Rabson 	return ret;
218c19800e8SDoug Rabson     }
219c19800e8SDoug Rabson 
220c19800e8SDoug Rabson     out->value = p;
221c19800e8SDoug Rabson     out->length = in->length + 16;
222c19800e8SDoug Rabson 
223c19800e8SDoug Rabson     return 0;
224c19800e8SDoug Rabson }
225c19800e8SDoug Rabson 
226c19800e8SDoug Rabson static OM_uint32
v2_unseal_message(gss_buffer_t in,unsigned char signkey[16],uint32_t seq,RC4_KEY * sealkey,gss_buffer_t out)227c19800e8SDoug Rabson v2_unseal_message(gss_buffer_t in,
228c19800e8SDoug Rabson 		  unsigned char signkey[16],
229c19800e8SDoug Rabson 		  uint32_t seq,
230c19800e8SDoug Rabson 		  RC4_KEY *sealkey,
231c19800e8SDoug Rabson 		  gss_buffer_t out)
232c19800e8SDoug Rabson {
233c19800e8SDoug Rabson     OM_uint32 ret;
234c19800e8SDoug Rabson 
235c19800e8SDoug Rabson     if (in->length < 16)
236c19800e8SDoug Rabson 	return GSS_S_BAD_MIC;
237c19800e8SDoug Rabson 
238c19800e8SDoug Rabson     out->length = in->length - 16;
239c19800e8SDoug Rabson     out->value = malloc(out->length);
240c19800e8SDoug Rabson     if (out->value == NULL)
241c19800e8SDoug Rabson 	return GSS_S_BAD_MIC;
242c19800e8SDoug Rabson 
243c19800e8SDoug Rabson     RC4(sealkey, out->length, in->value, out->value);
244c19800e8SDoug Rabson 
245c19800e8SDoug Rabson     ret = v2_verify_message(out, signkey, sealkey, seq,
246c19800e8SDoug Rabson 			    ((const unsigned char *)in->value) + out->length);
247c19800e8SDoug Rabson     if (ret) {
248c19800e8SDoug Rabson 	OM_uint32 junk;
249c19800e8SDoug Rabson 	gss_release_buffer(&junk, out);
250c19800e8SDoug Rabson     }
251c19800e8SDoug Rabson     return ret;
252c19800e8SDoug Rabson }
253c19800e8SDoug Rabson 
254c19800e8SDoug Rabson /*
255c19800e8SDoug Rabson  *
256c19800e8SDoug Rabson  */
257c19800e8SDoug Rabson 
258c19800e8SDoug Rabson #define CTX_FLAGS_ISSET(_ctx,_flags) \
259c19800e8SDoug Rabson     (((_ctx)->flags & (_flags)) == (_flags))
260c19800e8SDoug Rabson 
261c19800e8SDoug Rabson /*
262c19800e8SDoug Rabson  *
263c19800e8SDoug Rabson  */
264c19800e8SDoug Rabson 
265ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_get_mic(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,gss_qop_t qop_req,const gss_buffer_t message_buffer,gss_buffer_t message_token)266ae771770SStanislav Sedov _gss_ntlm_get_mic
267c19800e8SDoug Rabson            (OM_uint32 * minor_status,
268c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
269c19800e8SDoug Rabson             gss_qop_t qop_req,
270c19800e8SDoug Rabson             const gss_buffer_t message_buffer,
271c19800e8SDoug Rabson             gss_buffer_t message_token
272c19800e8SDoug Rabson            )
273c19800e8SDoug Rabson {
274c19800e8SDoug Rabson     ntlm_ctx ctx = (ntlm_ctx)context_handle;
275c19800e8SDoug Rabson     OM_uint32 junk;
276c19800e8SDoug Rabson 
277c19800e8SDoug Rabson     *minor_status = 0;
278c19800e8SDoug Rabson 
279c19800e8SDoug Rabson     message_token->value = malloc(16);
280c19800e8SDoug Rabson     message_token->length = 16;
281c19800e8SDoug Rabson     if (message_token->value == NULL) {
282c19800e8SDoug Rabson 	*minor_status = ENOMEM;
283c19800e8SDoug Rabson 	return GSS_S_FAILURE;
284c19800e8SDoug Rabson     }
285c19800e8SDoug Rabson 
286c19800e8SDoug Rabson     if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
287c19800e8SDoug Rabson 	OM_uint32 ret;
288c19800e8SDoug Rabson 
289c19800e8SDoug Rabson 	if ((ctx->status & STATUS_SESSIONKEY) == 0) {
290c19800e8SDoug Rabson 	    gss_release_buffer(&junk, message_token);
291c19800e8SDoug Rabson 	    return GSS_S_UNAVAILABLE;
292c19800e8SDoug Rabson 	}
293c19800e8SDoug Rabson 
294c19800e8SDoug Rabson 	ret = v2_sign_message(message_buffer,
295c19800e8SDoug Rabson 			      ctx->u.v2.send.signkey,
296c19800e8SDoug Rabson 			      ctx->u.v2.send.signsealkey,
297c19800e8SDoug Rabson 			      ctx->u.v2.send.seq++,
298c19800e8SDoug Rabson 			      message_token->value);
299c19800e8SDoug Rabson 	if (ret)
300c19800e8SDoug Rabson 	    gss_release_buffer(&junk, message_token);
301c19800e8SDoug Rabson         return ret;
302c19800e8SDoug Rabson 
303c19800e8SDoug Rabson     } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
304c19800e8SDoug Rabson 	OM_uint32 ret;
305c19800e8SDoug Rabson 
306c19800e8SDoug Rabson 	if ((ctx->status & STATUS_SESSIONKEY) == 0) {
307c19800e8SDoug Rabson 	    gss_release_buffer(&junk, message_token);
308c19800e8SDoug Rabson 	    return GSS_S_UNAVAILABLE;
309c19800e8SDoug Rabson 	}
310c19800e8SDoug Rabson 
311c19800e8SDoug Rabson 	ret = v1_sign_message(message_buffer,
312c19800e8SDoug Rabson 			      &ctx->u.v1.crypto_send.key,
313c19800e8SDoug Rabson 			      ctx->u.v1.crypto_send.seq++,
314c19800e8SDoug Rabson 			      message_token->value);
315c19800e8SDoug Rabson 	if (ret)
316c19800e8SDoug Rabson 	    gss_release_buffer(&junk, message_token);
317c19800e8SDoug Rabson         return ret;
318c19800e8SDoug Rabson 
319c19800e8SDoug Rabson     } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_ALWAYS_SIGN)) {
320c19800e8SDoug Rabson 	unsigned char *sigature;
321c19800e8SDoug Rabson 
322c19800e8SDoug Rabson 	sigature = message_token->value;
323c19800e8SDoug Rabson 
324c19800e8SDoug Rabson 	encode_le_uint32(1, &sigature[0]); /* version */
325c19800e8SDoug Rabson 	encode_le_uint32(0, &sigature[4]);
326c19800e8SDoug Rabson 	encode_le_uint32(0, &sigature[8]);
327c19800e8SDoug Rabson 	encode_le_uint32(0, &sigature[12]);
328c19800e8SDoug Rabson 
329c19800e8SDoug Rabson         return GSS_S_COMPLETE;
330c19800e8SDoug Rabson     }
331c19800e8SDoug Rabson     gss_release_buffer(&junk, message_token);
332c19800e8SDoug Rabson 
333c19800e8SDoug Rabson     return GSS_S_UNAVAILABLE;
334c19800e8SDoug Rabson }
335c19800e8SDoug Rabson 
336c19800e8SDoug Rabson /*
337c19800e8SDoug Rabson  *
338c19800e8SDoug Rabson  */
339c19800e8SDoug Rabson 
340ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_verify_mic(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)341c19800e8SDoug Rabson _gss_ntlm_verify_mic
342c19800e8SDoug Rabson            (OM_uint32 * minor_status,
343c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
344c19800e8SDoug Rabson             const gss_buffer_t message_buffer,
345c19800e8SDoug Rabson             const gss_buffer_t token_buffer,
346c19800e8SDoug Rabson             gss_qop_t * qop_state
347c19800e8SDoug Rabson 	    )
348c19800e8SDoug Rabson {
349c19800e8SDoug Rabson     ntlm_ctx ctx = (ntlm_ctx)context_handle;
350c19800e8SDoug Rabson 
351c19800e8SDoug Rabson     if (qop_state != NULL)
352c19800e8SDoug Rabson 	*qop_state = GSS_C_QOP_DEFAULT;
353c19800e8SDoug Rabson     *minor_status = 0;
354c19800e8SDoug Rabson 
355c19800e8SDoug Rabson     if (token_buffer->length != 16)
356c19800e8SDoug Rabson 	return GSS_S_BAD_MIC;
357c19800e8SDoug Rabson 
358c19800e8SDoug Rabson     if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
359c19800e8SDoug Rabson 	OM_uint32 ret;
360c19800e8SDoug Rabson 
361c19800e8SDoug Rabson 	if ((ctx->status & STATUS_SESSIONKEY) == 0)
362c19800e8SDoug Rabson 	    return GSS_S_UNAVAILABLE;
363c19800e8SDoug Rabson 
364c19800e8SDoug Rabson 	ret = v2_verify_message(message_buffer,
365c19800e8SDoug Rabson 				ctx->u.v2.recv.signkey,
366c19800e8SDoug Rabson 				ctx->u.v2.recv.signsealkey,
367c19800e8SDoug Rabson 				ctx->u.v2.recv.seq++,
368c19800e8SDoug Rabson 				token_buffer->value);
369c19800e8SDoug Rabson 	if (ret)
370c19800e8SDoug Rabson 	    return ret;
371c19800e8SDoug Rabson 
372c19800e8SDoug Rabson 	return GSS_S_COMPLETE;
373c19800e8SDoug Rabson     } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
374c19800e8SDoug Rabson 
375c19800e8SDoug Rabson 	unsigned char sigature[12];
376c19800e8SDoug Rabson 	uint32_t crc, num;
377c19800e8SDoug Rabson 
378c19800e8SDoug Rabson 	if ((ctx->status & STATUS_SESSIONKEY) == 0)
379c19800e8SDoug Rabson 	    return GSS_S_UNAVAILABLE;
380c19800e8SDoug Rabson 
381c19800e8SDoug Rabson 	decode_le_uint32(token_buffer->value, &num);
382c19800e8SDoug Rabson 	if (num != 1)
383c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
384c19800e8SDoug Rabson 
385c19800e8SDoug Rabson 	RC4(&ctx->u.v1.crypto_recv.key, sizeof(sigature),
386c19800e8SDoug Rabson 	    ((unsigned char *)token_buffer->value) + 4, sigature);
387c19800e8SDoug Rabson 
388c19800e8SDoug Rabson 	_krb5_crc_init_table();
389c19800e8SDoug Rabson 	crc = _krb5_crc_update(message_buffer->value,
390c19800e8SDoug Rabson 			       message_buffer->length, 0);
391c19800e8SDoug Rabson 	/* skip first 4 bytes in the encrypted checksum */
392c19800e8SDoug Rabson 	decode_le_uint32(&sigature[4], &num);
393c19800e8SDoug Rabson 	if (num != crc)
394c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
395c19800e8SDoug Rabson 	decode_le_uint32(&sigature[8], &num);
396c19800e8SDoug Rabson 	if (ctx->u.v1.crypto_recv.seq != num)
397c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
398c19800e8SDoug Rabson 	ctx->u.v1.crypto_recv.seq++;
399c19800e8SDoug Rabson 
400c19800e8SDoug Rabson         return GSS_S_COMPLETE;
401c19800e8SDoug Rabson     } else if (ctx->flags & NTLM_NEG_ALWAYS_SIGN) {
402c19800e8SDoug Rabson 	uint32_t num;
403c19800e8SDoug Rabson 	unsigned char *p;
404c19800e8SDoug Rabson 
405c19800e8SDoug Rabson 	p = (unsigned char*)(token_buffer->value);
406c19800e8SDoug Rabson 
407c19800e8SDoug Rabson 	decode_le_uint32(&p[0], &num); /* version */
408c19800e8SDoug Rabson 	if (num != 1) return GSS_S_BAD_MIC;
409c19800e8SDoug Rabson 	decode_le_uint32(&p[4], &num);
410c19800e8SDoug Rabson 	if (num != 0) return GSS_S_BAD_MIC;
411c19800e8SDoug Rabson 	decode_le_uint32(&p[8], &num);
412c19800e8SDoug Rabson 	if (num != 0) return GSS_S_BAD_MIC;
413c19800e8SDoug Rabson 	decode_le_uint32(&p[12], &num);
414c19800e8SDoug Rabson 	if (num != 0) return GSS_S_BAD_MIC;
415c19800e8SDoug Rabson 
416c19800e8SDoug Rabson         return GSS_S_COMPLETE;
417c19800e8SDoug Rabson     }
418c19800e8SDoug Rabson 
419c19800e8SDoug Rabson     return GSS_S_UNAVAILABLE;
420c19800e8SDoug Rabson }
421c19800e8SDoug Rabson 
422c19800e8SDoug Rabson /*
423c19800e8SDoug Rabson  *
424c19800e8SDoug Rabson  */
425c19800e8SDoug Rabson 
426ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_wrap_size_limit(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)427c19800e8SDoug Rabson _gss_ntlm_wrap_size_limit (
428c19800e8SDoug Rabson             OM_uint32 * minor_status,
429c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
430c19800e8SDoug Rabson             int conf_req_flag,
431c19800e8SDoug Rabson             gss_qop_t qop_req,
432c19800e8SDoug Rabson             OM_uint32 req_output_size,
433c19800e8SDoug Rabson             OM_uint32 * max_input_size
434c19800e8SDoug Rabson            )
435c19800e8SDoug Rabson {
436c19800e8SDoug Rabson     ntlm_ctx ctx = (ntlm_ctx)context_handle;
437c19800e8SDoug Rabson 
438c19800e8SDoug Rabson     *minor_status = 0;
439c19800e8SDoug Rabson 
440c19800e8SDoug Rabson     if(ctx->flags & NTLM_NEG_SEAL) {
441c19800e8SDoug Rabson 
442c19800e8SDoug Rabson 	if (req_output_size < 16)
443c19800e8SDoug Rabson 	    *max_input_size = 0;
444c19800e8SDoug Rabson 	else
445c19800e8SDoug Rabson 	    *max_input_size = req_output_size - 16;
446c19800e8SDoug Rabson 
447c19800e8SDoug Rabson 	return GSS_S_COMPLETE;
448c19800e8SDoug Rabson     }
449c19800e8SDoug Rabson 
450c19800e8SDoug Rabson     return GSS_S_UNAVAILABLE;
451c19800e8SDoug Rabson }
452c19800e8SDoug Rabson 
453c19800e8SDoug Rabson /*
454c19800e8SDoug Rabson  *
455c19800e8SDoug Rabson  */
456c19800e8SDoug Rabson 
457ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_wrap(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)458ae771770SStanislav Sedov _gss_ntlm_wrap
459c19800e8SDoug Rabson (OM_uint32 * minor_status,
460c19800e8SDoug Rabson  const gss_ctx_id_t context_handle,
461c19800e8SDoug Rabson  int conf_req_flag,
462c19800e8SDoug Rabson  gss_qop_t qop_req,
463c19800e8SDoug Rabson  const gss_buffer_t input_message_buffer,
464c19800e8SDoug Rabson  int * conf_state,
465c19800e8SDoug Rabson  gss_buffer_t output_message_buffer
466c19800e8SDoug Rabson     )
467c19800e8SDoug Rabson {
468c19800e8SDoug Rabson     ntlm_ctx ctx = (ntlm_ctx)context_handle;
469c19800e8SDoug Rabson     OM_uint32 ret;
470c19800e8SDoug Rabson 
471c19800e8SDoug Rabson     *minor_status = 0;
472c19800e8SDoug Rabson     if (conf_state)
473c19800e8SDoug Rabson 	*conf_state = 0;
474c19800e8SDoug Rabson     if (output_message_buffer == GSS_C_NO_BUFFER)
475c19800e8SDoug Rabson 	return GSS_S_FAILURE;
476c19800e8SDoug Rabson 
477c19800e8SDoug Rabson 
478c19800e8SDoug Rabson     if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
479c19800e8SDoug Rabson 
480c19800e8SDoug Rabson 	return v2_seal_message(input_message_buffer,
481c19800e8SDoug Rabson 			       ctx->u.v2.send.signkey,
482c19800e8SDoug Rabson 			       ctx->u.v2.send.seq++,
483c19800e8SDoug Rabson 			       &ctx->u.v2.send.sealkey,
484c19800e8SDoug Rabson 			       output_message_buffer);
485c19800e8SDoug Rabson 
486c19800e8SDoug Rabson     } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
487c19800e8SDoug Rabson 	gss_buffer_desc trailer;
488c19800e8SDoug Rabson 	OM_uint32 junk;
489c19800e8SDoug Rabson 
490c19800e8SDoug Rabson 	output_message_buffer->length = input_message_buffer->length + 16;
491c19800e8SDoug Rabson 	output_message_buffer->value = malloc(output_message_buffer->length);
492c19800e8SDoug Rabson 	if (output_message_buffer->value == NULL) {
493c19800e8SDoug Rabson 	    output_message_buffer->length = 0;
494c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
495c19800e8SDoug Rabson 	}
496c19800e8SDoug Rabson 
497c19800e8SDoug Rabson 
498c19800e8SDoug Rabson 	RC4(&ctx->u.v1.crypto_send.key, input_message_buffer->length,
499c19800e8SDoug Rabson 	    input_message_buffer->value, output_message_buffer->value);
500c19800e8SDoug Rabson 
501c19800e8SDoug Rabson 	ret = _gss_ntlm_get_mic(minor_status, context_handle,
502c19800e8SDoug Rabson 				0, input_message_buffer,
503c19800e8SDoug Rabson 				&trailer);
504c19800e8SDoug Rabson 	if (ret) {
505c19800e8SDoug Rabson 	    gss_release_buffer(&junk, output_message_buffer);
506c19800e8SDoug Rabson 	    return ret;
507c19800e8SDoug Rabson 	}
508c19800e8SDoug Rabson 	if (trailer.length != 16) {
509c19800e8SDoug Rabson 	    gss_release_buffer(&junk, output_message_buffer);
510c19800e8SDoug Rabson 	    gss_release_buffer(&junk, &trailer);
511c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
512c19800e8SDoug Rabson 	}
513c19800e8SDoug Rabson 	memcpy(((unsigned char *)output_message_buffer->value) +
514c19800e8SDoug Rabson 	       input_message_buffer->length,
515c19800e8SDoug Rabson 	       trailer.value, trailer.length);
516c19800e8SDoug Rabson 	gss_release_buffer(&junk, &trailer);
517c19800e8SDoug Rabson 
518c19800e8SDoug Rabson 	return GSS_S_COMPLETE;
519c19800e8SDoug Rabson     }
520c19800e8SDoug Rabson 
521c19800e8SDoug Rabson     return GSS_S_UNAVAILABLE;
522c19800e8SDoug Rabson }
523c19800e8SDoug Rabson 
524c19800e8SDoug Rabson /*
525c19800e8SDoug Rabson  *
526c19800e8SDoug Rabson  */
527c19800e8SDoug Rabson 
528ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_unwrap(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)529ae771770SStanislav Sedov _gss_ntlm_unwrap
530c19800e8SDoug Rabson            (OM_uint32 * minor_status,
531c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
532c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
533c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
534c19800e8SDoug Rabson             int * conf_state,
535c19800e8SDoug Rabson             gss_qop_t * qop_state
536c19800e8SDoug Rabson            )
537c19800e8SDoug Rabson {
538c19800e8SDoug Rabson     ntlm_ctx ctx = (ntlm_ctx)context_handle;
539c19800e8SDoug Rabson     OM_uint32 ret;
540c19800e8SDoug Rabson 
541c19800e8SDoug Rabson     *minor_status = 0;
542c19800e8SDoug Rabson     output_message_buffer->value = NULL;
543c19800e8SDoug Rabson     output_message_buffer->length = 0;
544ae771770SStanislav Sedov 
545c19800e8SDoug Rabson     if (conf_state)
546c19800e8SDoug Rabson 	*conf_state = 0;
547c19800e8SDoug Rabson     if (qop_state)
548c19800e8SDoug Rabson 	*qop_state = 0;
549c19800e8SDoug Rabson 
550c19800e8SDoug Rabson     if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
551c19800e8SDoug Rabson 
552c19800e8SDoug Rabson 	return v2_unseal_message(input_message_buffer,
553c19800e8SDoug Rabson 				 ctx->u.v2.recv.signkey,
554c19800e8SDoug Rabson 				 ctx->u.v2.recv.seq++,
555c19800e8SDoug Rabson 				 &ctx->u.v2.recv.sealkey,
556c19800e8SDoug Rabson 				 output_message_buffer);
557c19800e8SDoug Rabson 
558c19800e8SDoug Rabson     } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
559c19800e8SDoug Rabson 
560c19800e8SDoug Rabson 	gss_buffer_desc trailer;
561c19800e8SDoug Rabson 	OM_uint32 junk;
562c19800e8SDoug Rabson 
563c19800e8SDoug Rabson 	if (input_message_buffer->length < 16)
564c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
565c19800e8SDoug Rabson 
566c19800e8SDoug Rabson 	output_message_buffer->length = input_message_buffer->length - 16;
567c19800e8SDoug Rabson 	output_message_buffer->value = malloc(output_message_buffer->length);
568c19800e8SDoug Rabson 	if (output_message_buffer->value == NULL) {
569c19800e8SDoug Rabson 	    output_message_buffer->length = 0;
570c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
571c19800e8SDoug Rabson 	}
572c19800e8SDoug Rabson 
573c19800e8SDoug Rabson 	RC4(&ctx->u.v1.crypto_recv.key, output_message_buffer->length,
574c19800e8SDoug Rabson 	    input_message_buffer->value, output_message_buffer->value);
575c19800e8SDoug Rabson 
576c19800e8SDoug Rabson 	trailer.value = ((unsigned char *)input_message_buffer->value) +
577c19800e8SDoug Rabson 	    output_message_buffer->length;
578c19800e8SDoug Rabson 	trailer.length = 16;
579c19800e8SDoug Rabson 
580c19800e8SDoug Rabson 	ret = _gss_ntlm_verify_mic(minor_status, context_handle,
581c19800e8SDoug Rabson 				   output_message_buffer,
582c19800e8SDoug Rabson 				   &trailer, NULL);
583c19800e8SDoug Rabson 	if (ret) {
584c19800e8SDoug Rabson 	    gss_release_buffer(&junk, output_message_buffer);
585c19800e8SDoug Rabson 	    return ret;
586c19800e8SDoug Rabson 	}
587c19800e8SDoug Rabson 
588c19800e8SDoug Rabson 	return GSS_S_COMPLETE;
589c19800e8SDoug Rabson     }
590c19800e8SDoug Rabson 
591c19800e8SDoug Rabson     return GSS_S_UNAVAILABLE;
592c19800e8SDoug Rabson }
593