1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains source for the ZMakeAuthentication function.
4 * Created by: Robert French
6 * $Id: ZMkAuth.c,v 1.20 2002/11/11 18:28:06 ghudson Exp $
8 * Copyright (c) 1987 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
16 static const char rcsid_ZMakeAuthentication_c[] = "$Id: ZMkAuth.c,v 1.20 2002/11/11 18:28:06 ghudson Exp $";
23 #if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
24 #define krb5_free_data(ctx, dat) free((dat)->data)
27 Code_t ZResetAuthentication () {
31 Code_t ZMakeAuthentication(notice, buffer, buffer_len, len)
32 register ZNotice_t *notice;
44 extern unsigned long des_quad_cksum();
46 result = krb_mk_req(&authent, SERVER_SERVICE,
47 SERVER_INSTANCE, __Zephyr_realm, 0);
48 if (result != MK_AP_OK)
49 return (result+krb_err_base);
50 result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE,
51 __Zephyr_realm, &cred);
52 if (result != KSUCCESS)
53 return (result+krb_err_base);
56 notice->z_authent_len = authent.length;
57 notice->z_ascii_authent = (char *)malloc((unsigned)authent.length*3);
58 /* zero length authent is an error, so malloc(0) is not a problem */
59 if (!notice->z_ascii_authent)
61 if ((result = ZMakeAscii(notice->z_ascii_authent,
64 authent.length)) != ZERR_NONE) {
65 free(notice->z_ascii_authent);
68 result = Z_FormatRawHeader(notice, buffer, buffer_len, len, &cstart,
70 free(notice->z_ascii_authent);
71 notice->z_authent_len = 0;
75 /* Compute a checksum over the header and message. */
76 checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, cred.session);
77 checksum ^= des_quad_cksum(cend, NULL, buffer + *len - cend, 0,
79 checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len,
81 notice->z_checksum = checksum;
82 ZMakeAscii32(cstart, buffer + buffer_len - cstart, checksum);
86 notice->z_checksum = 0;
88 notice->z_authent_len = 0;
89 notice->z_ascii_authent = "";
90 return (Z_FormatRawHeader(notice, buffer, buffer_len, len, NULL, NULL));
94 Code_t ZMakeZcodeAuthentication(notice, buffer, buffer_len, phdr_len)
95 register ZNotice_t *notice;
100 return ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
104 Code_t ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
106 register ZNotice_t *notice;
113 krb5_error_code result;
115 krb5_creds creds_in, *creds;
116 krb5_keyblock *keyblock;
117 krb5_enctype enctype;
118 krb5_cksumtype cksumtype;
119 krb5_auth_context authctx;
122 #if HAVE_KRB5_C_MAKE_CHECKSUM
123 krb5_checksum checksum;
125 krb5_crypto cryptctx;
129 char *svcinst, *x, *y;
130 char *cksum_start, *cstart, *cend, *asn1_data;
131 int plain_len; /* length of part not to be checksummed */
132 int cksum_len; /* length of part to be checksummed (incl cksum) */
133 int cksum0_len; /* length of part before checksum */
134 int cksum1_len; /* length of part after checksum */
135 int i, zcode_len, asn1_len;
137 /* Get a pointer to the default ccache. We don't need to free this. */
138 result = krb5_cc_default(Z_krb5_ctx, &ccache);
142 /* GRRR. There's no allocator or constructor for krb5_creds */
143 /* GRRR. It would be nice if this API were documented at all */
144 memset(&creds_in, 0, sizeof(creds_in));
146 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
148 krb5_cc_close(Z_krb5_ctx, ccache);
152 /* construct the service principal */
153 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
156 SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0);
158 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
159 krb5_cc_close(Z_krb5_ctx, ccache);
162 /* HOLDING: creds_in.server, ccache */
164 /* look up or get the credentials we need */
165 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
167 krb5_cc_close(Z_krb5_ctx, ccache);
168 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
173 /* Figure out what checksum type to use */
174 #if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
175 keyblock = &creds->keyblock;
176 enctype = keyblock->enctype;
178 result = Z_krb5_lookup_cksumtype(enctype, &cksumtype);
180 krb5_free_creds(Z_krb5_ctx, creds);
184 keyblock = &creds->session;
190 result = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype,
193 krb5_free_creds(Z_krb5_ctx, creds);
199 result = Z_krb5_lookup_cksumtype(val[i], &cksumtype);
201 } while (result != 0);
204 krb5_free_creds(Z_krb5_ctx, creds);
212 /* Create the authenticator */
213 result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
215 krb5_free_creds(Z_krb5_ctx, creds);
219 authent = (krb5_data *)malloc(sizeof(krb5_data));
221 /* HOLDING: creds, authctx */
222 result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */,
223 0 /* in_data */, creds, authent);
224 krb5_auth_con_free(Z_krb5_ctx, authctx);
226 krb5_free_creds(Z_krb5_ctx, creds);
229 /* HOLDING: creds, authent */
231 /* Encode the authenticator */
233 notice->z_authent_len = authent->length;
234 zcode_len = authent->length * 2 + 2; /* 2x growth plus Z and null */
235 notice->z_ascii_authent = (char *)malloc(zcode_len);
236 if (!notice->z_ascii_authent) {
237 krb5_free_data(Z_krb5_ctx, authent);
238 krb5_free_creds(Z_krb5_ctx, creds);
241 /* HOLDING: creds, authent, notice->z_ascii_authent */
242 result = ZMakeZcode(notice->z_ascii_authent, zcode_len,
243 authent->data, authent->length);
244 krb5_free_data(Z_krb5_ctx, authent);
246 free(notice->z_ascii_authent);
247 krb5_free_creds(Z_krb5_ctx, creds);
250 /* HOLDING: creds, notice->z_ascii_authent */
252 /* format the notice header, with a zero checksum */
253 result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len,
254 &cksum_start, &cksum_len, &cstart, &cend);
255 free(notice->z_ascii_authent);
256 notice->z_authent_len = 0;
258 krb5_free_creds(Z_krb5_ctx, creds);
263 /* Assemble the things to be checksummed */
264 plain_len = cksum_start - buffer;
265 cksum0_len = cstart - cksum_start;
266 cksum1_len = (cksum_start + cksum_len) - cend;
267 memset(&cksumbuf, 0, sizeof(cksumbuf));
268 cksumbuf.length = cksum0_len + cksum1_len + notice->z_message_len;
269 cksumbuf.data = malloc(cksumbuf.length);
270 if (!cksumbuf.data) {
271 krb5_free_creds(Z_krb5_ctx, creds);
274 /* HOLDING: creds, cksumbuf.data */
275 memcpy(cksumbuf.data, cksum_start, cksum0_len);
276 memcpy(cksumbuf.data + cksum0_len, cend, cksum1_len);
277 memcpy(cksumbuf.data + cksum0_len + cksum1_len,
278 notice->z_message, notice->z_message_len);
280 #if HAVE_KRB5_C_MAKE_CHECKSUM
281 /* Create the checksum -- MIT crypto API */
282 result = krb5_c_make_checksum(Z_krb5_ctx, cksumtype,
283 keyblock, Z_KEYUSAGE_CLT_CKSUM,
284 &cksumbuf, &checksum);
285 krb5_free_creds(Z_krb5_ctx, creds);
290 /* HOLDING: cksumbuf.data, checksum */
292 asn1_data = checksum.contents;
293 asn1_len = checksum.length;
295 /* Create the checksum -- heimdal crypto API */
296 result = krb5_crypto_init(Z_krb5_ctx, keyblock, enctype, &cryptctx);
297 krb5_free_creds(Z_krb5_ctx, creds);
302 /* HOLDING: cksumbuf.data, cryptctx */
303 result = krb5_create_checksum(Z_krb5_ctx, cryptctx,
304 Z_KEYUSAGE_CLT_CKSUM, cksumtype,
305 cksumbuf.data, cksumbuf.length,
307 krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
312 asn1_len = checksum.checksum.length;
313 asn1_data = checksum.checksum.data;
314 /* HOLDING: cksumbuf.data, checksum */
318 * OK.... we can zcode to a space starting at 'cstart',
319 * with a length of buffer_len - (plain_len + cksum_len).
320 * Then we tack on the end part, which is located at
321 * cksumbuf.data + cksum0_len and has length cksum1_len
323 result = ZMakeZcode(cstart, buffer_len - (plain_len + cksum_len),
324 asn1_data, asn1_len);
326 zcode_len = strlen(cstart) + 1;
327 memcpy(cstart + zcode_len, cksumbuf.data + cksum0_len, cksum1_len);
328 *phdr_len -= cksum_len - (cksum0_len + cksum1_len);
329 *phdr_len += zcode_len;
332 /* free stuff up, and then return the result from the last call */
335 #if HAVE_KRB5_C_MAKE_CHECKSUM
336 krb5_free_checksum_contents(Z_krb5_ctx, &checksum);
338 free_Checksum(&checksum);
341 #endif /* HAVE_KRB5 */