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