auth: Avoid cellconfig.c stdio renaming
[openafs.git] / src / rxgk / rxgk_token.c
1 /* rxgk/rxgk_token.c - Token generation/manuipluation routines for RXGK */
2 /*
3  * Copyright (C) 2013, 2014 by the Massachusetts Institute of Technology.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 /**
33  * @file
34  * Routines to generate, encode, encrypt, decode, and decrypt rxgk tokens.
35  */
36
37
38 #include <afsconfig.h>
39 #include <afs/param.h>
40 #include <afs/stds.h>
41
42 #include <rx/rx.h>
43 #include <rx/xdr.h>
44 #include <rx/rx_opaque.h>
45 #include <rx/rxgk.h>
46 #include <errno.h>
47
48 #include "rxgk_private.h"
49
50 /*
51  * Copy the fields from a TokenInfo to a Token.
52  */
53 static void
54 tokeninfo_to_token(RXGK_TokenInfo *info, RXGK_Token *token)
55 {
56
57     token->enctype = info->enctype;
58     token->level = info->level;
59     token->lifetime = info->lifetime;
60     token->bytelife = info->bytelife;
61     token->expirationtime = info->expiration;
62     return;
63 }
64
65 /*
66  * Take the input RXGK_Token and XDR-encode it, returning the result in 'out'.
67  * The caller is responsible for freeing the memory contained in 'out'.
68  *
69  * Returns RX errors.
70  */
71 static afs_int32
72 pack_token(RXGK_Token *token, struct rx_opaque *out)
73 {
74     XDR xdrs;
75     afs_int32 ret;
76     u_int len;
77
78     memset(&xdrs, 0, sizeof(xdrs));
79     memset(out, 0, sizeof(*out));
80     xdrlen_create(&xdrs);
81     if (!xdr_RXGK_Token(&xdrs, token)) {
82         ret = RXGEN_SS_MARSHAL;
83         goto done;
84     }
85     len = xdr_getpos(&xdrs);
86
87     ret = rx_opaque_alloc(out, len);
88     if (ret != 0)
89         goto done;
90
91     xdr_destroy(&xdrs);
92     xdrmem_create(&xdrs, out->val, len, XDR_ENCODE);
93     if (!xdr_RXGK_Token(&xdrs, token)) {
94         rx_opaque_freeContents(out);
95         ret = RXGEN_SS_MARSHAL;
96         goto done;
97     }
98     ret = 0;
99
100  done:
101     if (xdrs.x_ops) {
102         xdr_destroy(&xdrs);
103     }
104     return ret;
105 }
106
107 /*
108  * Take the input TokenContainer and XDR-encode it, returning the result
109  * in 'out'.  The caller is responsible for freeing the memory contained
110  * in 'out'.
111  *
112  * Returns RX errors.
113  */
114 static afs_int32
115 pack_container(RXGK_TokenContainer *container, struct rx_opaque *out)
116 {
117     XDR xdrs;
118     afs_int32 ret;
119     u_int len;
120
121     memset(&xdrs, 0, sizeof(xdrs));
122     xdrlen_create(&xdrs);
123     if (!xdr_RXGK_TokenContainer(&xdrs, container)) {
124         ret = RXGEN_SS_MARSHAL;
125         goto done;
126     }
127     len = xdr_getpos(&xdrs);
128
129     ret = rx_opaque_alloc(out, len);
130     if (ret != 0)
131         goto done;
132
133     xdr_destroy(&xdrs);
134     xdrmem_create(&xdrs, out->val, len, XDR_ENCODE);
135     if (!xdr_RXGK_TokenContainer(&xdrs, container)) {
136         rx_opaque_freeContents(out);
137         ret = RXGEN_SS_MARSHAL;
138         goto done;
139     }
140     ret = 0;
141
142  done:
143     if (xdrs.x_ops) {
144         xdr_destroy(&xdrs);
145     }
146     return ret;
147 }
148
149 /*
150  * Take the input token, encode it, encrypt that blob, populate a
151  * TokenContainer with the encrypted token, kvno, and enctype, and encode
152  * the resulting TokenContainer into 'out'.
153  *
154  * Returns RX errors.
155  */
156 static afs_int32
157 pack_wrap_token(rxgk_key server_key, afs_int32 kvno, afs_int32 enctype,
158                 RXGK_Token *token, struct rx_opaque *out)
159 {
160     struct rx_opaque packed_token = RX_EMPTY_OPAQUE;
161     struct rx_opaque encrypted_token = RX_EMPTY_OPAQUE;
162     RXGK_TokenContainer container;
163     afs_int32 ret;
164
165     memset(&container, 0, sizeof(container));
166
167     /* XDR-encode the token in to packed_token. */
168     ret = pack_token(token, &packed_token);
169     if (ret != 0)
170         goto done;
171
172     ret = rxgk_encrypt_in_key(server_key, RXGK_SERVER_ENC_TOKEN, &packed_token,
173                               &encrypted_token);
174     if (ret != 0)
175         goto done;
176     ret = rx_opaque_populate(&container.encrypted_token, encrypted_token.val,
177                              encrypted_token.len);
178     if (ret != 0)
179         goto done;
180     container.kvno = kvno;
181     container.enctype = enctype;
182
183     /* Now the token container is populated; time to encode it into 'out'. */
184     ret = pack_container(&container, out);
185
186  done:
187     rx_opaque_freeContents(&packed_token);
188     rx_opaque_freeContents(&encrypted_token);
189     rx_opaque_freeContents(&container.encrypted_token);
190     return ret;
191 }
192
193 /**
194  * Print an rxgk token with random key, returning key and token
195  *
196  * Print a token (with empty identity list) with a random master key,
197  * and encrypt it in the specified key/kvno/enctype.  Return the master
198  * key as well as the token, so that the token is usable.
199  *
200  * The caller must free k0 with release_key().
201  *
202  * @param[out] out      The printed token (RXGK_TokenContainer).
203  * @param[in] input_info        Parameters describing the token to be printed.
204  * @param[in] key       The token-encrypting key.
205  * @param[in] kvno      The kvno of key.
206  * @param[in] enctype   The enctype of key.
207  * @param[out] k0_out   The token master key.
208  * @return rxgk error codes.
209  */
210 afs_int32
211 rxgk_print_token_and_key(struct rx_opaque *out, RXGK_TokenInfo *input_info,
212                          rxgk_key key, afs_int32 kvno, afs_int32 enctype,
213                          rxgk_key *k0_out)
214 {
215     struct rx_opaque k0_data = RX_EMPTY_OPAQUE;
216     rxgk_key k0 = NULL;
217     ssize_t len;
218     afs_int32 ret;
219
220     *k0_out = NULL;
221
222     len = rxgk_etype_to_len(input_info->enctype);
223     if (len < 0) {
224         ret = RXGK_BADETYPE;
225         goto done;
226     }
227
228     ret = rxgk_nonce(&k0_data, len);
229     if (ret != 0)
230         goto done;
231
232     ret = rxgk_make_key(&k0, k0_data.val, k0_data.len, input_info->enctype);
233     if (ret != 0)
234         goto done;
235
236     ret = rxgk_print_token(out, input_info, &k0_data, key, kvno, enctype);
237     if (ret != 0)
238         goto done;
239
240     *k0_out = k0;
241     k0 = NULL;
242
243  done:
244     rx_opaque_freeContents(&k0_data);
245     rxgk_release_key(&k0);
246     return ret;
247 }
248
249 /*
250  * Helper functions for rxgk_extract_token.
251  */
252 static int
253 unpack_container(RXGK_Data *in, RXGK_TokenContainer *container)
254 {
255     XDR xdrs;
256
257     memset(&xdrs, 0, sizeof(xdrs));
258
259     xdrmem_create(&xdrs, in->val, in->len, XDR_DECODE);
260     if (!xdr_RXGK_TokenContainer(&xdrs, container)) {
261         xdr_destroy(&xdrs);
262         return RXGEN_SS_UNMARSHAL;
263     }
264     xdr_destroy(&xdrs);
265     return 0;
266 }
267
268 static int
269 decrypt_token(struct rx_opaque *enctoken, afs_int32 kvno, afs_int32 enctype,
270               rxgk_getkey_func getkey, void *rock, RXGK_Data *out)
271 {
272     rxgk_key service_key = NULL;
273     afs_int32 ret;
274
275     if (kvno <= 0 || enctype <= 0) {
276         ret = RXGK_BAD_TOKEN;
277         goto done;
278     }
279
280     ret = getkey(rock, &kvno, &enctype, &service_key);
281     if (ret != 0)
282         goto done;
283     ret = rxgk_decrypt_in_key(service_key, RXGK_SERVER_ENC_TOKEN, enctoken,
284                               out);
285
286  done:
287     rxgk_release_key(&service_key);
288     return ret;
289 }
290
291 static int
292 unpack_token(RXGK_Data *in, RXGK_Token *token)
293 {
294     XDR xdrs;
295
296     memset(&xdrs, 0, sizeof(xdrs));
297
298     xdrmem_create(&xdrs, in->val, in->len, XDR_DECODE);
299     if (!xdr_RXGK_Token(&xdrs, token)) {
300         xdr_destroy(&xdrs);
301         return RXGEN_SS_UNMARSHAL;
302     }
303     xdr_destroy(&xdrs);
304     return 0;
305 }
306
307 /**
308  * Extract a cleartext RXGK_Token from a packed RXGK_TokenContainer
309  *
310  * Given an XDR-encoded RXGK_TokenContainer, extract/decrypt the contents
311  * into an RXGK_Token.
312  *
313  * The caller must free the returned token with xdr_free.
314  *
315  * @param[in] tc        The RXGK_TokenContainer to unpack.
316  * @param[out] out      The extracted RXGK_Token.
317  * @param[in] getkey    The getkey function used to decrypt the token.
318  * @param[in] rock      Data to pass to getkey.
319  * @return rxgk error codes.
320  */
321 afs_int32
322 rxgk_extract_token(RXGK_Data *tc, RXGK_Token *out, rxgk_getkey_func getkey,
323                    void *rock)
324 {
325     RXGK_TokenContainer container;
326     struct rx_opaque packed_token = RX_EMPTY_OPAQUE;
327     afs_int32 ret;
328
329     memset(&container, 0, sizeof(container));
330
331     ret = unpack_container(tc, &container);
332     if (ret != 0)
333         goto done;
334     ret = decrypt_token(&container.encrypted_token, container.kvno,
335                         container.enctype, getkey, rock, &packed_token);
336     if (ret != 0)
337         goto done;
338     ret = unpack_token(&packed_token, out);
339
340  done:
341     xdr_free((xdrproc_t)xdr_RXGK_TokenContainer, &container);
342     xdr_free((xdrproc_t)xdr_RXGK_Data, &packed_token);
343     return ret;
344 }
345
346 /* NEVER call this function directly (except from rxgk_make_token or
347  * rxgk_print_token). Call rxgk_make_token or rxgk_print_token instead. See
348  * rxgk_make_token for info about our arguments. */
349 static afs_int32
350 make_token(struct rx_opaque *out, RXGK_TokenInfo *info,
351            struct rx_opaque *k0, PrAuthName *identities,
352            int nids, rxgk_key key, afs_int32 kvno, afs_int32 enctype)
353 {
354     RXGK_Token token;
355     afs_int32 ret;
356
357     memset(&token, 0, sizeof(token));
358     memset(out, 0, sizeof(*out));
359
360     if (nids < 0) {
361         ret = RXGK_INCONSISTENCY;
362         goto done;
363     }
364
365     /* Get the tokeninfo values from the authoritative source. */
366     tokeninfo_to_token(info, &token);
367
368     /* Create the rest of the token. */
369     ret = rx_opaque_populate(&token.K0, k0->val, k0->len);
370     if (ret != 0)
371         goto done;
372     token.identities.len = (afs_uint32)nids;
373     token.identities.val = identities;
374     ret = pack_wrap_token(key, kvno, enctype, &token, out);
375     if (ret != 0)
376         goto done;
377
378  done:
379     /*
380      * We need to free the contents in 'token', but don't free
381      * token.identities. The pointer for that was given to us by our caller;
382      * they'll manage the memory for it.
383      */
384     memset(&token.identities, 0, sizeof(token.identities));
385     xdr_free((xdrproc_t)xdr_RXGK_Token, &token);
386     return ret;
387 }
388
389 /**
390  * Create an rxgk token
391  *
392  * Create a token from the specified TokenInfo, key, start time, and lists
393  * of identities.  Encrypts the token and stores it as an rx_opaque.
394  *
395  * Note that you cannot make printed tokens with this function ('nids' must be
396  * greater than 0). This is a deliberate restriction to try to avoid
397  * accidentally creating printed tokens.  Use rxgk_print_token() instead to
398  * make printed tokens.
399  *
400  * @param[out] out      The encoded rxgk token (RXGK_TokenContainer).
401  * @param[in] info      RXGK_Tokeninfo describing the token to be produced.
402  * @param[in] k0        The token master key.
403  * @param[in] identities The list of identities to be included in the token.
404  * @param[in] nids      The number of identities in the identities list (must
405  *                      be positive).
406  * @param[in] key       The token-encrypting key to use.
407  * @param[in] kvno      The kvno of key.
408  * @param[in] enctype   The enctype of key.
409  * @return rxgk error codes.
410  */
411 afs_int32
412 rxgk_make_token(struct rx_opaque *out, RXGK_TokenInfo *info,
413                 struct rx_opaque *k0, PrAuthName *identities,
414                 int nids, rxgk_key key, afs_int32 kvno, afs_int32 enctype)
415 {
416     if (nids == 0 || identities == NULL) {
417         /* You cannot make printed tokens with this function; use
418          * rxgk_print_token instead. */
419         memset(out, 0, sizeof(*out));
420         return RXGK_INCONSISTENCY;
421     }
422     return make_token(out, info, k0, identities, nids, key, kvno, enctype);
423 }
424
425 /* This lifetime is in seconds. */
426 #define DEFAULT_LIFETIME        (60 * 60 * 10)
427 /* The bytelife is log_2(bytes). */
428 #define DEFAULT_BYTELIFE        30
429 /**
430  * Create a printed rxgk token
431  *
432  * Print a token (with empty identity list) where the master key (k0)
433  * already exists, and encrypt it in the specified key/kvno/enctype.
434  *
435  * @param[out] out      The printed token (RXGK_TokenContainer).
436  * @param[in] input_info        Parameters describing the token to be printed.
437  * @param[in] k0        The master key to use for the token.
438  * @param[in] key       The token-encrypting key.
439  * @param[in] kvno      The kvno of key.
440  * @param[in] enctype   The enctype of key.
441  * @return rxgk error codes.
442  */
443 afs_int32
444 rxgk_print_token(struct rx_opaque *out, RXGK_TokenInfo *input_info,
445                  struct rx_opaque *k0, rxgk_key key, afs_int32 kvno,
446                  afs_int32 enctype)
447 {
448     RXGK_TokenInfo info;
449
450     memset(&info, 0, sizeof(info));
451
452     info.enctype = input_info->enctype;
453     info.level = input_info->level;
454     info.lifetime = DEFAULT_LIFETIME;
455     info.bytelife = DEFAULT_BYTELIFE;
456     info.expiration = RXGK_NEVERDATE;
457
458     return make_token(out, &info, k0, NULL, 0, key, kvno, enctype);
459 }
460