2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
19 #include "lifetimes.h"
21 #include "rxkad_convert.h"
23 /* This union is used to insure we allocate enough space for a key
24 * schedule even if we are linked against a library that uses OpenSSL's
25 * larger representation. This is necessary so we don't lose if an
26 * application uses both rxkad and openssl.
28 union Key_schedule_safe {
29 DES_key_schedule schedule;
36 } openssl_schedule[16];
39 #define getstr(name,min) \
40 slen = strlen(ticket); \
41 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
42 strcpy (name, ticket); \
46 decode_athena_ticket(char *ticket, int ticketLen, char *name, char *inst,
47 char *realm, afs_int32 * host,
48 struct ktc_encryptionKey *sessionKey, afs_uint32 * start,
51 char *ticketBeg = ticket;
55 unsigned char lifetime;
56 char sname[MAXKTCNAMELEN]; /* these aren't used, */
57 char sinst[MAXKTCNAMELEN]; /* but are in the ticket */
64 memcpy(host, ticket, sizeof(*host));
65 ticket += sizeof(*host);
66 *host = ktohl(flags, *host);
68 memcpy(sessionKey, ticket, sizeof(struct ktc_encryptionKey));
69 ticket += sizeof(struct ktc_encryptionKey);
72 memcpy(start, ticket, sizeof(*start));
73 ticket += sizeof(*start);
74 *start = ktohl(flags, *start);
75 *end = life_to_time(*start, lifetime);
80 tlen = ticket - ticketBeg;
81 if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56))
86 /* This is called to interpret a ticket. It is assumed that the necessary keys
87 have been added so that the key version number in the ticket will indicate a
88 valid key for decrypting the ticket. The various fields inside the ticket
89 are copied into the return arguments. An error code indicate some problem
90 interpreting the ticket and the values of the output parameters are
94 tkt_DecodeTicket(char *asecret, afs_int32 ticketLen,
95 struct ktc_encryptionKey *key, char *name, char *inst,
96 char *cell, struct ktc_encryptionKey *sessionKey, afs_int32 * host,
97 afs_uint32 * start, afs_uint32 * end)
99 char clear_ticket[MAXKTCTICKETLEN];
101 union Key_schedule_safe schedule;
105 return RXKADBADTICKET; /* no ticket */
106 if ((ticketLen < MINKTCTICKETLEN) || /* minimum legal ticket size */
107 (ticketLen > MAXKTCTICKETLEN) || /* maximum legal ticket size */
108 ((ticketLen) % 8 != 0)) /* enc. part must be (0 mod 8) bytes */
109 return RXKADBADTICKET;
111 if (DES_key_sched(ktc_to_cblock(key), &schedule.schedule))
114 ticket = clear_ticket;
115 DES_pcbc_encrypt(asecret, ticket, ticketLen, &schedule.schedule, ktc_to_cblockptr(key), DECRYPT);
118 decode_athena_ticket(ticket, ticketLen, name, inst, cell, host,
119 (struct ktc_encryptionKey *)sessionKey, start, end);
122 return RXKADBADTICKET;
124 code = tkt_CheckTimes(*start, *end, time(0));
130 return RXKADBADTICKET;
135 /* This makes a Kerberos ticket */
137 char *ticket; * ticket is constructed here *
138 int *ticketLen; * output length of finished ticket *
139 struct ktc_encryptionKey *key; * key ticket should be sealed with *
140 char *name; * user of this ticket *
142 char *cell; * cell of authentication *
143 afs_uint32 start,end; * life of ticket *
144 struct ktc_encryptionKey *sessionKey; * session key invented for ticket *
145 afs_uint32 host; * caller's host address *
146 char *sname; * server *
150 #define putstr(name,min) \
151 slen = strlen(name); \
152 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
153 strcpy (ticket, name); \
155 #define putint(num) num = htonl(num);\
156 memcpy(ticket, &num, sizeof(num));\
157 ticket += sizeof(num)
160 assemble_athena_ticket(char *ticket, int *ticketLen, char *name, char *inst,
161 char *realm, afs_int32 host,
162 struct ktc_encryptionKey *sessionKey, afs_uint32 start,
163 afs_uint32 end, char *sname, char *sinst)
165 char *ticketBeg = ticket;
169 *ticket++ = 0; /* flags, always send net-byte-order */
175 memcpy(ticket, sessionKey, sizeof(struct ktc_encryptionKey));
176 ticket += sizeof(struct ktc_encryptionKey);
178 life = time_to_life(start, end);
187 *ticketLen = ticket - ticketBeg;
192 tkt_MakeTicket(char *ticket, int *ticketLen, struct ktc_encryptionKey *key,
193 char *name, char *inst, char *cell, afs_uint32 start,
194 afs_uint32 end, struct ktc_encryptionKey *sessionKey,
195 afs_uint32 host, char *sname, char *sinst)
198 union Key_schedule_safe schedule;
200 *ticketLen = 0; /* in case we return early */
202 assemble_athena_ticket(ticket, ticketLen, name, inst, cell, host,
203 sessionKey, start, end, sname, sinst);
204 *ticketLen = round_up_to_ebs(*ticketLen); /* round up */
209 if ((code = DES_key_sched(ktc_to_cblock(key), &schedule.schedule))) {
210 printf("In tkt_MakeTicket: key_sched returned %d\n", code);
213 DES_pcbc_encrypt(ticket, ticket, *ticketLen, &schedule.schedule,
214 ktc_to_cblockptr(key), ENCRYPT);
218 /* This is just a routine that checks the consistency of ticket lifetimes. It
219 returns three values: */
220 /* -2 means the times are inconsistent or ticket has expired
221 -1 means the ticket has recently expired.
222 0 means the times are consistent but start time is in the (near) future.
223 1 means the start time is in the past and the end time is infinity.
224 2 means the start time is past and the end time is in the future
225 and the lifetime is within the legal limit.
229 tkt_CheckTimes(afs_uint32 start, afs_uint32 end, afs_uint32 now)
234 return -2; /* zero or negative lifetime */
235 if (start > now + KTC_TIME_UNCERTAINTY + MAXKTCTICKETLIFETIME)
236 return -2; /* starts too far in the future? */
237 if ((start != 0) && (end != NEVERDATE)
238 && (end - start > MAXKTCTICKETLIFETIME))
239 return -2; /* too long a life */
240 if ((end != NEVERDATE) && (end + KTC_TIME_UNCERTAINTY < now)) { /* expired */
242 && (now - start > MAXKTCTICKETLIFETIME + 24 * 60 * 60))
245 return -1; /* expired only recently */
247 if ((start == 0) || (start - KTC_TIME_UNCERTAINTY <= now))
250 active = 0; /* start time not yet arrived */
252 if ((start == 0) || (end == NEVERDATE))
253 return active; /* no expiration time */
254 return active * 2; /* ticket valid */
258 ktohl(char flags, afs_int32 l)
261 unsigned char *lp = (unsigned char *)&l;
263 hl = *lp + (*(lp + 1) << 8) + (*(lp + 2) << 16) + (*(lp + 3) << 24);
269 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
270 * returns the corresponding end time. There are four simple cases to be
271 * handled. The first is a life of 0xff, meaning no expiration, and results in
272 * an end time of 0xffffffff. The second is when life is less than the values
273 * covered by the table. In this case, the end time is the start time plus the
274 * number of 5 minute intervals specified by life. The third case returns
275 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
276 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
277 * table to extract the lifetime in seconds, which is added to start to produce
281 life_to_time(afs_uint32 start, unsigned char life)
285 if (life == TKTLIFENOEXPIRE)
287 if (life < TKTLIFEMINFIXED)
288 return start + life * 5 * 60;
289 if (life > TKTLIFEMAXFIXED)
290 return start + MAXTKTLIFETIME;
291 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
292 return start + realLife;
295 /* time_to_life - takes start and end times for the ticket and returns a
296 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
297 * lifetimes above 127*5minutes. First, the special case of (end ==
298 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
299 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
300 * less than the first table entry are handled by rounding the requested
301 * lifetime *up* to the next 5 minute interval. The final step is to search
302 * the table for the smallest entry *greater than or equal* to the requested
303 * entry. The actual code is prepared to handle the case where the table is
304 * unordered but that it an unnecessary frill. */
307 time_to_life(afs_uint32 start, afs_uint32 end)
309 int lifetime = end - start;
313 if (end == NEVERDATE)
314 return TKTLIFENOEXPIRE;
315 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
317 if (lifetime < tkt_lifetimes[0])
318 return (lifetime + 5 * 60 - 1) / (5 * 60);
320 best = MAXKTCTICKETLIFETIME;
321 for (i = 0; i < TKTLIFENUMFIXED; i++)
322 if (tkt_lifetimes[i] >= lifetime) {
323 int diff = tkt_lifetimes[i] - lifetime;
331 return best_i + TKTLIFEMINFIXED;