2 * Copyright (c) 1997 - 2004 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"
36 #define CHECKED_ALLOC(dst) do { \
37 if ((ALLOC(dst, 1)) == NULL) { \
38 ret = krb5_enomem(context); \
43 #define CHECKED_COPY(cp_func, dst, src) do { \
44 if (cp_func(src, dst)) { \
45 ret = krb5_enomem(context); \
49 #define CHECKED_COPY_PPC2KCI(cp_func, dst, src) \
50 CHECKED_COPY(cp_func, krb_cred_info->dst, &ppcreds[i]->src)
52 #define CHECKED_ALLOC_ASSIGN(dst, src) do { \
53 if ((ALLOC(dst, 1)) == NULL) { \
54 ret = krb5_enomem(context); \
59 #define CHECKED_ALLOC_ASSIGN_PPC2KCI(dst, src) \
60 CHECKED_ALLOC_ASSIGN(krb_cred_info->dst, ppcreds[i]->src)
62 #define CHECKED_ALLOC_COPY(cp_func, dst, src) do { \
63 if ((ALLOC(dst, 1)) == NULL || cp_func(src, dst)) { \
64 ret = krb5_enomem(context); \
68 #define CHECKED_ALLOC_COPY_PPC2KCI(cp_func, dst, src) \
69 CHECKED_ALLOC_COPY(cp_func, krb_cred_info->dst, &ppcreds[i]->src)
72 * Make a KRB-CRED PDU with N credentials.
74 * @param context A kerberos 5 context.
75 * @param auth_context The auth context with the key to encrypt the out_data.
76 * @param ppcreds A null-terminated array of credentials to forward.
77 * @param ppdata The output KRB-CRED (to be freed by caller).
78 * @param replay_data (unused).
80 * @return Return an error code or 0.
82 * @ingroup krb5_credential
86 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
87 krb5_mk_ncred(krb5_context context
, krb5_auth_context auth_context
,
88 krb5_creds
**ppcreds
, krb5_data
**ppdata
,
89 krb5_replay_data
*replay_data
)
94 ret
= _krb5_mk_ncred(context
, auth_context
, ppcreds
, &out_data
,
98 * MIT allocates the return structure for no good reason. We do
99 * likewise as, in this case, incompatibility is the greater evil.
101 *ppdata
= calloc(1, sizeof(**ppdata
));
105 krb5_data_free(&out_data
);
106 ret
= krb5_enomem(context
);
114 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
115 _krb5_mk_ncred(krb5_context context
,
116 krb5_auth_context auth_context
,
117 krb5_creds
**ppcreds
,
119 krb5_replay_data
*replay_data
)
122 EncKrbCredPart enc_krb_cred_part
;
123 KrbCredInfo
*krb_cred_info
;
126 unsigned char *buf
= NULL
;
132 * The ownership of 'buf' is re-assigned to a containing structure
133 * multiple times. We enforce an invariant, either buf is non-zero
134 * and we own it, or buf is zero and it is freed or some structure
135 * owns any storage previously allocated as 'buf'.
137 #define CHOWN_BUF(x, buf) do { (x) = (buf); (buf) = 0; } while (0)
138 #define DISOWN_BUF(buf) do { free(buf); (buf) = 0; } while (0)
140 for (ncreds
= 0; ppcreds
[ncreds
]; ncreds
++)
143 memset (&cred
, 0, sizeof(cred
));
144 memset (&enc_krb_cred_part
, 0, sizeof(enc_krb_cred_part
));
146 cred
.msg_type
= krb_cred
;
147 ALLOC_SEQ(&cred
.tickets
, ncreds
);
148 if (cred
.tickets
.val
== NULL
) {
149 ret
= krb5_enomem(context
);
152 ALLOC_SEQ(&enc_krb_cred_part
.ticket_info
, ncreds
);
153 if (enc_krb_cred_part
.ticket_info
.val
== NULL
) {
154 ret
= krb5_enomem(context
);
158 for (i
= 0; i
< ncreds
; i
++) {
159 ret
= decode_Ticket(ppcreds
[i
]->ticket
.data
,
160 ppcreds
[i
]->ticket
.length
,
161 &cred
.tickets
.val
[i
],
162 &len
);/* don't care about len */
166 /* fill ticket_info.val[i] */
167 krb_cred_info
= &enc_krb_cred_part
.ticket_info
.val
[i
];
169 CHECKED_COPY(copy_EncryptionKey
,
170 &krb_cred_info
->key
, &ppcreds
[i
]->session
);
171 CHECKED_ALLOC_COPY_PPC2KCI(copy_Realm
, prealm
, client
->realm
);
172 CHECKED_ALLOC_COPY_PPC2KCI(copy_PrincipalName
, pname
, client
->name
);
173 CHECKED_ALLOC_ASSIGN_PPC2KCI(flags
, flags
.b
);
174 CHECKED_ALLOC_ASSIGN_PPC2KCI(authtime
, times
.authtime
);
175 CHECKED_ALLOC_ASSIGN_PPC2KCI(starttime
, times
.starttime
);
176 CHECKED_ALLOC_ASSIGN_PPC2KCI(endtime
, times
.endtime
);
177 CHECKED_ALLOC_ASSIGN_PPC2KCI(renew_till
, times
.renew_till
);
178 CHECKED_ALLOC_COPY_PPC2KCI(copy_Realm
, srealm
, server
->realm
);
179 CHECKED_ALLOC_COPY_PPC2KCI(copy_PrincipalName
, sname
, server
->name
);
180 CHECKED_ALLOC_COPY_PPC2KCI(copy_HostAddresses
, caddr
, addresses
);
183 if (auth_context
->flags
& KRB5_AUTH_CONTEXT_DO_TIME
) {
187 krb5_us_timeofday (context
, &sec
, &usec
);
189 CHECKED_ALLOC_ASSIGN(enc_krb_cred_part
.timestamp
, sec
);
190 CHECKED_ALLOC_ASSIGN(enc_krb_cred_part
.usec
, usec
);
192 enc_krb_cred_part
.timestamp
= NULL
;
193 enc_krb_cred_part
.usec
= NULL
;
194 /* XXX Er, shouldn't we set the seq nums?? */
197 /* XXX: Is this needed? */
198 if (auth_context
->local_address
&& auth_context
->local_port
) {
199 ret
= krb5_make_addrport(context
,
200 &enc_krb_cred_part
.s_address
,
201 auth_context
->local_address
,
202 auth_context
->local_port
);
207 /* XXX: Is this needed? */
208 if (auth_context
->remote_address
) {
209 if (auth_context
->remote_port
) {
211 * XXX: Should we be checking "no-addresses" for
212 * the receiving realm?
214 ret
= krb5_make_addrport(context
,
215 &enc_krb_cred_part
.r_address
,
216 auth_context
->remote_address
,
217 auth_context
->remote_port
);
222 * XXX Ugly, make krb5_make_addrport() handle missing port
223 * number (i.e., port == 0), then remove this else.
225 CHECKED_ALLOC(enc_krb_cred_part
.r_address
);
226 ret
= krb5_copy_address(context
, auth_context
->remote_address
,
227 enc_krb_cred_part
.r_address
);
233 /* encode EncKrbCredPart */
234 ASN1_MALLOC_ENCODE(EncKrbCredPart
, buf
, buf_size
,
235 &enc_krb_cred_part
, &len
, ret
);
240 * Some older of the MIT gssapi library used clear-text tickets
241 * (warped inside AP-REQ encryption), use the krb5_auth_context
242 * flag KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED to support those
243 * tickets. The session key is used otherwise to encrypt the
247 if (auth_context
->flags
& KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED
) {
248 cred
.enc_part
.etype
= KRB5_ENCTYPE_NULL
;
249 cred
.enc_part
.kvno
= NULL
;
250 CHOWN_BUF(cred
.enc_part
.cipher
.data
, buf
);
251 cred
.enc_part
.cipher
.length
= buf_size
;
254 * Here older versions then 0.7.2 of Heimdal used the local or
255 * remote subkey. That is wrong, the session key should be
256 * used. Heimdal 0.7.2 and newer have code to try both in the
260 ret
= krb5_crypto_init(context
, auth_context
->keyblock
, 0, &crypto
);
262 ret
= krb5_encrypt_EncryptedData(context
,
272 krb5_crypto_destroy(context
, crypto
);
275 ASN1_MALLOC_ENCODE(KRB_CRED
, buf
, buf_size
, &cred
, &len
, ret
);
279 CHOWN_BUF(out_data
->data
, buf
);
280 out_data
->length
= len
;
284 free_EncKrbCredPart(&enc_krb_cred_part
);
285 free_KRB_CRED(&cred
);
291 * Make a KRB-CRED PDU with 1 credential.
293 * @param context A kerberos 5 context.
294 * @param auth_context The auth context with the key to encrypt the out_data.
295 * @param ppcred A credential to forward.
296 * @param ppdata The output KRB-CRED (to be freed by caller).
297 * @param replay_data (unused).
299 * @return Return an error code or 0.
301 * @ingroup krb5_credential
305 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
306 krb5_mk_1cred(krb5_context context
, krb5_auth_context auth_context
,
307 krb5_creds
*ppcred
, krb5_data
**ppdata
,
308 krb5_replay_data
*replay_data
)
310 krb5_creds
*ppcreds
[2] = { ppcred
, NULL
};
312 return krb5_mk_ncred(context
, auth_context
, ppcreds
, ppdata
, replay_data
);
316 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
317 _krb5_mk_1cred(krb5_context context
, krb5_auth_context auth_context
,
318 krb5_creds
*ppcred
, krb5_data
*ppdata
,
319 krb5_replay_data
*replay_data
)
321 krb5_creds
*ppcreds
[2] = { ppcred
, NULL
};
323 return _krb5_mk_ncred(context
, auth_context
, ppcreds
, ppdata
, replay_data
);