2 * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <krb5_locl.h>
38 static krb5_error_code
39 decrypt_tkt_enc_part (krb5_context context
,
41 EncryptedData
*enc_part
,
42 EncTicketPart
*decr_part
)
49 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
52 ret
= krb5_decrypt_EncryptedData (context
,
57 krb5_crypto_destroy(context
, crypto
);
61 ret
= krb5_decode_EncTicketPart(context
, plain
.data
, plain
.length
,
63 krb5_data_free (&plain
);
67 static krb5_error_code
68 decrypt_authenticator (krb5_context context
,
70 EncryptedData
*enc_part
,
71 Authenticator
*authenticator
,
79 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
82 ret
= krb5_decrypt_EncryptedData (context
,
84 usage
/* KRB5_KU_AP_REQ_AUTH */,
87 /* for backwards compatibility, also try the old usage */
88 if (ret
&& usage
== KRB5_KU_TGS_REQ_AUTH
)
89 ret
= krb5_decrypt_EncryptedData (context
,
94 krb5_crypto_destroy(context
, crypto
);
98 ret
= krb5_decode_Authenticator(context
, plain
.data
, plain
.length
,
100 krb5_data_free (&plain
);
105 krb5_decode_ap_req(krb5_context context
,
106 const krb5_data
*inbuf
,
111 ret
= decode_AP_REQ(inbuf
->data
, inbuf
->length
, ap_req
, &len
);
114 if (ap_req
->pvno
!= 5){
116 krb5_clear_error_string (context
);
117 return KRB5KRB_AP_ERR_BADVERSION
;
119 if (ap_req
->msg_type
!= krb_ap_req
){
121 krb5_clear_error_string (context
);
122 return KRB5KRB_AP_ERR_MSG_TYPE
;
124 if (ap_req
->ticket
.tkt_vno
!= 5){
126 krb5_clear_error_string (context
);
127 return KRB5KRB_AP_ERR_BADVERSION
;
132 static krb5_error_code
133 check_transited(krb5_context context
, Ticket
*ticket
, EncTicketPart
*enc
)
139 if(enc
->transited
.tr_type
!= DOMAIN_X500_COMPRESS
)
140 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
142 if(enc
->transited
.contents
.length
== 0)
145 ret
= krb5_domain_x500_decode(context
, enc
->transited
.contents
,
146 &realms
, &num_realms
,
151 ret
= krb5_check_transited(context
, enc
->crealm
,
153 realms
, num_realms
, NULL
);
159 krb5_decrypt_ticket(krb5_context context
,
167 ret
= decrypt_tkt_enc_part (context
, key
, &ticket
->enc_part
, &t
);
173 time_t start
= t
.authtime
;
175 krb5_timeofday (context
, &now
);
177 start
= *t
.starttime
;
178 if(start
- now
> context
->max_skew
180 && !(flags
& KRB5_VERIFY_AP_REQ_IGNORE_INVALID
))) {
181 free_EncTicketPart(&t
);
182 krb5_clear_error_string (context
);
183 return KRB5KRB_AP_ERR_TKT_NYV
;
185 if(now
- t
.endtime
> context
->max_skew
) {
186 free_EncTicketPart(&t
);
187 krb5_clear_error_string (context
);
188 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
191 if(!t
.flags
.transited_policy_checked
) {
192 ret
= check_transited(context
, ticket
, &t
);
194 free_EncTicketPart(&t
);
203 free_EncTicketPart(&t
);
208 krb5_verify_authenticator_checksum(krb5_context context
,
209 krb5_auth_context ac
,
215 krb5_authenticator authenticator
;
218 ret
= krb5_auth_con_getauthenticator (context
,
223 if(authenticator
->cksum
== NULL
)
225 ret
= krb5_auth_con_getkey(context
, ac
, &key
);
227 krb5_free_authenticator(context
, &authenticator
);
230 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
233 ret
= krb5_verify_checksum (context
,
235 KRB5_KU_AP_REQ_AUTH_CKSUM
,
238 authenticator
->cksum
);
239 krb5_crypto_destroy(context
, crypto
);
241 krb5_free_authenticator(context
, &authenticator
);
242 krb5_free_keyblock(context
, key
);
248 krb5_verify_ap_req(krb5_context context
,
249 krb5_auth_context
*auth_context
,
251 krb5_const_principal server
,
252 krb5_keyblock
*keyblock
,
254 krb5_flags
*ap_req_options
,
255 krb5_ticket
**ticket
)
257 return krb5_verify_ap_req2 (context
,
265 KRB5_KU_AP_REQ_AUTH
);
269 krb5_verify_ap_req2(krb5_context context
,
270 krb5_auth_context
*auth_context
,
272 krb5_const_principal server
,
273 krb5_keyblock
*keyblock
,
275 krb5_flags
*ap_req_options
,
276 krb5_ticket
**ticket
,
277 krb5_key_usage usage
)
280 krb5_auth_context ac
;
283 if (auth_context
&& *auth_context
) {
286 ret
= krb5_auth_con_init (context
, &ac
);
291 if (ap_req
->ap_options
.use_session_key
&& ac
->keyblock
){
292 ret
= krb5_decrypt_ticket(context
, &ap_req
->ticket
,
296 krb5_free_keyblock(context
, ac
->keyblock
);
299 ret
= krb5_decrypt_ticket(context
, &ap_req
->ticket
,
307 principalname2krb5_principal(&t
.server
, ap_req
->ticket
.sname
,
308 ap_req
->ticket
.realm
);
309 principalname2krb5_principal(&t
.client
, t
.ticket
.cname
,
314 krb5_copy_keyblock(context
, &t
.ticket
.key
, &ac
->keyblock
);
316 ret
= decrypt_authenticator (context
,
318 &ap_req
->authenticator
,
325 krb5_principal p1
, p2
;
328 principalname2krb5_principal(&p1
,
329 ac
->authenticator
->cname
,
330 ac
->authenticator
->crealm
);
331 principalname2krb5_principal(&p2
,
334 res
= krb5_principal_compare (context
, p1
, p2
);
335 krb5_free_principal (context
, p1
);
336 krb5_free_principal (context
, p2
);
338 ret
= KRB5KRB_AP_ERR_BADMATCH
;
339 krb5_clear_error_string (context
);
344 /* check addresses */
347 && ac
->remote_address
348 && !krb5_address_search (context
,
351 ret
= KRB5KRB_AP_ERR_BADADDR
;
352 krb5_clear_error_string (context
);
356 if (ac
->authenticator
->seq_number
)
357 krb5_auth_con_setremoteseqnumber(context
, ac
,
358 *ac
->authenticator
->seq_number
);
360 /* XXX - Xor sequence numbers */
362 if (ac
->authenticator
->subkey
) {
363 ret
= krb5_auth_con_setremotesubkey(context
, ac
,
364 ac
->authenticator
->subkey
);
369 if (ap_req_options
) {
371 if (ap_req
->ap_options
.use_session_key
)
372 *ap_req_options
|= AP_OPTS_USE_SESSION_KEY
;
373 if (ap_req
->ap_options
.mutual_required
)
374 *ap_req_options
|= AP_OPTS_MUTUAL_REQUIRED
;
378 *ticket
= malloc(sizeof(**ticket
));
381 krb5_free_ticket (context
, &t
);
383 if (*auth_context
== NULL
)
386 krb5_auth_con_free (context
, ac
);
389 krb5_free_ticket (context
, &t
);
391 if (auth_context
== NULL
|| *auth_context
== NULL
)
392 krb5_auth_con_free (context
, ac
);
398 krb5_rd_req_with_keyblock(krb5_context context
,
399 krb5_auth_context
*auth_context
,
400 const krb5_data
*inbuf
,
401 krb5_const_principal server
,
402 krb5_keyblock
*keyblock
,
403 krb5_flags
*ap_req_options
,
404 krb5_ticket
**ticket
)
409 if (*auth_context
== NULL
) {
410 ret
= krb5_auth_con_init(context
, auth_context
);
415 ret
= krb5_decode_ap_req(context
, inbuf
, &ap_req
);
419 ret
= krb5_verify_ap_req(context
,
428 free_AP_REQ(&ap_req
);
432 static krb5_error_code
433 get_key_from_keytab(krb5_context context
,
434 krb5_auth_context
*auth_context
,
436 krb5_const_principal server
,
438 krb5_keyblock
**out_key
)
440 krb5_keytab_entry entry
;
443 krb5_keytab real_keytab
;
446 krb5_kt_default(context
, &real_keytab
);
448 real_keytab
= keytab
;
450 if (ap_req
->ticket
.enc_part
.kvno
)
451 kvno
= *ap_req
->ticket
.enc_part
.kvno
;
455 ret
= krb5_kt_get_entry (context
,
459 ap_req
->ticket
.enc_part
.etype
,
463 ret
= krb5_copy_keyblock(context
, &entry
.keyblock
, out_key
);
464 krb5_kt_free_entry (context
, &entry
);
467 krb5_kt_close(context
, real_keytab
);
473 krb5_rd_req(krb5_context context
,
474 krb5_auth_context
*auth_context
,
475 const krb5_data
*inbuf
,
476 krb5_const_principal server
,
478 krb5_flags
*ap_req_options
,
479 krb5_ticket
**ticket
)
483 krb5_keyblock
*keyblock
= NULL
;
484 krb5_principal service
= NULL
;
486 if (*auth_context
== NULL
) {
487 ret
= krb5_auth_con_init(context
, auth_context
);
492 ret
= krb5_decode_ap_req(context
, inbuf
, &ap_req
);
497 principalname2krb5_principal(&service
,
499 ap_req
.ticket
.realm
);
502 if (ap_req
.ap_options
.use_session_key
&&
503 (*auth_context
)->keyblock
== NULL
) {
504 krb5_set_error_string(context
, "krb5_rd_req: user to user auth "
505 "without session key given");
506 ret
= KRB5KRB_AP_ERR_NOKEY
;
510 if((*auth_context
)->keyblock
== NULL
){
511 ret
= get_key_from_keytab(context
,
520 ret
= krb5_copy_keyblock(context
,
521 (*auth_context
)->keyblock
,
527 ret
= krb5_verify_ap_req(context
,
537 krb5_free_keyblock(context
, keyblock
);
540 free_AP_REQ(&ap_req
);
542 krb5_free_principal(context
, service
);