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>
16 #include <hcrypto/des.h>
21 #include "lifetimes.h"
23 #include "rxkad_convert.h"
25 /* This union is used to insure we allocate enough space for a key
26 * schedule even if we are linked against a library that uses OpenSSL's
27 * larger representation. This is necessary so we don't lose if an
28 * application uses both rxkad and openssl.
30 union Key_schedule_safe {
31 DES_key_schedule schedule;
38 } openssl_schedule[16];
41 #define getstr(name,min) \
42 slen = strlen(ticket); \
43 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
44 strcpy (name, ticket); \
48 decode_athena_ticket(char *ticket, int ticketLen, char *name, char *inst,
49 char *realm, afs_int32 * host,
50 struct ktc_encryptionKey *sessionKey, afs_uint32 * start,
53 char *ticketBeg = ticket;
57 unsigned char lifetime;
58 char sname[MAXKTCNAMELEN]; /* these aren't used, */
59 char sinst[MAXKTCNAMELEN]; /* but are in the ticket */
66 memcpy(host, ticket, sizeof(*host));
67 ticket += sizeof(*host);
68 *host = ktohl(flags, *host);
70 memcpy(sessionKey, ticket, sizeof(struct ktc_encryptionKey));
71 ticket += sizeof(struct ktc_encryptionKey);
74 memcpy(start, ticket, sizeof(*start));
75 ticket += sizeof(*start);
76 *start = ktohl(flags, *start);
77 *end = life_to_time(*start, lifetime);
82 tlen = ticket - ticketBeg;
83 if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56))
88 /* This is called to interpret a ticket. It is assumed that the necessary keys
89 have been added so that the key version number in the ticket will indicate a
90 valid key for decrypting the ticket. The various fields inside the ticket
91 are copied into the return arguments. An error code indicate some problem
92 interpreting the ticket and the values of the output parameters are
96 tkt_DecodeTicket(char *asecret, afs_int32 ticketLen,
97 struct ktc_encryptionKey *key, char *name, char *inst,
98 char *cell, struct ktc_encryptionKey *sessionKey, afs_int32 * host,
99 afs_uint32 * start, afs_uint32 * end)
101 char clear_ticket[MAXKTCTICKETLEN];
103 union Key_schedule_safe schedule;
107 return RXKADBADTICKET; /* no ticket */
108 if ((ticketLen < MINKTCTICKETLEN) || /* minimum legal ticket size */
109 (ticketLen > MAXKTCTICKETLEN) || /* maximum legal ticket size */
110 ((ticketLen) % 8 != 0)) /* enc. part must be (0 mod 8) bytes */
111 return RXKADBADTICKET;
113 if (DES_key_sched(ktc_to_cblock(key), &schedule.schedule))
116 ticket = clear_ticket;
117 DES_pcbc_encrypt(asecret, ticket, ticketLen, &schedule.schedule, ktc_to_cblockptr(key), DECRYPT);
120 decode_athena_ticket(ticket, ticketLen, name, inst, cell, host,
121 (struct ktc_encryptionKey *)sessionKey, start, end);
124 return RXKADBADTICKET;
126 code = tkt_CheckTimes(*start, *end, time(0));
132 return RXKADBADTICKET;
137 /* This makes a Kerberos ticket */
139 char *ticket; * ticket is constructed here *
140 int *ticketLen; * output length of finished ticket *
141 struct ktc_encryptionKey *key; * key ticket should be sealed with *
142 char *name; * user of this ticket *
144 char *cell; * cell of authentication *
145 afs_uint32 start,end; * life of ticket *
146 struct ktc_encryptionKey *sessionKey; * session key invented for ticket *
147 afs_uint32 host; * caller's host address *
148 char *sname; * server *
152 #define putstr(name,min) \
153 slen = strlen(name); \
154 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
155 strcpy (ticket, name); \
157 #define putint(num) num = htonl(num);\
158 memcpy(ticket, &num, sizeof(num));\
159 ticket += sizeof(num)
162 assemble_athena_ticket(char *ticket, int *ticketLen, char *name, char *inst,
163 char *realm, afs_int32 host,
164 struct ktc_encryptionKey *sessionKey, afs_uint32 start,
165 afs_uint32 end, char *sname, char *sinst)
167 char *ticketBeg = ticket;
171 *ticket++ = 0; /* flags, always send net-byte-order */
177 memcpy(ticket, sessionKey, sizeof(struct ktc_encryptionKey));
178 ticket += sizeof(struct ktc_encryptionKey);
180 life = time_to_life(start, end);
189 *ticketLen = ticket - ticketBeg;
194 tkt_MakeTicket(char *ticket, int *ticketLen, struct ktc_encryptionKey *key,
195 char *name, char *inst, char *cell, afs_uint32 start,
196 afs_uint32 end, struct ktc_encryptionKey *sessionKey,
197 afs_uint32 host, char *sname, char *sinst)
200 union Key_schedule_safe schedule;
202 *ticketLen = 0; /* in case we return early */
204 assemble_athena_ticket(ticket, ticketLen, name, inst, cell, host,
205 sessionKey, start, end, sname, sinst);
206 *ticketLen = round_up_to_ebs(*ticketLen); /* round up */
211 if ((code = DES_key_sched(ktc_to_cblock(key), &schedule.schedule))) {
212 printf("In tkt_MakeTicket: key_sched returned %d\n", code);
215 DES_pcbc_encrypt(ticket, ticket, *ticketLen, &schedule.schedule,
216 ktc_to_cblockptr(key), ENCRYPT);
220 /* This is just a routine that checks the consistency of ticket lifetimes. It
221 returns three values: */
222 /* -2 means the times are inconsistent or ticket has expired
223 -1 means the ticket has recently expired.
224 0 means the times are consistent but start time is in the (near) future.
225 1 means the start time is in the past and the end time is infinity.
226 2 means the start time is past and the end time is in the future
227 and the lifetime is within the legal limit.
231 tkt_CheckTimes(afs_uint32 start, afs_uint32 end, afs_uint32 now)
236 return -2; /* zero or negative lifetime */
237 if (start > now + KTC_TIME_UNCERTAINTY + MAXKTCTICKETLIFETIME)
238 return -2; /* starts too far in the future? */
239 if ((start != 0) && (end != NEVERDATE)
240 && (end - start > MAXKTCTICKETLIFETIME))
241 return -2; /* too long a life */
242 if ((end != NEVERDATE) && (end + KTC_TIME_UNCERTAINTY < now)) { /* expired */
244 && (now - start > MAXKTCTICKETLIFETIME + 24 * 60 * 60))
247 return -1; /* expired only recently */
249 if ((start == 0) || (start - KTC_TIME_UNCERTAINTY <= now))
252 active = 0; /* start time not yet arrived */
254 if ((start == 0) || (end == NEVERDATE))
255 return active; /* no expiration time */
256 return active * 2; /* ticket valid */
260 ktohl(char flags, afs_int32 l)
263 unsigned char *lp = (unsigned char *)&l;
265 hl = *lp + (*(lp + 1) << 8) + (*(lp + 2) << 16) + (*(lp + 3) << 24);
271 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
272 * returns the corresponding end time. There are four simple cases to be
273 * handled. The first is a life of 0xff, meaning no expiration, and results in
274 * an end time of 0xffffffff. The second is when life is less than the values
275 * covered by the table. In this case, the end time is the start time plus the
276 * number of 5 minute intervals specified by life. The third case returns
277 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
278 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
279 * table to extract the lifetime in seconds, which is added to start to produce
283 life_to_time(afs_uint32 start, unsigned char life)
287 if (life == TKTLIFENOEXPIRE)
289 if (life < TKTLIFEMINFIXED)
290 return start + life * 5 * 60;
291 if (life > TKTLIFEMAXFIXED)
292 return start + MAXTKTLIFETIME;
293 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
294 return start + realLife;
297 /* time_to_life - takes start and end times for the ticket and returns a
298 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
299 * lifetimes above 127*5minutes. First, the special case of (end ==
300 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
301 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
302 * less than the first table entry are handled by rounding the requested
303 * lifetime *up* to the next 5 minute interval. The final step is to search
304 * the table for the smallest entry *greater than or equal* to the requested
305 * entry. The actual code is prepared to handle the case where the table is
306 * unordered but that it an unnecessary frill. */
309 time_to_life(afs_uint32 start, afs_uint32 end)
311 int lifetime = end - start;
315 if (end == NEVERDATE)
316 return TKTLIFENOEXPIRE;
317 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
319 if (lifetime < tkt_lifetimes[0])
320 return (lifetime + 5 * 60 - 1) / (5 * 60);
322 best = MAXKTCTICKETLIFETIME;
323 for (i = 0; i < TKTLIFENUMFIXED; i++)
324 if (tkt_lifetimes[i] >= lifetime) {
325 int diff = tkt_lifetimes[i] - lifetime;
333 return best_i + TKTLIFEMINFIXED;