xref: /freebsd-src/crypto/heimdal/lib/krb5/digest.c (revision c19800e8cd5640693f36f2040db4ab5e8d738146)
1*c19800e8SDoug Rabson /*
2*c19800e8SDoug Rabson  * Copyright (c) 2006 Kungliga Tekniska H�gskolan
3*c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4*c19800e8SDoug Rabson  * All rights reserved.
5*c19800e8SDoug Rabson  *
6*c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7*c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8*c19800e8SDoug Rabson  * are met:
9*c19800e8SDoug Rabson  *
10*c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11*c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12*c19800e8SDoug Rabson  *
13*c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14*c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15*c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16*c19800e8SDoug Rabson  *
17*c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18*c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19*c19800e8SDoug Rabson  *    without specific prior written permission.
20*c19800e8SDoug Rabson  *
21*c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22*c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25*c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*c19800e8SDoug Rabson  * SUCH DAMAGE.
32*c19800e8SDoug Rabson  */
33*c19800e8SDoug Rabson 
34*c19800e8SDoug Rabson #include "krb5_locl.h"
35*c19800e8SDoug Rabson RCSID("$Id: digest.c 22156 2007-12-04 20:02:49Z lha $");
36*c19800e8SDoug Rabson #include "digest_asn1.h"
37*c19800e8SDoug Rabson 
38*c19800e8SDoug Rabson struct krb5_digest_data {
39*c19800e8SDoug Rabson     char *cbtype;
40*c19800e8SDoug Rabson     char *cbbinding;
41*c19800e8SDoug Rabson 
42*c19800e8SDoug Rabson     DigestInit init;
43*c19800e8SDoug Rabson     DigestInitReply initReply;
44*c19800e8SDoug Rabson     DigestRequest request;
45*c19800e8SDoug Rabson     DigestResponse response;
46*c19800e8SDoug Rabson };
47*c19800e8SDoug Rabson 
48*c19800e8SDoug Rabson krb5_error_code
49*c19800e8SDoug Rabson krb5_digest_alloc(krb5_context context, krb5_digest *digest)
50*c19800e8SDoug Rabson {
51*c19800e8SDoug Rabson     krb5_digest d;
52*c19800e8SDoug Rabson 
53*c19800e8SDoug Rabson     d = calloc(1, sizeof(*d));
54*c19800e8SDoug Rabson     if (d == NULL) {
55*c19800e8SDoug Rabson 	*digest = NULL;
56*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
57*c19800e8SDoug Rabson 	return ENOMEM;
58*c19800e8SDoug Rabson     }
59*c19800e8SDoug Rabson     *digest = d;
60*c19800e8SDoug Rabson 
61*c19800e8SDoug Rabson     return 0;
62*c19800e8SDoug Rabson }
63*c19800e8SDoug Rabson 
64*c19800e8SDoug Rabson void
65*c19800e8SDoug Rabson krb5_digest_free(krb5_digest digest)
66*c19800e8SDoug Rabson {
67*c19800e8SDoug Rabson     if (digest == NULL)
68*c19800e8SDoug Rabson 	return;
69*c19800e8SDoug Rabson     free_DigestInit(&digest->init);
70*c19800e8SDoug Rabson     free_DigestInitReply(&digest->initReply);
71*c19800e8SDoug Rabson     free_DigestRequest(&digest->request);
72*c19800e8SDoug Rabson     free_DigestResponse(&digest->response);
73*c19800e8SDoug Rabson     memset(digest, 0, sizeof(*digest));
74*c19800e8SDoug Rabson     free(digest);
75*c19800e8SDoug Rabson     return;
76*c19800e8SDoug Rabson }
77*c19800e8SDoug Rabson 
78*c19800e8SDoug Rabson krb5_error_code
79*c19800e8SDoug Rabson krb5_digest_set_server_cb(krb5_context context,
80*c19800e8SDoug Rabson 			  krb5_digest digest,
81*c19800e8SDoug Rabson 			  const char *type,
82*c19800e8SDoug Rabson 			  const char *binding)
83*c19800e8SDoug Rabson {
84*c19800e8SDoug Rabson     if (digest->init.channel) {
85*c19800e8SDoug Rabson 	krb5_set_error_string(context, "server channel binding already set");
86*c19800e8SDoug Rabson 	return EINVAL;
87*c19800e8SDoug Rabson     }
88*c19800e8SDoug Rabson     digest->init.channel = calloc(1, sizeof(*digest->init.channel));
89*c19800e8SDoug Rabson     if (digest->init.channel == NULL)
90*c19800e8SDoug Rabson 	goto error;
91*c19800e8SDoug Rabson 
92*c19800e8SDoug Rabson     digest->init.channel->cb_type = strdup(type);
93*c19800e8SDoug Rabson     if (digest->init.channel->cb_type == NULL)
94*c19800e8SDoug Rabson 	goto error;
95*c19800e8SDoug Rabson 
96*c19800e8SDoug Rabson     digest->init.channel->cb_binding = strdup(binding);
97*c19800e8SDoug Rabson     if (digest->init.channel->cb_binding == NULL)
98*c19800e8SDoug Rabson 	goto error;
99*c19800e8SDoug Rabson     return 0;
100*c19800e8SDoug Rabson error:
101*c19800e8SDoug Rabson     if (digest->init.channel) {
102*c19800e8SDoug Rabson 	free(digest->init.channel->cb_type);
103*c19800e8SDoug Rabson 	free(digest->init.channel->cb_binding);
104*c19800e8SDoug Rabson 	free(digest->init.channel);
105*c19800e8SDoug Rabson 	digest->init.channel = NULL;
106*c19800e8SDoug Rabson     }
107*c19800e8SDoug Rabson     krb5_set_error_string(context, "out of memory");
108*c19800e8SDoug Rabson     return ENOMEM;
109*c19800e8SDoug Rabson }
110*c19800e8SDoug Rabson 
111*c19800e8SDoug Rabson krb5_error_code
112*c19800e8SDoug Rabson krb5_digest_set_type(krb5_context context,
113*c19800e8SDoug Rabson 		     krb5_digest digest,
114*c19800e8SDoug Rabson 		     const char *type)
115*c19800e8SDoug Rabson {
116*c19800e8SDoug Rabson     if (digest->init.type) {
117*c19800e8SDoug Rabson 	krb5_set_error_string(context, "client type already set");
118*c19800e8SDoug Rabson 	return EINVAL;
119*c19800e8SDoug Rabson     }
120*c19800e8SDoug Rabson     digest->init.type = strdup(type);
121*c19800e8SDoug Rabson     if (digest->init.type == NULL) {
122*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
123*c19800e8SDoug Rabson 	return ENOMEM;
124*c19800e8SDoug Rabson     }
125*c19800e8SDoug Rabson     return 0;
126*c19800e8SDoug Rabson }
127*c19800e8SDoug Rabson 
128*c19800e8SDoug Rabson krb5_error_code
129*c19800e8SDoug Rabson krb5_digest_set_hostname(krb5_context context,
130*c19800e8SDoug Rabson 			 krb5_digest digest,
131*c19800e8SDoug Rabson 			 const char *hostname)
132*c19800e8SDoug Rabson {
133*c19800e8SDoug Rabson     if (digest->init.hostname) {
134*c19800e8SDoug Rabson 	krb5_set_error_string(context, "server hostname already set");
135*c19800e8SDoug Rabson 	return EINVAL;
136*c19800e8SDoug Rabson     }
137*c19800e8SDoug Rabson     digest->init.hostname = malloc(sizeof(*digest->init.hostname));
138*c19800e8SDoug Rabson     if (digest->init.hostname == NULL) {
139*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
140*c19800e8SDoug Rabson 	return ENOMEM;
141*c19800e8SDoug Rabson     }
142*c19800e8SDoug Rabson     *digest->init.hostname = strdup(hostname);
143*c19800e8SDoug Rabson     if (*digest->init.hostname == NULL) {
144*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
145*c19800e8SDoug Rabson 	free(digest->init.hostname);
146*c19800e8SDoug Rabson 	digest->init.hostname = NULL;
147*c19800e8SDoug Rabson 	return ENOMEM;
148*c19800e8SDoug Rabson     }
149*c19800e8SDoug Rabson     return 0;
150*c19800e8SDoug Rabson }
151*c19800e8SDoug Rabson 
152*c19800e8SDoug Rabson const char *
153*c19800e8SDoug Rabson krb5_digest_get_server_nonce(krb5_context context,
154*c19800e8SDoug Rabson 			     krb5_digest digest)
155*c19800e8SDoug Rabson {
156*c19800e8SDoug Rabson     return digest->initReply.nonce;
157*c19800e8SDoug Rabson }
158*c19800e8SDoug Rabson 
159*c19800e8SDoug Rabson krb5_error_code
160*c19800e8SDoug Rabson krb5_digest_set_server_nonce(krb5_context context,
161*c19800e8SDoug Rabson 			     krb5_digest digest,
162*c19800e8SDoug Rabson 			     const char *nonce)
163*c19800e8SDoug Rabson {
164*c19800e8SDoug Rabson     if (digest->request.serverNonce) {
165*c19800e8SDoug Rabson 	krb5_set_error_string(context, "nonce already set");
166*c19800e8SDoug Rabson 	return EINVAL;
167*c19800e8SDoug Rabson     }
168*c19800e8SDoug Rabson     digest->request.serverNonce = strdup(nonce);
169*c19800e8SDoug Rabson     if (digest->request.serverNonce == NULL) {
170*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
171*c19800e8SDoug Rabson 	return ENOMEM;
172*c19800e8SDoug Rabson     }
173*c19800e8SDoug Rabson     return 0;
174*c19800e8SDoug Rabson }
175*c19800e8SDoug Rabson 
176*c19800e8SDoug Rabson const char *
177*c19800e8SDoug Rabson krb5_digest_get_opaque(krb5_context context,
178*c19800e8SDoug Rabson 		       krb5_digest digest)
179*c19800e8SDoug Rabson {
180*c19800e8SDoug Rabson     return digest->initReply.opaque;
181*c19800e8SDoug Rabson }
182*c19800e8SDoug Rabson 
183*c19800e8SDoug Rabson krb5_error_code
184*c19800e8SDoug Rabson krb5_digest_set_opaque(krb5_context context,
185*c19800e8SDoug Rabson 		       krb5_digest digest,
186*c19800e8SDoug Rabson 		       const char *opaque)
187*c19800e8SDoug Rabson {
188*c19800e8SDoug Rabson     if (digest->request.opaque) {
189*c19800e8SDoug Rabson 	krb5_set_error_string(context, "opaque already set");
190*c19800e8SDoug Rabson 	return EINVAL;
191*c19800e8SDoug Rabson     }
192*c19800e8SDoug Rabson     digest->request.opaque = strdup(opaque);
193*c19800e8SDoug Rabson     if (digest->request.opaque == NULL) {
194*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
195*c19800e8SDoug Rabson 	return ENOMEM;
196*c19800e8SDoug Rabson     }
197*c19800e8SDoug Rabson     return 0;
198*c19800e8SDoug Rabson }
199*c19800e8SDoug Rabson 
200*c19800e8SDoug Rabson const char *
201*c19800e8SDoug Rabson krb5_digest_get_identifier(krb5_context context,
202*c19800e8SDoug Rabson 			   krb5_digest digest)
203*c19800e8SDoug Rabson {
204*c19800e8SDoug Rabson     if (digest->initReply.identifier == NULL)
205*c19800e8SDoug Rabson 	return NULL;
206*c19800e8SDoug Rabson     return *digest->initReply.identifier;
207*c19800e8SDoug Rabson }
208*c19800e8SDoug Rabson 
209*c19800e8SDoug Rabson krb5_error_code
210*c19800e8SDoug Rabson krb5_digest_set_identifier(krb5_context context,
211*c19800e8SDoug Rabson 			   krb5_digest digest,
212*c19800e8SDoug Rabson 			   const char *id)
213*c19800e8SDoug Rabson {
214*c19800e8SDoug Rabson     if (digest->request.identifier) {
215*c19800e8SDoug Rabson 	krb5_set_error_string(context, "identifier already set");
216*c19800e8SDoug Rabson 	return EINVAL;
217*c19800e8SDoug Rabson     }
218*c19800e8SDoug Rabson     digest->request.identifier = calloc(1, sizeof(*digest->request.identifier));
219*c19800e8SDoug Rabson     if (digest->request.identifier == NULL) {
220*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
221*c19800e8SDoug Rabson 	return ENOMEM;
222*c19800e8SDoug Rabson     }
223*c19800e8SDoug Rabson     *digest->request.identifier = strdup(id);
224*c19800e8SDoug Rabson     if (*digest->request.identifier == NULL) {
225*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
226*c19800e8SDoug Rabson 	free(digest->request.identifier);
227*c19800e8SDoug Rabson 	digest->request.identifier = NULL;
228*c19800e8SDoug Rabson 	return ENOMEM;
229*c19800e8SDoug Rabson     }
230*c19800e8SDoug Rabson     return 0;
231*c19800e8SDoug Rabson }
232*c19800e8SDoug Rabson 
233*c19800e8SDoug Rabson static krb5_error_code
234*c19800e8SDoug Rabson digest_request(krb5_context context,
235*c19800e8SDoug Rabson 	       krb5_realm realm,
236*c19800e8SDoug Rabson 	       krb5_ccache ccache,
237*c19800e8SDoug Rabson 	       krb5_key_usage usage,
238*c19800e8SDoug Rabson 	       const DigestReqInner *ireq,
239*c19800e8SDoug Rabson 	       DigestRepInner *irep)
240*c19800e8SDoug Rabson {
241*c19800e8SDoug Rabson     DigestREQ req;
242*c19800e8SDoug Rabson     DigestREP rep;
243*c19800e8SDoug Rabson     krb5_error_code ret;
244*c19800e8SDoug Rabson     krb5_data data, data2;
245*c19800e8SDoug Rabson     size_t size;
246*c19800e8SDoug Rabson     krb5_crypto crypto = NULL;
247*c19800e8SDoug Rabson     krb5_auth_context ac = NULL;
248*c19800e8SDoug Rabson     krb5_principal principal = NULL;
249*c19800e8SDoug Rabson     krb5_ccache id = NULL;
250*c19800e8SDoug Rabson     krb5_realm r = NULL;
251*c19800e8SDoug Rabson 
252*c19800e8SDoug Rabson     krb5_data_zero(&data);
253*c19800e8SDoug Rabson     krb5_data_zero(&data2);
254*c19800e8SDoug Rabson     memset(&req, 0, sizeof(req));
255*c19800e8SDoug Rabson     memset(&rep, 0, sizeof(rep));
256*c19800e8SDoug Rabson 
257*c19800e8SDoug Rabson     if (ccache == NULL) {
258*c19800e8SDoug Rabson 	ret = krb5_cc_default(context, &id);
259*c19800e8SDoug Rabson 	if (ret)
260*c19800e8SDoug Rabson 	    goto out;
261*c19800e8SDoug Rabson     } else
262*c19800e8SDoug Rabson 	id = ccache;
263*c19800e8SDoug Rabson 
264*c19800e8SDoug Rabson     if (realm == NULL) {
265*c19800e8SDoug Rabson 	ret = krb5_get_default_realm(context, &r);
266*c19800e8SDoug Rabson 	if (ret)
267*c19800e8SDoug Rabson 	    goto out;
268*c19800e8SDoug Rabson     } else
269*c19800e8SDoug Rabson 	r = realm;
270*c19800e8SDoug Rabson 
271*c19800e8SDoug Rabson     /*
272*c19800e8SDoug Rabson      *
273*c19800e8SDoug Rabson      */
274*c19800e8SDoug Rabson 
275*c19800e8SDoug Rabson     ret = krb5_make_principal(context, &principal,
276*c19800e8SDoug Rabson 			      r, KRB5_DIGEST_NAME, r, NULL);
277*c19800e8SDoug Rabson     if (ret)
278*c19800e8SDoug Rabson 	goto out;
279*c19800e8SDoug Rabson 
280*c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length,
281*c19800e8SDoug Rabson 		       ireq, &size, ret);
282*c19800e8SDoug Rabson     if (ret) {
283*c19800e8SDoug Rabson 	krb5_set_error_string(context,
284*c19800e8SDoug Rabson 			      "Failed to encode digest inner request");
285*c19800e8SDoug Rabson 	goto out;
286*c19800e8SDoug Rabson     }
287*c19800e8SDoug Rabson     if (size != data.length)
288*c19800e8SDoug Rabson 	krb5_abortx(context, "ASN.1 internal encoder error");
289*c19800e8SDoug Rabson 
290*c19800e8SDoug Rabson     ret = krb5_mk_req_exact(context, &ac,
291*c19800e8SDoug Rabson 			    AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED,
292*c19800e8SDoug Rabson 			    principal, NULL, id, &req.apReq);
293*c19800e8SDoug Rabson     if (ret)
294*c19800e8SDoug Rabson 	goto out;
295*c19800e8SDoug Rabson 
296*c19800e8SDoug Rabson     {
297*c19800e8SDoug Rabson 	krb5_keyblock *key;
298*c19800e8SDoug Rabson 
299*c19800e8SDoug Rabson 	ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
300*c19800e8SDoug Rabson 	if (ret)
301*c19800e8SDoug Rabson 	    goto out;
302*c19800e8SDoug Rabson 	if (key == NULL) {
303*c19800e8SDoug Rabson 	    krb5_set_error_string(context, "Digest failed to get local subkey");
304*c19800e8SDoug Rabson 	    ret = EINVAL;
305*c19800e8SDoug Rabson 	    goto out;
306*c19800e8SDoug Rabson 	}
307*c19800e8SDoug Rabson 
308*c19800e8SDoug Rabson 	ret = krb5_crypto_init(context, key, 0, &crypto);
309*c19800e8SDoug Rabson 	krb5_free_keyblock (context, key);
310*c19800e8SDoug Rabson 	if (ret)
311*c19800e8SDoug Rabson 	    goto out;
312*c19800e8SDoug Rabson     }
313*c19800e8SDoug Rabson 
314*c19800e8SDoug Rabson     ret = krb5_encrypt_EncryptedData(context, crypto, usage,
315*c19800e8SDoug Rabson 				     data.data, data.length, 0,
316*c19800e8SDoug Rabson 				     &req.innerReq);
317*c19800e8SDoug Rabson     if (ret)
318*c19800e8SDoug Rabson 	goto out;
319*c19800e8SDoug Rabson 
320*c19800e8SDoug Rabson     krb5_data_free(&data);
321*c19800e8SDoug Rabson 
322*c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length,
323*c19800e8SDoug Rabson 		       &req, &size, ret);
324*c19800e8SDoug Rabson     if (ret) {
325*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to encode DigestREQest");
326*c19800e8SDoug Rabson 	goto out;
327*c19800e8SDoug Rabson     }
328*c19800e8SDoug Rabson     if (size != data.length)
329*c19800e8SDoug Rabson 	krb5_abortx(context, "ASN.1 internal encoder error");
330*c19800e8SDoug Rabson 
331*c19800e8SDoug Rabson     ret = krb5_sendto_kdc(context, &data, &r, &data2);
332*c19800e8SDoug Rabson     if (ret)
333*c19800e8SDoug Rabson 	goto out;
334*c19800e8SDoug Rabson 
335*c19800e8SDoug Rabson     ret = decode_DigestREP(data2.data, data2.length, &rep, NULL);
336*c19800e8SDoug Rabson     if (ret) {
337*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to parse digest response");
338*c19800e8SDoug Rabson 	goto out;
339*c19800e8SDoug Rabson     }
340*c19800e8SDoug Rabson 
341*c19800e8SDoug Rabson     {
342*c19800e8SDoug Rabson 	krb5_ap_rep_enc_part *repl;
343*c19800e8SDoug Rabson 
344*c19800e8SDoug Rabson 	ret = krb5_rd_rep(context, ac, &rep.apRep, &repl);
345*c19800e8SDoug Rabson 	if (ret)
346*c19800e8SDoug Rabson 	    goto out;
347*c19800e8SDoug Rabson 
348*c19800e8SDoug Rabson 	krb5_free_ap_rep_enc_part(context, repl);
349*c19800e8SDoug Rabson     }
350*c19800e8SDoug Rabson     {
351*c19800e8SDoug Rabson 	krb5_keyblock *key;
352*c19800e8SDoug Rabson 
353*c19800e8SDoug Rabson 	ret = krb5_auth_con_getremotesubkey(context, ac, &key);
354*c19800e8SDoug Rabson 	if (ret)
355*c19800e8SDoug Rabson 	    goto out;
356*c19800e8SDoug Rabson 	if (key == NULL) {
357*c19800e8SDoug Rabson 	    ret = EINVAL;
358*c19800e8SDoug Rabson 	    krb5_set_error_string(context,
359*c19800e8SDoug Rabson 				  "Digest reply have no remote subkey");
360*c19800e8SDoug Rabson 	    goto out;
361*c19800e8SDoug Rabson 	}
362*c19800e8SDoug Rabson 
363*c19800e8SDoug Rabson 	krb5_crypto_destroy(context, crypto);
364*c19800e8SDoug Rabson 	ret = krb5_crypto_init(context, key, 0, &crypto);
365*c19800e8SDoug Rabson 	krb5_free_keyblock (context, key);
366*c19800e8SDoug Rabson 	if (ret)
367*c19800e8SDoug Rabson 	    goto out;
368*c19800e8SDoug Rabson     }
369*c19800e8SDoug Rabson 
370*c19800e8SDoug Rabson     krb5_data_free(&data);
371*c19800e8SDoug Rabson     ret = krb5_decrypt_EncryptedData(context, crypto, usage,
372*c19800e8SDoug Rabson 				     &rep.innerRep, &data);
373*c19800e8SDoug Rabson     if (ret)
374*c19800e8SDoug Rabson 	goto out;
375*c19800e8SDoug Rabson 
376*c19800e8SDoug Rabson     ret = decode_DigestRepInner(data.data, data.length, irep, NULL);
377*c19800e8SDoug Rabson     if (ret) {
378*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to decode digest inner reply");
379*c19800e8SDoug Rabson 	goto out;
380*c19800e8SDoug Rabson     }
381*c19800e8SDoug Rabson 
382*c19800e8SDoug Rabson out:
383*c19800e8SDoug Rabson     if (ccache == NULL && id)
384*c19800e8SDoug Rabson 	krb5_cc_close(context, id);
385*c19800e8SDoug Rabson     if (realm == NULL && r)
386*c19800e8SDoug Rabson 	free(r);
387*c19800e8SDoug Rabson     if (crypto)
388*c19800e8SDoug Rabson 	krb5_crypto_destroy(context, crypto);
389*c19800e8SDoug Rabson     if (ac)
390*c19800e8SDoug Rabson 	krb5_auth_con_free(context, ac);
391*c19800e8SDoug Rabson     if (principal)
392*c19800e8SDoug Rabson 	krb5_free_principal(context, principal);
393*c19800e8SDoug Rabson 
394*c19800e8SDoug Rabson     krb5_data_free(&data);
395*c19800e8SDoug Rabson     krb5_data_free(&data2);
396*c19800e8SDoug Rabson 
397*c19800e8SDoug Rabson     free_DigestREQ(&req);
398*c19800e8SDoug Rabson     free_DigestREP(&rep);
399*c19800e8SDoug Rabson 
400*c19800e8SDoug Rabson     return ret;
401*c19800e8SDoug Rabson }
402*c19800e8SDoug Rabson 
403*c19800e8SDoug Rabson krb5_error_code
404*c19800e8SDoug Rabson krb5_digest_init_request(krb5_context context,
405*c19800e8SDoug Rabson 			 krb5_digest digest,
406*c19800e8SDoug Rabson 			 krb5_realm realm,
407*c19800e8SDoug Rabson 			 krb5_ccache ccache)
408*c19800e8SDoug Rabson {
409*c19800e8SDoug Rabson     DigestReqInner ireq;
410*c19800e8SDoug Rabson     DigestRepInner irep;
411*c19800e8SDoug Rabson     krb5_error_code ret;
412*c19800e8SDoug Rabson 
413*c19800e8SDoug Rabson     memset(&ireq, 0, sizeof(ireq));
414*c19800e8SDoug Rabson     memset(&irep, 0, sizeof(irep));
415*c19800e8SDoug Rabson 
416*c19800e8SDoug Rabson     if (digest->init.type == NULL) {
417*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Type missing from init req");
418*c19800e8SDoug Rabson 	return EINVAL;
419*c19800e8SDoug Rabson     }
420*c19800e8SDoug Rabson 
421*c19800e8SDoug Rabson     ireq.element = choice_DigestReqInner_init;
422*c19800e8SDoug Rabson     ireq.u.init = digest->init;
423*c19800e8SDoug Rabson 
424*c19800e8SDoug Rabson     ret = digest_request(context, realm, ccache,
425*c19800e8SDoug Rabson 			 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
426*c19800e8SDoug Rabson     if (ret)
427*c19800e8SDoug Rabson 	goto out;
428*c19800e8SDoug Rabson 
429*c19800e8SDoug Rabson     if (irep.element == choice_DigestRepInner_error) {
430*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Digest init error: %s",
431*c19800e8SDoug Rabson 			      irep.u.error.reason);
432*c19800e8SDoug Rabson 	ret = irep.u.error.code;
433*c19800e8SDoug Rabson 	goto out;
434*c19800e8SDoug Rabson     }
435*c19800e8SDoug Rabson 
436*c19800e8SDoug Rabson     if (irep.element != choice_DigestRepInner_initReply) {
437*c19800e8SDoug Rabson 	krb5_set_error_string(context, "digest reply not an initReply");
438*c19800e8SDoug Rabson 	ret = EINVAL;
439*c19800e8SDoug Rabson 	goto out;
440*c19800e8SDoug Rabson     }
441*c19800e8SDoug Rabson 
442*c19800e8SDoug Rabson     ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply);
443*c19800e8SDoug Rabson     if (ret) {
444*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to copy initReply");
445*c19800e8SDoug Rabson 	goto out;
446*c19800e8SDoug Rabson     }
447*c19800e8SDoug Rabson 
448*c19800e8SDoug Rabson out:
449*c19800e8SDoug Rabson     free_DigestRepInner(&irep);
450*c19800e8SDoug Rabson 
451*c19800e8SDoug Rabson     return ret;
452*c19800e8SDoug Rabson }
453*c19800e8SDoug Rabson 
454*c19800e8SDoug Rabson 
455*c19800e8SDoug Rabson krb5_error_code
456*c19800e8SDoug Rabson krb5_digest_set_client_nonce(krb5_context context,
457*c19800e8SDoug Rabson 			     krb5_digest digest,
458*c19800e8SDoug Rabson 			     const char *nonce)
459*c19800e8SDoug Rabson {
460*c19800e8SDoug Rabson     if (digest->request.clientNonce) {
461*c19800e8SDoug Rabson 	krb5_set_error_string(context, "clientNonce already set");
462*c19800e8SDoug Rabson 	return EINVAL;
463*c19800e8SDoug Rabson     }
464*c19800e8SDoug Rabson     digest->request.clientNonce =
465*c19800e8SDoug Rabson 	calloc(1, sizeof(*digest->request.clientNonce));
466*c19800e8SDoug Rabson     if (digest->request.clientNonce == NULL) {
467*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
468*c19800e8SDoug Rabson 	return ENOMEM;
469*c19800e8SDoug Rabson     }
470*c19800e8SDoug Rabson     *digest->request.clientNonce = strdup(nonce);
471*c19800e8SDoug Rabson     if (*digest->request.clientNonce == NULL) {
472*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
473*c19800e8SDoug Rabson 	free(digest->request.clientNonce);
474*c19800e8SDoug Rabson 	digest->request.clientNonce = NULL;
475*c19800e8SDoug Rabson 	return ENOMEM;
476*c19800e8SDoug Rabson     }
477*c19800e8SDoug Rabson     return 0;
478*c19800e8SDoug Rabson }
479*c19800e8SDoug Rabson 
480*c19800e8SDoug Rabson krb5_error_code
481*c19800e8SDoug Rabson krb5_digest_set_digest(krb5_context context,
482*c19800e8SDoug Rabson 		       krb5_digest digest,
483*c19800e8SDoug Rabson 		       const char *dgst)
484*c19800e8SDoug Rabson {
485*c19800e8SDoug Rabson     if (digest->request.digest) {
486*c19800e8SDoug Rabson 	krb5_set_error_string(context, "digest already set");
487*c19800e8SDoug Rabson 	return EINVAL;
488*c19800e8SDoug Rabson     }
489*c19800e8SDoug Rabson     digest->request.digest = strdup(dgst);
490*c19800e8SDoug Rabson     if (digest->request.digest == NULL) {
491*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
492*c19800e8SDoug Rabson 	return ENOMEM;
493*c19800e8SDoug Rabson     }
494*c19800e8SDoug Rabson     return 0;
495*c19800e8SDoug Rabson }
496*c19800e8SDoug Rabson 
497*c19800e8SDoug Rabson krb5_error_code
498*c19800e8SDoug Rabson krb5_digest_set_username(krb5_context context,
499*c19800e8SDoug Rabson 			 krb5_digest digest,
500*c19800e8SDoug Rabson 			 const char *username)
501*c19800e8SDoug Rabson {
502*c19800e8SDoug Rabson     if (digest->request.username) {
503*c19800e8SDoug Rabson 	krb5_set_error_string(context, "username already set");
504*c19800e8SDoug Rabson 	return EINVAL;
505*c19800e8SDoug Rabson     }
506*c19800e8SDoug Rabson     digest->request.username = strdup(username);
507*c19800e8SDoug Rabson     if (digest->request.username == NULL) {
508*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
509*c19800e8SDoug Rabson 	return ENOMEM;
510*c19800e8SDoug Rabson     }
511*c19800e8SDoug Rabson     return 0;
512*c19800e8SDoug Rabson }
513*c19800e8SDoug Rabson 
514*c19800e8SDoug Rabson krb5_error_code
515*c19800e8SDoug Rabson krb5_digest_set_authid(krb5_context context,
516*c19800e8SDoug Rabson 		       krb5_digest digest,
517*c19800e8SDoug Rabson 		       const char *authid)
518*c19800e8SDoug Rabson {
519*c19800e8SDoug Rabson     if (digest->request.authid) {
520*c19800e8SDoug Rabson 	krb5_set_error_string(context, "authid already set");
521*c19800e8SDoug Rabson 	return EINVAL;
522*c19800e8SDoug Rabson     }
523*c19800e8SDoug Rabson     digest->request.authid = malloc(sizeof(*digest->request.authid));
524*c19800e8SDoug Rabson     if (digest->request.authid == NULL) {
525*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
526*c19800e8SDoug Rabson 	return ENOMEM;
527*c19800e8SDoug Rabson     }
528*c19800e8SDoug Rabson     *digest->request.authid = strdup(authid);
529*c19800e8SDoug Rabson     if (*digest->request.authid == NULL) {
530*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
531*c19800e8SDoug Rabson 	free(digest->request.authid);
532*c19800e8SDoug Rabson 	digest->request.authid = NULL;
533*c19800e8SDoug Rabson 	return ENOMEM;
534*c19800e8SDoug Rabson     }
535*c19800e8SDoug Rabson     return 0;
536*c19800e8SDoug Rabson }
537*c19800e8SDoug Rabson 
538*c19800e8SDoug Rabson krb5_error_code
539*c19800e8SDoug Rabson krb5_digest_set_authentication_user(krb5_context context,
540*c19800e8SDoug Rabson 				    krb5_digest digest,
541*c19800e8SDoug Rabson 				    krb5_principal authentication_user)
542*c19800e8SDoug Rabson {
543*c19800e8SDoug Rabson     krb5_error_code ret;
544*c19800e8SDoug Rabson 
545*c19800e8SDoug Rabson     if (digest->request.authentication_user) {
546*c19800e8SDoug Rabson 	krb5_set_error_string(context, "authentication_user already set");
547*c19800e8SDoug Rabson 	return EINVAL;
548*c19800e8SDoug Rabson     }
549*c19800e8SDoug Rabson     ret = krb5_copy_principal(context,
550*c19800e8SDoug Rabson 			      authentication_user,
551*c19800e8SDoug Rabson 			      &digest->request.authentication_user);
552*c19800e8SDoug Rabson     if (digest->request.authentication_user == NULL) {
553*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
554*c19800e8SDoug Rabson 	return ENOMEM;
555*c19800e8SDoug Rabson     }
556*c19800e8SDoug Rabson     return 0;
557*c19800e8SDoug Rabson }
558*c19800e8SDoug Rabson 
559*c19800e8SDoug Rabson krb5_error_code
560*c19800e8SDoug Rabson krb5_digest_set_realm(krb5_context context,
561*c19800e8SDoug Rabson 		      krb5_digest digest,
562*c19800e8SDoug Rabson 		      const char *realm)
563*c19800e8SDoug Rabson {
564*c19800e8SDoug Rabson     if (digest->request.realm) {
565*c19800e8SDoug Rabson 	krb5_set_error_string(context, "realm already set");
566*c19800e8SDoug Rabson 	return EINVAL;
567*c19800e8SDoug Rabson     }
568*c19800e8SDoug Rabson     digest->request.realm = malloc(sizeof(*digest->request.realm));
569*c19800e8SDoug Rabson     if (digest->request.realm == NULL) {
570*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
571*c19800e8SDoug Rabson 	return ENOMEM;
572*c19800e8SDoug Rabson     }
573*c19800e8SDoug Rabson     *digest->request.realm = strdup(realm);
574*c19800e8SDoug Rabson     if (*digest->request.realm == NULL) {
575*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
576*c19800e8SDoug Rabson 	free(digest->request.realm);
577*c19800e8SDoug Rabson 	digest->request.realm = NULL;
578*c19800e8SDoug Rabson 	return ENOMEM;
579*c19800e8SDoug Rabson     }
580*c19800e8SDoug Rabson     return 0;
581*c19800e8SDoug Rabson }
582*c19800e8SDoug Rabson 
583*c19800e8SDoug Rabson krb5_error_code
584*c19800e8SDoug Rabson krb5_digest_set_method(krb5_context context,
585*c19800e8SDoug Rabson 		       krb5_digest digest,
586*c19800e8SDoug Rabson 		       const char *method)
587*c19800e8SDoug Rabson {
588*c19800e8SDoug Rabson     if (digest->request.method) {
589*c19800e8SDoug Rabson 	krb5_set_error_string(context, "method already set");
590*c19800e8SDoug Rabson 	return EINVAL;
591*c19800e8SDoug Rabson     }
592*c19800e8SDoug Rabson     digest->request.method = malloc(sizeof(*digest->request.method));
593*c19800e8SDoug Rabson     if (digest->request.method == NULL) {
594*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
595*c19800e8SDoug Rabson 	return ENOMEM;
596*c19800e8SDoug Rabson     }
597*c19800e8SDoug Rabson     *digest->request.method = strdup(method);
598*c19800e8SDoug Rabson     if (*digest->request.method == NULL) {
599*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
600*c19800e8SDoug Rabson 	free(digest->request.method);
601*c19800e8SDoug Rabson 	digest->request.method = NULL;
602*c19800e8SDoug Rabson 	return ENOMEM;
603*c19800e8SDoug Rabson     }
604*c19800e8SDoug Rabson     return 0;
605*c19800e8SDoug Rabson }
606*c19800e8SDoug Rabson 
607*c19800e8SDoug Rabson krb5_error_code
608*c19800e8SDoug Rabson krb5_digest_set_uri(krb5_context context,
609*c19800e8SDoug Rabson 		    krb5_digest digest,
610*c19800e8SDoug Rabson 		    const char *uri)
611*c19800e8SDoug Rabson {
612*c19800e8SDoug Rabson     if (digest->request.uri) {
613*c19800e8SDoug Rabson 	krb5_set_error_string(context, "uri already set");
614*c19800e8SDoug Rabson 	return EINVAL;
615*c19800e8SDoug Rabson     }
616*c19800e8SDoug Rabson     digest->request.uri = malloc(sizeof(*digest->request.uri));
617*c19800e8SDoug Rabson     if (digest->request.uri == NULL) {
618*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
619*c19800e8SDoug Rabson 	return ENOMEM;
620*c19800e8SDoug Rabson     }
621*c19800e8SDoug Rabson     *digest->request.uri = strdup(uri);
622*c19800e8SDoug Rabson     if (*digest->request.uri == NULL) {
623*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
624*c19800e8SDoug Rabson 	free(digest->request.uri);
625*c19800e8SDoug Rabson 	digest->request.uri = NULL;
626*c19800e8SDoug Rabson 	return ENOMEM;
627*c19800e8SDoug Rabson     }
628*c19800e8SDoug Rabson     return 0;
629*c19800e8SDoug Rabson }
630*c19800e8SDoug Rabson 
631*c19800e8SDoug Rabson krb5_error_code
632*c19800e8SDoug Rabson krb5_digest_set_nonceCount(krb5_context context,
633*c19800e8SDoug Rabson 			   krb5_digest digest,
634*c19800e8SDoug Rabson 			   const char *nonce_count)
635*c19800e8SDoug Rabson {
636*c19800e8SDoug Rabson     if (digest->request.nonceCount) {
637*c19800e8SDoug Rabson 	krb5_set_error_string(context, "nonceCount already set");
638*c19800e8SDoug Rabson 	return EINVAL;
639*c19800e8SDoug Rabson     }
640*c19800e8SDoug Rabson     digest->request.nonceCount =
641*c19800e8SDoug Rabson 	malloc(sizeof(*digest->request.nonceCount));
642*c19800e8SDoug Rabson     if (digest->request.nonceCount == NULL) {
643*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
644*c19800e8SDoug Rabson 	return ENOMEM;
645*c19800e8SDoug Rabson     }
646*c19800e8SDoug Rabson     *digest->request.nonceCount = strdup(nonce_count);
647*c19800e8SDoug Rabson     if (*digest->request.nonceCount == NULL) {
648*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
649*c19800e8SDoug Rabson 	free(digest->request.nonceCount);
650*c19800e8SDoug Rabson 	digest->request.nonceCount = NULL;
651*c19800e8SDoug Rabson 	return ENOMEM;
652*c19800e8SDoug Rabson     }
653*c19800e8SDoug Rabson     return 0;
654*c19800e8SDoug Rabson }
655*c19800e8SDoug Rabson 
656*c19800e8SDoug Rabson krb5_error_code
657*c19800e8SDoug Rabson krb5_digest_set_qop(krb5_context context,
658*c19800e8SDoug Rabson 		    krb5_digest digest,
659*c19800e8SDoug Rabson 		    const char *qop)
660*c19800e8SDoug Rabson {
661*c19800e8SDoug Rabson     if (digest->request.qop) {
662*c19800e8SDoug Rabson 	krb5_set_error_string(context, "qop already set");
663*c19800e8SDoug Rabson 	return EINVAL;
664*c19800e8SDoug Rabson     }
665*c19800e8SDoug Rabson     digest->request.qop = malloc(sizeof(*digest->request.qop));
666*c19800e8SDoug Rabson     if (digest->request.qop == NULL) {
667*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
668*c19800e8SDoug Rabson 	return ENOMEM;
669*c19800e8SDoug Rabson     }
670*c19800e8SDoug Rabson     *digest->request.qop = strdup(qop);
671*c19800e8SDoug Rabson     if (*digest->request.qop == NULL) {
672*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
673*c19800e8SDoug Rabson 	free(digest->request.qop);
674*c19800e8SDoug Rabson 	digest->request.qop = NULL;
675*c19800e8SDoug Rabson 	return ENOMEM;
676*c19800e8SDoug Rabson     }
677*c19800e8SDoug Rabson     return 0;
678*c19800e8SDoug Rabson }
679*c19800e8SDoug Rabson 
680*c19800e8SDoug Rabson int
681*c19800e8SDoug Rabson krb5_digest_set_responseData(krb5_context context,
682*c19800e8SDoug Rabson 			     krb5_digest digest,
683*c19800e8SDoug Rabson 			     const char *response)
684*c19800e8SDoug Rabson {
685*c19800e8SDoug Rabson     digest->request.responseData = strdup(response);
686*c19800e8SDoug Rabson     if (digest->request.responseData == NULL) {
687*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
688*c19800e8SDoug Rabson 	return ENOMEM;
689*c19800e8SDoug Rabson     }
690*c19800e8SDoug Rabson     return 0;
691*c19800e8SDoug Rabson }
692*c19800e8SDoug Rabson 
693*c19800e8SDoug Rabson krb5_error_code
694*c19800e8SDoug Rabson krb5_digest_request(krb5_context context,
695*c19800e8SDoug Rabson 		    krb5_digest digest,
696*c19800e8SDoug Rabson 		    krb5_realm realm,
697*c19800e8SDoug Rabson 		    krb5_ccache ccache)
698*c19800e8SDoug Rabson {
699*c19800e8SDoug Rabson     DigestReqInner ireq;
700*c19800e8SDoug Rabson     DigestRepInner irep;
701*c19800e8SDoug Rabson     krb5_error_code ret;
702*c19800e8SDoug Rabson 
703*c19800e8SDoug Rabson     memset(&ireq, 0, sizeof(ireq));
704*c19800e8SDoug Rabson     memset(&irep, 0, sizeof(irep));
705*c19800e8SDoug Rabson 
706*c19800e8SDoug Rabson     ireq.element = choice_DigestReqInner_digestRequest;
707*c19800e8SDoug Rabson     ireq.u.digestRequest = digest->request;
708*c19800e8SDoug Rabson 
709*c19800e8SDoug Rabson     if (digest->request.type == NULL) {
710*c19800e8SDoug Rabson 	if (digest->init.type == NULL) {
711*c19800e8SDoug Rabson 	    krb5_set_error_string(context, "Type missing from req");
712*c19800e8SDoug Rabson 	    return EINVAL;
713*c19800e8SDoug Rabson 	}
714*c19800e8SDoug Rabson 	ireq.u.digestRequest.type = digest->init.type;
715*c19800e8SDoug Rabson     }
716*c19800e8SDoug Rabson 
717*c19800e8SDoug Rabson     if (ireq.u.digestRequest.digest == NULL)
718*c19800e8SDoug Rabson 	ireq.u.digestRequest.digest = "md5";
719*c19800e8SDoug Rabson 
720*c19800e8SDoug Rabson     ret = digest_request(context, realm, ccache,
721*c19800e8SDoug Rabson 			 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
722*c19800e8SDoug Rabson     if (ret)
723*c19800e8SDoug Rabson 	return ret;
724*c19800e8SDoug Rabson 
725*c19800e8SDoug Rabson     if (irep.element == choice_DigestRepInner_error) {
726*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Digest response error: %s",
727*c19800e8SDoug Rabson 			      irep.u.error.reason);
728*c19800e8SDoug Rabson 	ret = irep.u.error.code;
729*c19800e8SDoug Rabson 	goto out;
730*c19800e8SDoug Rabson     }
731*c19800e8SDoug Rabson 
732*c19800e8SDoug Rabson     if (irep.element != choice_DigestRepInner_response) {
733*c19800e8SDoug Rabson 	krb5_set_error_string(context, "digest reply not an DigestResponse");
734*c19800e8SDoug Rabson 	ret = EINVAL;
735*c19800e8SDoug Rabson 	goto out;
736*c19800e8SDoug Rabson     }
737*c19800e8SDoug Rabson 
738*c19800e8SDoug Rabson     ret = copy_DigestResponse(&irep.u.response, &digest->response);
739*c19800e8SDoug Rabson     if (ret) {
740*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to copy initReply");
741*c19800e8SDoug Rabson 	goto out;
742*c19800e8SDoug Rabson     }
743*c19800e8SDoug Rabson 
744*c19800e8SDoug Rabson out:
745*c19800e8SDoug Rabson     free_DigestRepInner(&irep);
746*c19800e8SDoug Rabson 
747*c19800e8SDoug Rabson     return ret;
748*c19800e8SDoug Rabson }
749*c19800e8SDoug Rabson 
750*c19800e8SDoug Rabson krb5_boolean
751*c19800e8SDoug Rabson krb5_digest_rep_get_status(krb5_context context,
752*c19800e8SDoug Rabson 			   krb5_digest digest)
753*c19800e8SDoug Rabson {
754*c19800e8SDoug Rabson     return digest->response.success ? TRUE : FALSE;
755*c19800e8SDoug Rabson }
756*c19800e8SDoug Rabson 
757*c19800e8SDoug Rabson const char *
758*c19800e8SDoug Rabson krb5_digest_get_rsp(krb5_context context,
759*c19800e8SDoug Rabson 		    krb5_digest digest)
760*c19800e8SDoug Rabson {
761*c19800e8SDoug Rabson     if (digest->response.rsp == NULL)
762*c19800e8SDoug Rabson 	return NULL;
763*c19800e8SDoug Rabson     return *digest->response.rsp;
764*c19800e8SDoug Rabson }
765*c19800e8SDoug Rabson 
766*c19800e8SDoug Rabson krb5_error_code
767*c19800e8SDoug Rabson krb5_digest_get_tickets(krb5_context context,
768*c19800e8SDoug Rabson 			krb5_digest digest,
769*c19800e8SDoug Rabson 			Ticket **tickets)
770*c19800e8SDoug Rabson {
771*c19800e8SDoug Rabson     *tickets = NULL;
772*c19800e8SDoug Rabson     return 0;
773*c19800e8SDoug Rabson }
774*c19800e8SDoug Rabson 
775*c19800e8SDoug Rabson 
776*c19800e8SDoug Rabson krb5_error_code
777*c19800e8SDoug Rabson krb5_digest_get_client_binding(krb5_context context,
778*c19800e8SDoug Rabson 			       krb5_digest digest,
779*c19800e8SDoug Rabson 			       char **type,
780*c19800e8SDoug Rabson 			       char **binding)
781*c19800e8SDoug Rabson {
782*c19800e8SDoug Rabson     if (digest->response.channel) {
783*c19800e8SDoug Rabson 	*type = strdup(digest->response.channel->cb_type);
784*c19800e8SDoug Rabson 	*binding = strdup(digest->response.channel->cb_binding);
785*c19800e8SDoug Rabson 	if (*type == NULL || *binding == NULL) {
786*c19800e8SDoug Rabson 	    free(*type);
787*c19800e8SDoug Rabson 	    free(*binding);
788*c19800e8SDoug Rabson 	    krb5_set_error_string(context, "out of memory");
789*c19800e8SDoug Rabson 	    return ENOMEM;
790*c19800e8SDoug Rabson 	}
791*c19800e8SDoug Rabson     } else {
792*c19800e8SDoug Rabson 	*type = NULL;
793*c19800e8SDoug Rabson 	*binding = NULL;
794*c19800e8SDoug Rabson     }
795*c19800e8SDoug Rabson     return 0;
796*c19800e8SDoug Rabson }
797*c19800e8SDoug Rabson 
798*c19800e8SDoug Rabson krb5_error_code
799*c19800e8SDoug Rabson krb5_digest_get_session_key(krb5_context context,
800*c19800e8SDoug Rabson 			    krb5_digest digest,
801*c19800e8SDoug Rabson 			    krb5_data *data)
802*c19800e8SDoug Rabson {
803*c19800e8SDoug Rabson     krb5_error_code ret;
804*c19800e8SDoug Rabson 
805*c19800e8SDoug Rabson     krb5_data_zero(data);
806*c19800e8SDoug Rabson     if (digest->response.session_key == NULL)
807*c19800e8SDoug Rabson 	return 0;
808*c19800e8SDoug Rabson     ret = der_copy_octet_string(digest->response.session_key, data);
809*c19800e8SDoug Rabson     if (ret)
810*c19800e8SDoug Rabson 	krb5_clear_error_string(context);
811*c19800e8SDoug Rabson 
812*c19800e8SDoug Rabson     return ret;
813*c19800e8SDoug Rabson }
814*c19800e8SDoug Rabson 
815*c19800e8SDoug Rabson struct krb5_ntlm_data {
816*c19800e8SDoug Rabson     NTLMInit init;
817*c19800e8SDoug Rabson     NTLMInitReply initReply;
818*c19800e8SDoug Rabson     NTLMRequest request;
819*c19800e8SDoug Rabson     NTLMResponse response;
820*c19800e8SDoug Rabson };
821*c19800e8SDoug Rabson 
822*c19800e8SDoug Rabson krb5_error_code
823*c19800e8SDoug Rabson krb5_ntlm_alloc(krb5_context context,
824*c19800e8SDoug Rabson 		krb5_ntlm *ntlm)
825*c19800e8SDoug Rabson {
826*c19800e8SDoug Rabson     *ntlm = calloc(1, sizeof(**ntlm));
827*c19800e8SDoug Rabson     if (*ntlm == NULL) {
828*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
829*c19800e8SDoug Rabson 	return ENOMEM;
830*c19800e8SDoug Rabson     }
831*c19800e8SDoug Rabson     return 0;
832*c19800e8SDoug Rabson }
833*c19800e8SDoug Rabson 
834*c19800e8SDoug Rabson krb5_error_code
835*c19800e8SDoug Rabson krb5_ntlm_free(krb5_context context, krb5_ntlm ntlm)
836*c19800e8SDoug Rabson {
837*c19800e8SDoug Rabson     free_NTLMInit(&ntlm->init);
838*c19800e8SDoug Rabson     free_NTLMInitReply(&ntlm->initReply);
839*c19800e8SDoug Rabson     free_NTLMRequest(&ntlm->request);
840*c19800e8SDoug Rabson     free_NTLMResponse(&ntlm->response);
841*c19800e8SDoug Rabson     memset(ntlm, 0, sizeof(*ntlm));
842*c19800e8SDoug Rabson     free(ntlm);
843*c19800e8SDoug Rabson     return 0;
844*c19800e8SDoug Rabson }
845*c19800e8SDoug Rabson 
846*c19800e8SDoug Rabson 
847*c19800e8SDoug Rabson krb5_error_code
848*c19800e8SDoug Rabson krb5_ntlm_init_request(krb5_context context,
849*c19800e8SDoug Rabson 		       krb5_ntlm ntlm,
850*c19800e8SDoug Rabson 		       krb5_realm realm,
851*c19800e8SDoug Rabson 		       krb5_ccache ccache,
852*c19800e8SDoug Rabson 		       uint32_t flags,
853*c19800e8SDoug Rabson 		       const char *hostname,
854*c19800e8SDoug Rabson 		       const char *domainname)
855*c19800e8SDoug Rabson {
856*c19800e8SDoug Rabson     DigestReqInner ireq;
857*c19800e8SDoug Rabson     DigestRepInner irep;
858*c19800e8SDoug Rabson     krb5_error_code ret;
859*c19800e8SDoug Rabson 
860*c19800e8SDoug Rabson     memset(&ireq, 0, sizeof(ireq));
861*c19800e8SDoug Rabson     memset(&irep, 0, sizeof(irep));
862*c19800e8SDoug Rabson 
863*c19800e8SDoug Rabson     ntlm->init.flags = flags;
864*c19800e8SDoug Rabson     if (hostname) {
865*c19800e8SDoug Rabson 	ALLOC(ntlm->init.hostname, 1);
866*c19800e8SDoug Rabson 	*ntlm->init.hostname = strdup(hostname);
867*c19800e8SDoug Rabson     }
868*c19800e8SDoug Rabson     if (domainname) {
869*c19800e8SDoug Rabson 	ALLOC(ntlm->init.domain, 1);
870*c19800e8SDoug Rabson 	*ntlm->init.domain = strdup(domainname);
871*c19800e8SDoug Rabson     }
872*c19800e8SDoug Rabson 
873*c19800e8SDoug Rabson     ireq.element = choice_DigestReqInner_ntlmInit;
874*c19800e8SDoug Rabson     ireq.u.ntlmInit = ntlm->init;
875*c19800e8SDoug Rabson 
876*c19800e8SDoug Rabson     ret = digest_request(context, realm, ccache,
877*c19800e8SDoug Rabson 			 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
878*c19800e8SDoug Rabson     if (ret)
879*c19800e8SDoug Rabson 	goto out;
880*c19800e8SDoug Rabson 
881*c19800e8SDoug Rabson     if (irep.element == choice_DigestRepInner_error) {
882*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Digest init error: %s",
883*c19800e8SDoug Rabson 			      irep.u.error.reason);
884*c19800e8SDoug Rabson 	ret = irep.u.error.code;
885*c19800e8SDoug Rabson 	goto out;
886*c19800e8SDoug Rabson     }
887*c19800e8SDoug Rabson 
888*c19800e8SDoug Rabson     if (irep.element != choice_DigestRepInner_ntlmInitReply) {
889*c19800e8SDoug Rabson 	krb5_set_error_string(context, "ntlm reply not an initReply");
890*c19800e8SDoug Rabson 	ret = EINVAL;
891*c19800e8SDoug Rabson 	goto out;
892*c19800e8SDoug Rabson     }
893*c19800e8SDoug Rabson 
894*c19800e8SDoug Rabson     ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply);
895*c19800e8SDoug Rabson     if (ret) {
896*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to copy initReply");
897*c19800e8SDoug Rabson 	goto out;
898*c19800e8SDoug Rabson     }
899*c19800e8SDoug Rabson 
900*c19800e8SDoug Rabson out:
901*c19800e8SDoug Rabson     free_DigestRepInner(&irep);
902*c19800e8SDoug Rabson 
903*c19800e8SDoug Rabson     return ret;
904*c19800e8SDoug Rabson }
905*c19800e8SDoug Rabson 
906*c19800e8SDoug Rabson krb5_error_code
907*c19800e8SDoug Rabson krb5_ntlm_init_get_flags(krb5_context context,
908*c19800e8SDoug Rabson 			 krb5_ntlm ntlm,
909*c19800e8SDoug Rabson 			 uint32_t *flags)
910*c19800e8SDoug Rabson {
911*c19800e8SDoug Rabson     *flags = ntlm->initReply.flags;
912*c19800e8SDoug Rabson     return 0;
913*c19800e8SDoug Rabson }
914*c19800e8SDoug Rabson 
915*c19800e8SDoug Rabson krb5_error_code
916*c19800e8SDoug Rabson krb5_ntlm_init_get_challange(krb5_context context,
917*c19800e8SDoug Rabson 			     krb5_ntlm ntlm,
918*c19800e8SDoug Rabson 			     krb5_data *challange)
919*c19800e8SDoug Rabson {
920*c19800e8SDoug Rabson     krb5_error_code ret;
921*c19800e8SDoug Rabson 
922*c19800e8SDoug Rabson     ret = der_copy_octet_string(&ntlm->initReply.challange, challange);
923*c19800e8SDoug Rabson     if (ret)
924*c19800e8SDoug Rabson 	krb5_clear_error_string(context);
925*c19800e8SDoug Rabson 
926*c19800e8SDoug Rabson     return ret;
927*c19800e8SDoug Rabson }
928*c19800e8SDoug Rabson 
929*c19800e8SDoug Rabson krb5_error_code
930*c19800e8SDoug Rabson krb5_ntlm_init_get_opaque(krb5_context context,
931*c19800e8SDoug Rabson 			  krb5_ntlm ntlm,
932*c19800e8SDoug Rabson 			  krb5_data *opaque)
933*c19800e8SDoug Rabson {
934*c19800e8SDoug Rabson     krb5_error_code ret;
935*c19800e8SDoug Rabson 
936*c19800e8SDoug Rabson     ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque);
937*c19800e8SDoug Rabson     if (ret)
938*c19800e8SDoug Rabson 	krb5_clear_error_string(context);
939*c19800e8SDoug Rabson 
940*c19800e8SDoug Rabson     return ret;
941*c19800e8SDoug Rabson }
942*c19800e8SDoug Rabson 
943*c19800e8SDoug Rabson krb5_error_code
944*c19800e8SDoug Rabson krb5_ntlm_init_get_targetname(krb5_context context,
945*c19800e8SDoug Rabson 			      krb5_ntlm ntlm,
946*c19800e8SDoug Rabson 			      char **name)
947*c19800e8SDoug Rabson {
948*c19800e8SDoug Rabson     *name = strdup(ntlm->initReply.targetname);
949*c19800e8SDoug Rabson     if (*name == NULL) {
950*c19800e8SDoug Rabson 	krb5_clear_error_string(context);
951*c19800e8SDoug Rabson 	return ENOMEM;
952*c19800e8SDoug Rabson     }
953*c19800e8SDoug Rabson     return 0;
954*c19800e8SDoug Rabson }
955*c19800e8SDoug Rabson 
956*c19800e8SDoug Rabson krb5_error_code
957*c19800e8SDoug Rabson krb5_ntlm_init_get_targetinfo(krb5_context context,
958*c19800e8SDoug Rabson 			      krb5_ntlm ntlm,
959*c19800e8SDoug Rabson 			      krb5_data *data)
960*c19800e8SDoug Rabson {
961*c19800e8SDoug Rabson     krb5_error_code ret;
962*c19800e8SDoug Rabson 
963*c19800e8SDoug Rabson     if (ntlm->initReply.targetinfo == NULL) {
964*c19800e8SDoug Rabson 	krb5_data_zero(data);
965*c19800e8SDoug Rabson 	return 0;
966*c19800e8SDoug Rabson     }
967*c19800e8SDoug Rabson 
968*c19800e8SDoug Rabson     ret = krb5_data_copy(data,
969*c19800e8SDoug Rabson 			 ntlm->initReply.targetinfo->data,
970*c19800e8SDoug Rabson 			 ntlm->initReply.targetinfo->length);
971*c19800e8SDoug Rabson     if (ret) {
972*c19800e8SDoug Rabson 	krb5_clear_error_string(context);
973*c19800e8SDoug Rabson 	return ret;
974*c19800e8SDoug Rabson     }
975*c19800e8SDoug Rabson     return 0;
976*c19800e8SDoug Rabson }
977*c19800e8SDoug Rabson 
978*c19800e8SDoug Rabson 
979*c19800e8SDoug Rabson krb5_error_code
980*c19800e8SDoug Rabson krb5_ntlm_request(krb5_context context,
981*c19800e8SDoug Rabson 		  krb5_ntlm ntlm,
982*c19800e8SDoug Rabson 		  krb5_realm realm,
983*c19800e8SDoug Rabson 		  krb5_ccache ccache)
984*c19800e8SDoug Rabson {
985*c19800e8SDoug Rabson     DigestReqInner ireq;
986*c19800e8SDoug Rabson     DigestRepInner irep;
987*c19800e8SDoug Rabson     krb5_error_code ret;
988*c19800e8SDoug Rabson 
989*c19800e8SDoug Rabson     memset(&ireq, 0, sizeof(ireq));
990*c19800e8SDoug Rabson     memset(&irep, 0, sizeof(irep));
991*c19800e8SDoug Rabson 
992*c19800e8SDoug Rabson     ireq.element = choice_DigestReqInner_ntlmRequest;
993*c19800e8SDoug Rabson     ireq.u.ntlmRequest = ntlm->request;
994*c19800e8SDoug Rabson 
995*c19800e8SDoug Rabson     ret = digest_request(context, realm, ccache,
996*c19800e8SDoug Rabson 			 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
997*c19800e8SDoug Rabson     if (ret)
998*c19800e8SDoug Rabson 	return ret;
999*c19800e8SDoug Rabson 
1000*c19800e8SDoug Rabson     if (irep.element == choice_DigestRepInner_error) {
1001*c19800e8SDoug Rabson 	krb5_set_error_string(context, "NTLM response error: %s",
1002*c19800e8SDoug Rabson 			      irep.u.error.reason);
1003*c19800e8SDoug Rabson 	ret = irep.u.error.code;
1004*c19800e8SDoug Rabson 	goto out;
1005*c19800e8SDoug Rabson     }
1006*c19800e8SDoug Rabson 
1007*c19800e8SDoug Rabson     if (irep.element != choice_DigestRepInner_ntlmResponse) {
1008*c19800e8SDoug Rabson 	krb5_set_error_string(context, "NTLM reply not an NTLMResponse");
1009*c19800e8SDoug Rabson 	ret = EINVAL;
1010*c19800e8SDoug Rabson 	goto out;
1011*c19800e8SDoug Rabson     }
1012*c19800e8SDoug Rabson 
1013*c19800e8SDoug Rabson     ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response);
1014*c19800e8SDoug Rabson     if (ret) {
1015*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to copy NTLMResponse");
1016*c19800e8SDoug Rabson 	goto out;
1017*c19800e8SDoug Rabson     }
1018*c19800e8SDoug Rabson 
1019*c19800e8SDoug Rabson out:
1020*c19800e8SDoug Rabson     free_DigestRepInner(&irep);
1021*c19800e8SDoug Rabson 
1022*c19800e8SDoug Rabson     return ret;
1023*c19800e8SDoug Rabson }
1024*c19800e8SDoug Rabson 
1025*c19800e8SDoug Rabson krb5_error_code
1026*c19800e8SDoug Rabson krb5_ntlm_req_set_flags(krb5_context context,
1027*c19800e8SDoug Rabson 			krb5_ntlm ntlm,
1028*c19800e8SDoug Rabson 			uint32_t flags)
1029*c19800e8SDoug Rabson {
1030*c19800e8SDoug Rabson     ntlm->request.flags = flags;
1031*c19800e8SDoug Rabson     return 0;
1032*c19800e8SDoug Rabson }
1033*c19800e8SDoug Rabson 
1034*c19800e8SDoug Rabson krb5_error_code
1035*c19800e8SDoug Rabson krb5_ntlm_req_set_username(krb5_context context,
1036*c19800e8SDoug Rabson 			   krb5_ntlm ntlm,
1037*c19800e8SDoug Rabson 			   const char *username)
1038*c19800e8SDoug Rabson {
1039*c19800e8SDoug Rabson     ntlm->request.username = strdup(username);
1040*c19800e8SDoug Rabson     if (ntlm->request.username == NULL) {
1041*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1042*c19800e8SDoug Rabson 	return ENOMEM;
1043*c19800e8SDoug Rabson     }
1044*c19800e8SDoug Rabson     return 0;
1045*c19800e8SDoug Rabson }
1046*c19800e8SDoug Rabson 
1047*c19800e8SDoug Rabson krb5_error_code
1048*c19800e8SDoug Rabson krb5_ntlm_req_set_targetname(krb5_context context,
1049*c19800e8SDoug Rabson 			     krb5_ntlm ntlm,
1050*c19800e8SDoug Rabson 			     const char *targetname)
1051*c19800e8SDoug Rabson {
1052*c19800e8SDoug Rabson     ntlm->request.targetname = strdup(targetname);
1053*c19800e8SDoug Rabson     if (ntlm->request.targetname == NULL) {
1054*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1055*c19800e8SDoug Rabson 	return ENOMEM;
1056*c19800e8SDoug Rabson     }
1057*c19800e8SDoug Rabson     return 0;
1058*c19800e8SDoug Rabson }
1059*c19800e8SDoug Rabson 
1060*c19800e8SDoug Rabson krb5_error_code
1061*c19800e8SDoug Rabson krb5_ntlm_req_set_lm(krb5_context context,
1062*c19800e8SDoug Rabson 		     krb5_ntlm ntlm,
1063*c19800e8SDoug Rabson 		     void *hash, size_t len)
1064*c19800e8SDoug Rabson {
1065*c19800e8SDoug Rabson     ntlm->request.lm.data = malloc(len);
1066*c19800e8SDoug Rabson     if (ntlm->request.lm.data == NULL) {
1067*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1068*c19800e8SDoug Rabson 	return ENOMEM;
1069*c19800e8SDoug Rabson     }
1070*c19800e8SDoug Rabson     ntlm->request.lm.length = len;
1071*c19800e8SDoug Rabson     memcpy(ntlm->request.lm.data, hash, len);
1072*c19800e8SDoug Rabson     return 0;
1073*c19800e8SDoug Rabson }
1074*c19800e8SDoug Rabson 
1075*c19800e8SDoug Rabson krb5_error_code
1076*c19800e8SDoug Rabson krb5_ntlm_req_set_ntlm(krb5_context context,
1077*c19800e8SDoug Rabson 		       krb5_ntlm ntlm,
1078*c19800e8SDoug Rabson 		       void *hash, size_t len)
1079*c19800e8SDoug Rabson {
1080*c19800e8SDoug Rabson     ntlm->request.ntlm.data = malloc(len);
1081*c19800e8SDoug Rabson     if (ntlm->request.ntlm.data == NULL) {
1082*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1083*c19800e8SDoug Rabson 	return ENOMEM;
1084*c19800e8SDoug Rabson     }
1085*c19800e8SDoug Rabson     ntlm->request.ntlm.length = len;
1086*c19800e8SDoug Rabson     memcpy(ntlm->request.ntlm.data, hash, len);
1087*c19800e8SDoug Rabson     return 0;
1088*c19800e8SDoug Rabson }
1089*c19800e8SDoug Rabson 
1090*c19800e8SDoug Rabson krb5_error_code
1091*c19800e8SDoug Rabson krb5_ntlm_req_set_opaque(krb5_context context,
1092*c19800e8SDoug Rabson 			 krb5_ntlm ntlm,
1093*c19800e8SDoug Rabson 			 krb5_data *opaque)
1094*c19800e8SDoug Rabson {
1095*c19800e8SDoug Rabson     ntlm->request.opaque.data = malloc(opaque->length);
1096*c19800e8SDoug Rabson     if (ntlm->request.opaque.data == NULL) {
1097*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1098*c19800e8SDoug Rabson 	return ENOMEM;
1099*c19800e8SDoug Rabson     }
1100*c19800e8SDoug Rabson     ntlm->request.opaque.length = opaque->length;
1101*c19800e8SDoug Rabson     memcpy(ntlm->request.opaque.data, opaque->data, opaque->length);
1102*c19800e8SDoug Rabson     return 0;
1103*c19800e8SDoug Rabson }
1104*c19800e8SDoug Rabson 
1105*c19800e8SDoug Rabson krb5_error_code
1106*c19800e8SDoug Rabson krb5_ntlm_req_set_session(krb5_context context,
1107*c19800e8SDoug Rabson 			  krb5_ntlm ntlm,
1108*c19800e8SDoug Rabson 			  void *sessionkey, size_t length)
1109*c19800e8SDoug Rabson {
1110*c19800e8SDoug Rabson     ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey));
1111*c19800e8SDoug Rabson     if (ntlm->request.sessionkey == NULL) {
1112*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1113*c19800e8SDoug Rabson 	return ENOMEM;
1114*c19800e8SDoug Rabson     }
1115*c19800e8SDoug Rabson     ntlm->request.sessionkey->data = malloc(length);
1116*c19800e8SDoug Rabson     if (ntlm->request.sessionkey->data == NULL) {
1117*c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
1118*c19800e8SDoug Rabson 	return ENOMEM;
1119*c19800e8SDoug Rabson     }
1120*c19800e8SDoug Rabson     memcpy(ntlm->request.sessionkey->data, sessionkey, length);
1121*c19800e8SDoug Rabson     ntlm->request.sessionkey->length = length;
1122*c19800e8SDoug Rabson     return 0;
1123*c19800e8SDoug Rabson }
1124*c19800e8SDoug Rabson 
1125*c19800e8SDoug Rabson krb5_boolean
1126*c19800e8SDoug Rabson krb5_ntlm_rep_get_status(krb5_context context,
1127*c19800e8SDoug Rabson 			 krb5_ntlm ntlm)
1128*c19800e8SDoug Rabson {
1129*c19800e8SDoug Rabson     return ntlm->response.success ? TRUE : FALSE;
1130*c19800e8SDoug Rabson }
1131*c19800e8SDoug Rabson 
1132*c19800e8SDoug Rabson krb5_error_code
1133*c19800e8SDoug Rabson krb5_ntlm_rep_get_sessionkey(krb5_context context,
1134*c19800e8SDoug Rabson 			     krb5_ntlm ntlm,
1135*c19800e8SDoug Rabson 			     krb5_data *data)
1136*c19800e8SDoug Rabson {
1137*c19800e8SDoug Rabson     if (ntlm->response.sessionkey == NULL) {
1138*c19800e8SDoug Rabson 	krb5_set_error_string(context, "no ntlm session key");
1139*c19800e8SDoug Rabson 	return EINVAL;
1140*c19800e8SDoug Rabson     }
1141*c19800e8SDoug Rabson     krb5_clear_error_string(context);
1142*c19800e8SDoug Rabson     return krb5_data_copy(data,
1143*c19800e8SDoug Rabson 			  ntlm->response.sessionkey->data,
1144*c19800e8SDoug Rabson 			  ntlm->response.sessionkey->length);
1145*c19800e8SDoug Rabson }
1146*c19800e8SDoug Rabson 
1147*c19800e8SDoug Rabson /**
1148*c19800e8SDoug Rabson  * Get the supported/allowed mechanism for this principal.
1149*c19800e8SDoug Rabson  *
1150*c19800e8SDoug Rabson  * @param context A Keberos context.
1151*c19800e8SDoug Rabson  * @param realm The realm of the KDC.
1152*c19800e8SDoug Rabson  * @param ccache The credential cache to use when talking to the KDC.
1153*c19800e8SDoug Rabson  * @param flags The supported mechanism.
1154*c19800e8SDoug Rabson  *
1155*c19800e8SDoug Rabson  * @return Return an error code or 0.
1156*c19800e8SDoug Rabson  *
1157*c19800e8SDoug Rabson  * @ingroup krb5_digest
1158*c19800e8SDoug Rabson  */
1159*c19800e8SDoug Rabson 
1160*c19800e8SDoug Rabson krb5_error_code
1161*c19800e8SDoug Rabson krb5_digest_probe(krb5_context context,
1162*c19800e8SDoug Rabson 		  krb5_realm realm,
1163*c19800e8SDoug Rabson 		  krb5_ccache ccache,
1164*c19800e8SDoug Rabson 		  unsigned *flags)
1165*c19800e8SDoug Rabson {
1166*c19800e8SDoug Rabson     DigestReqInner ireq;
1167*c19800e8SDoug Rabson     DigestRepInner irep;
1168*c19800e8SDoug Rabson     krb5_error_code ret;
1169*c19800e8SDoug Rabson 
1170*c19800e8SDoug Rabson     memset(&ireq, 0, sizeof(ireq));
1171*c19800e8SDoug Rabson     memset(&irep, 0, sizeof(irep));
1172*c19800e8SDoug Rabson 
1173*c19800e8SDoug Rabson     ireq.element = choice_DigestReqInner_supportedMechs;
1174*c19800e8SDoug Rabson 
1175*c19800e8SDoug Rabson     ret = digest_request(context, realm, ccache,
1176*c19800e8SDoug Rabson 			 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
1177*c19800e8SDoug Rabson     if (ret)
1178*c19800e8SDoug Rabson 	goto out;
1179*c19800e8SDoug Rabson 
1180*c19800e8SDoug Rabson     if (irep.element == choice_DigestRepInner_error) {
1181*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Digest probe error: %s",
1182*c19800e8SDoug Rabson 			      irep.u.error.reason);
1183*c19800e8SDoug Rabson 	ret = irep.u.error.code;
1184*c19800e8SDoug Rabson 	goto out;
1185*c19800e8SDoug Rabson     }
1186*c19800e8SDoug Rabson 
1187*c19800e8SDoug Rabson     if (irep.element != choice_DigestRepInner_supportedMechs) {
1188*c19800e8SDoug Rabson 	krb5_set_error_string(context, "Digest reply not an probe");
1189*c19800e8SDoug Rabson 	ret = EINVAL;
1190*c19800e8SDoug Rabson 	goto out;
1191*c19800e8SDoug Rabson     }
1192*c19800e8SDoug Rabson 
1193*c19800e8SDoug Rabson     *flags = DigestTypes2int(irep.u.supportedMechs);
1194*c19800e8SDoug Rabson 
1195*c19800e8SDoug Rabson out:
1196*c19800e8SDoug Rabson     free_DigestRepInner(&irep);
1197*c19800e8SDoug Rabson 
1198*c19800e8SDoug Rabson     return ret;
1199*c19800e8SDoug Rabson }
1200