Add rxgk_token.c
[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     xdr_destroy(&xdrs);
102     return ret;
103 }
104
105 /*
106  * Take the input TokenContainer and XDR-encode it, returning the result
107  * in 'out'.  The caller is responsible for freeing the memory contained
108  * in 'out'.
109  *
110  * Returns RX errors.
111  */
112 static afs_int32
113 pack_container(RXGK_TokenContainer *container, struct rx_opaque *out)
114 {
115     XDR xdrs;
116     afs_int32 ret;
117     u_int len;
118
119     memset(&xdrs, 0, sizeof(xdrs));
120     xdrlen_create(&xdrs);
121     if (!xdr_RXGK_TokenContainer(&xdrs, container)) {
122         ret = RXGEN_SS_MARSHAL;
123         goto done;
124     }
125     len = xdr_getpos(&xdrs);
126
127     ret = rx_opaque_alloc(out, len);
128     if (ret != 0)
129         goto done;
130
131     xdr_destroy(&xdrs);
132     xdrmem_create(&xdrs, out->val, len, XDR_ENCODE);
133     if (!xdr_RXGK_TokenContainer(&xdrs, container)) {
134         rx_opaque_freeContents(out);
135         ret = RXGEN_SS_MARSHAL;
136         goto done;
137     }
138     ret = 0;
139
140  done:
141     xdr_destroy(&xdrs);
142     return ret;
143 }
144
145 /*
146  * Take the input token, encode it, encrypt that blob, populate a
147  * TokenContainer with the encrypted token, kvno, and enctype, and encode
148  * the resulting TokenContainer into 'out'.
149  *
150  * Returns RX errors.
151  */
152 static afs_int32
153 pack_wrap_token(rxgk_key server_key, afs_int32 kvno, afs_int32 enctype,
154                 RXGK_Token *token, struct rx_opaque *out)
155 {
156     struct rx_opaque packed_token = RX_EMPTY_OPAQUE;
157     struct rx_opaque encrypted_token = RX_EMPTY_OPAQUE;
158     RXGK_TokenContainer container;
159     afs_int32 ret;
160
161     memset(&container, 0, sizeof(container));
162
163     /* XDR-encode the token in to packed_token. */
164     ret = pack_token(token, &packed_token);
165     if (ret != 0)
166         goto done;
167
168     ret = rxgk_encrypt_in_key(server_key, RXGK_SERVER_ENC_TOKEN, &packed_token,
169                               &encrypted_token);
170     if (ret != 0)
171         goto done;
172     ret = rx_opaque_populate(&container.encrypted_token, encrypted_token.val,
173                              encrypted_token.len);
174     if (ret != 0)
175         goto done;
176     container.kvno = kvno;
177     container.enctype = enctype;
178
179     /* Now the token container is populated; time to encode it into 'out'. */
180     ret = pack_container(&container, out);
181
182  done:
183     rx_opaque_freeContents(&packed_token);
184     rx_opaque_freeContents(&encrypted_token);
185     rx_opaque_freeContents(&container.encrypted_token);
186     return ret;
187 }
188
189 /**
190  * Print an rxgk token with random key, returning key and token
191  *
192  * Print a token (with empty identity list) with a random master key,
193  * and encrypt it in the specified key/kvno/enctype.  Return the master
194  * key as well as the token, so that the token is usable.
195  *
196  * The caller must free k0 with release_key().
197  *
198  * @param[out] out      The printed token (RXGK_TokenContainer).
199  * @param[in] input_info        Parameters describing the token to be printed.
200  * @param[in] key       The token-encrypting key.
201  * @param[in] kvno      The kvno of key.
202  * @param[in] enctype   The enctype of key.
203  * @param[out] k0_out   The token master key.
204  * @return rxgk error codes.
205  */
206 afs_int32
207 rxgk_print_token_and_key(struct rx_opaque *out, RXGK_TokenInfo *input_info,
208                          rxgk_key key, afs_int32 kvno, afs_int32 enctype,
209                          rxgk_key *k0_out)
210 {
211     struct rx_opaque k0_data = RX_EMPTY_OPAQUE;
212     rxgk_key k0 = NULL;
213     ssize_t len;
214     afs_int32 ret;
215
216     *k0_out = NULL;
217
218     len = rxgk_etype_to_len(input_info->enctype);
219     if (len < 0) {
220         ret = RXGK_BADETYPE;
221         goto done;
222     }
223
224     ret = rxgk_nonce(&k0_data, len);
225     if (ret != 0)
226         goto done;
227
228     ret = rxgk_make_key(&k0, k0_data.val, k0_data.len, input_info->enctype);
229     if (ret != 0)
230         goto done;
231
232     ret = rxgk_print_token(out, input_info, &k0_data, key, kvno, enctype);
233     if (ret != 0)
234         goto done;
235
236     *k0_out = k0;
237     k0 = NULL;
238
239  done:
240     rx_opaque_freeContents(&k0_data);
241     rxgk_release_key(&k0);
242     return ret;
243 }
244
245 /*
246  * Helper functions for rxgk_extract_token.
247  */
248 static int
249 unpack_container(RXGK_Data *in, RXGK_TokenContainer *container)
250 {
251     XDR xdrs;
252
253     memset(&xdrs, 0, sizeof(xdrs));
254
255     xdrmem_create(&xdrs, in->val, in->len, XDR_DECODE);
256     if (!xdr_RXGK_TokenContainer(&xdrs, container)) {
257         xdr_destroy(&xdrs);
258         return RXGEN_SS_UNMARSHAL;
259     }
260     xdr_destroy(&xdrs);
261     return 0;
262 }
263
264 static int
265 decrypt_token(struct rx_opaque *enctoken, afs_int32 kvno, afs_int32 enctype,
266               rxgk_getkey_func getkey, void *rock, RXGK_Data *out)
267 {
268     rxgk_key service_key = NULL;
269     afs_int32 ret;
270
271     if (kvno <= 0 || enctype <= 0) {
272         ret = RXGK_BAD_TOKEN;
273         goto done;
274     }
275
276     ret = getkey(rock, &kvno, &enctype, &service_key);
277     if (ret != 0)
278         goto done;
279     ret = rxgk_decrypt_in_key(service_key, RXGK_SERVER_ENC_TOKEN, enctoken,
280                               out);
281
282  done:
283     rxgk_release_key(&service_key);
284     return ret;
285 }
286
287 static int
288 unpack_token(RXGK_Data *in, RXGK_Token *token)
289 {
290     XDR xdrs;
291
292     memset(&xdrs, 0, sizeof(xdrs));
293
294     xdrmem_create(&xdrs, in->val, in->len, XDR_DECODE);
295     if (!xdr_RXGK_Token(&xdrs, token)) {
296         xdr_destroy(&xdrs);
297         return RXGEN_SS_UNMARSHAL;
298     }
299     xdr_destroy(&xdrs);
300     return 0;
301 }
302
303 /**
304  * Extract a cleartext RXGK_Token from a packed RXGK_TokenContainer
305  *
306  * Given an XDR-encoded RXGK_TokenContainer, extract/decrypt the contents
307  * into an RXGK_Token.
308  *
309  * The caller must free the returned token with xdr_free.
310  *
311  * @param[in] tc        The RXGK_TokenContainer to unpack.
312  * @param[out] out      The extracted RXGK_Token.
313  * @param[in] getkey    The getkey function used to decrypt the token.
314  * @param[in] rock      Data to pass to getkey.
315  * @return rxgk error codes.
316  */
317 afs_int32
318 rxgk_extract_token(RXGK_Data *tc, RXGK_Token *out, rxgk_getkey_func getkey,
319                    void *rock)
320 {
321     RXGK_TokenContainer container;
322     struct rx_opaque packed_token = RX_EMPTY_OPAQUE;
323     afs_int32 ret;
324
325     memset(&container, 0, sizeof(container));
326
327     ret = unpack_container(tc, &container);
328     if (ret != 0)
329         goto done;
330     ret = decrypt_token(&container.encrypted_token, container.kvno,
331                         container.enctype, getkey, rock, &packed_token);
332     if (ret != 0)
333         goto done;
334     ret = unpack_token(&packed_token, out);
335
336  done:
337     xdr_free((xdrproc_t)xdr_RXGK_TokenContainer, &container);
338     xdr_free((xdrproc_t)xdr_RXGK_Data, &packed_token);
339     return ret;
340 }
341
342 /* NEVER call this function directly (except from rxgk_make_token or
343  * rxgk_print_token). Call rxgk_make_token or rxgk_print_token instead. See
344  * rxgk_make_token for info about our arguments. */
345 static afs_int32
346 make_token(struct rx_opaque *out, RXGK_TokenInfo *info,
347            struct rx_opaque *k0, PrAuthName *identities,
348            int nids, rxgk_key key, afs_int32 kvno, afs_int32 enctype)
349 {
350     RXGK_Token token;
351     afs_int32 ret;
352
353     memset(&token, 0, sizeof(token));
354     memset(out, 0, sizeof(*out));
355
356     if (nids < 0) {
357         ret = RXGK_INCONSISTENCY;
358         goto done;
359     }
360
361     /* Get the tokeninfo values from the authoritative source. */
362     tokeninfo_to_token(info, &token);
363
364     /* Create the rest of the token. */
365     ret = rx_opaque_populate(&token.K0, k0->val, k0->len);
366     if (ret != 0)
367         goto done;
368     token.identities.len = (afs_uint32)nids;
369     token.identities.val = identities;
370     ret = pack_wrap_token(key, kvno, enctype, &token, out);
371     if (ret != 0)
372         goto done;
373
374  done:
375     /*
376      * We need to free the contents in 'token', but don't free
377      * token.identities. The pointer for that was given to us by our caller;
378      * they'll manage the memory for it.
379      */
380     memset(&token.identities, 0, sizeof(token.identities));
381     xdr_free((xdrproc_t)xdr_RXGK_Token, &token);
382     return ret;
383 }
384
385 /**
386  * Create an rxgk token
387  *
388  * Create a token from the specified TokenInfo, key, start time, and lists
389  * of identities.  Encrypts the token and stores it as an rx_opaque.
390  *
391  * Note that you cannot make printed tokens with this function ('nids' must be
392  * greater than 0). This is a deliberate restriction to try to avoid
393  * accidentally creating printed tokens.  Use rxgk_print_token() instead to
394  * make printed tokens.
395  *
396  * @param[out] out      The encoded rxgk token (RXGK_TokenContainer).
397  * @param[in] info      RXGK_Tokeninfo describing the token to be produced.
398  * @param[in] k0        The token master key.
399  * @param[in] identities The list of identities to be included in the token.
400  * @param[in] nids      The number of identities in the identities list (must
401  *                      be positive).
402  * @param[in] key       The token-encrypting key to use.
403  * @param[in] kvno      The kvno of key.
404  * @param[in] enctype   The enctype of key.
405  * @return rxgk error codes.
406  */
407 afs_int32
408 rxgk_make_token(struct rx_opaque *out, RXGK_TokenInfo *info,
409                 struct rx_opaque *k0, PrAuthName *identities,
410                 int nids, rxgk_key key, afs_int32 kvno, afs_int32 enctype)
411 {
412     if (nids == 0 || identities == NULL) {
413         /* You cannot make printed tokens with this function; use
414          * rxgk_print_token instead. */
415         memset(out, 0, sizeof(*out));
416         return RXGK_INCONSISTENCY;
417     }
418     return make_token(out, info, k0, identities, nids, key, kvno, enctype);
419 }
420
421 /* This lifetime is in seconds. */
422 #define DEFAULT_LIFETIME        (60 * 60 * 10)
423 /* The bytelife is log_2(bytes). */
424 #define DEFAULT_BYTELIFE        30
425 /**
426  * Create a printed rxgk token
427  *
428  * Print a token (with empty identity list) where the master key (k0)
429  * already exists, and encrypt it in the specified key/kvno/enctype.
430  *
431  * @param[out] out      The printed token (RXGK_TokenContainer).
432  * @param[in] input_info        Parameters describing the token to be printed.
433  * @param[in] k0        The master key to use for the token.
434  * @param[in] key       The token-encrypting key.
435  * @param[in] kvno      The kvno of key.
436  * @param[in] enctype   The enctype of key.
437  * @return rxgk error codes.
438  */
439 afs_int32
440 rxgk_print_token(struct rx_opaque *out, RXGK_TokenInfo *input_info,
441                  struct rx_opaque *k0, rxgk_key key, afs_int32 kvno,
442                  afs_int32 enctype)
443 {
444     RXGK_TokenInfo info;
445
446     memset(&info, 0, sizeof(info));
447
448     info.enctype = input_info->enctype;
449     info.level = input_info->level;
450     info.lifetime = DEFAULT_LIFETIME;
451     info.bytelife = DEFAULT_BYTELIFE;
452     info.expiration = RXGK_NEVERDATE;
453
454     return make_token(out, &info, k0, NULL, 0, key, kvno, enctype);
455 }
456