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