DEVEL15-cvsignore-happiness-20060801
[openafs.git] / src / rxgk / rxgk_common.c
1 /*
2  * Copyright (c) 2002 - 2004, Stockholms universitet
3  * (Stockholm University, Stockholm Sweden)
4  * All rights reserved.
5  * 
6  * Redistribution is not permitted
7  */
8
9 #include "rxgk_locl.h"
10
11 RCSID("$Id$");
12
13 #include <errno.h>
14
15 #include <rx/rx.h>
16 #include "rxgk_proto.h"
17
18 /*
19  *
20  */
21
22 int rxgk_key_contrib_size = 16;
23
24 /*
25  *
26  */
27
28 int
29 rxk5_mutual_auth_client_generate(krb5_context context, krb5_keyblock *key,
30                                  uint32_t number,
31                                  RXGK_Token *challage_token)
32 {
33     krb5_crypto crypto;
34     krb5_data data;
35     RXGK_CHALLENGE_TOKEN ct;
36     char buf[RXGK_CHALLENGE_TOKEN_MAX_SIZE];
37     size_t sz;
38     int ret;
39
40     data.data = NULL;
41
42     ret = krb5_crypto_init (context, key, key->keytype, &crypto);
43     if (ret)
44         return ret;
45     
46     ct.ct_version = RXGK_CR_TOKEN_VERSION;
47     ct.ct_nonce = number;
48     ct.ct_enctype.val = malloc(sizeof(ct.ct_enctype.val[0]));
49     ct.ct_enctype.len = 1;
50     if (ct.ct_enctype.val == NULL) {
51         ret = ENOMEM;
52         goto out;
53     }
54     ct.ct_enctype.val[0] = RXGK_CRYPTO_DES_CBC_CRC;
55     
56     sz = RXGK_CHALLENGE_TOKEN_MAX_SIZE;
57     if (ydr_encode_RXGK_CHALLENGE_TOKEN(&ct, buf, &sz) == NULL) {
58         ret = ENOMEM;
59         goto out;
60     }
61     sz = RXGK_CHALLENGE_TOKEN_MAX_SIZE - sz;
62
63     ret = krb5_encrypt(context, crypto, 0, buf, sz, &data);
64     if (ret)
65         goto out;
66     
67     challage_token->val = malloc(data.length);
68     if (challage_token->val == NULL) {
69         ret = ENOMEM;
70         goto out;
71     }
72
73     challage_token->len = data.length;
74     memcpy(challage_token->val, data.data, data.length);
75
76  out:
77     ydr_free_RXGK_CHALLENGE_TOKEN(&ct);
78     if (data.data)
79         krb5_data_free(&data);
80     krb5_crypto_destroy(context, crypto);
81     return ret;
82 }
83
84 /*
85  *
86  */
87
88 int
89 rxk5_mutual_auth_client_check(krb5_context context, krb5_keyblock *key,
90                               uint32_t number,
91                               const RXGK_Token *challage_token,
92                               krb5_keyblock *rxsession_key)
93 {
94     krb5_crypto crypto;
95     krb5_data data;
96     RXGK_REPLY_TOKEN rt;
97     size_t sz;
98     int ret;
99
100     memset(&rt, 0, sizeof(rt));
101     memset(rxsession_key, 0, sizeof(*rxsession_key));
102
103     ret = krb5_crypto_init (context, key, key->keytype, &crypto);
104     if (ret)
105         return ret;
106     
107     /* Decrypt ticket */
108     data.data = NULL;
109     ret = krb5_decrypt(context, crypto, 0,
110                        challage_token->val, challage_token->len,
111                        &data);
112     if (ret)
113         goto out;
114
115     sz = data.length;
116     if (ydr_decode_RXGK_REPLY_TOKEN(&rt, data.data, &sz) == NULL) {
117         ret = RXGKSEALEDINCON;
118         goto out;
119     }
120
121     if (rt.rt_nonce != number + 1) {
122         ret = RXGKSEALEDINCON;
123         goto out2;
124     }
125
126     if (rt.rt_error != 0) {
127         ret = rt.rt_error;
128         goto out2;
129     }
130
131 #if 1
132     /* XXX check rt_enctype */
133     ret = rxgk_random_to_key(rt.rt_enctype, 
134                              rt.rt_key.val, rt.rt_key.len,
135                              rxsession_key);
136 #else
137     ret = krb5_copy_keyblock_contents(context, key, rxsession_key);
138 #endif
139
140  out2:
141     ydr_free_RXGK_REPLY_TOKEN(&rt);
142  out:
143     if (data.data)
144         krb5_data_free(&data);
145     krb5_crypto_destroy(context, crypto);
146
147     return ret;
148 }
149
150 /*
151  *
152  */
153
154 int
155 rxk5_mutual_auth_server(krb5_context context, krb5_keyblock *key,
156                         const RXGK_Token *challage_token,
157                         int *session_enctype, 
158                         void **session_key, size_t *session_key_size,
159                         RXGK_Token *reply_token)
160 {
161     krb5_crypto crypto;
162     krb5_data data;
163     krb5_keyblock keyblock;
164     RXGK_CHALLENGE_TOKEN ct;
165     RXGK_REPLY_TOKEN rt;
166     char buf[RXGK_REPLY_TOKEN_MAX_SIZE];
167     size_t sz;
168     int ret;
169
170     memset(&rt, 0, sizeof(rt));
171     memset(&ct, 0, sizeof(ct));
172
173     *session_enctype = 0;
174     *session_key = NULL;
175     *session_key_size = 0;
176
177     keyblock.keyvalue.data = NULL;
178
179     sz = RXGK_CHALLENGE_TOKEN_MAX_SIZE - sz;
180
181     ret = krb5_crypto_init (context, key, key->keytype, &crypto);
182     if (ret)
183         return ret;
184     
185     /* Decrypt ticket */
186     data.data = NULL;
187     ret = krb5_decrypt(context, crypto, 0,
188                        challage_token->val, challage_token->len,
189                        &data);
190     if (ret)
191         goto out;
192
193     sz = data.length;
194     if (ydr_decode_RXGK_CHALLENGE_TOKEN(&ct, data.data, &sz) == NULL) {
195         memset(&ct, 0, sizeof(ct));
196         ret = ENOMEM;
197         goto out;
198     }
199     sz = data.length - sz;
200
201     krb5_data_free(&data);
202     data.data = NULL;
203
204     if (ct.ct_version < RXGK_CR_TOKEN_VERSION) {
205         ret = RXGKSEALEDINCON;
206         goto out;
207     } else
208         ret = 0;
209
210     /* XXX choose best enctype, not just the one we use now */
211     { 
212         int i;
213
214         for (i = 0; i < ct.ct_enctype.len ; i++) {
215             if (ct.ct_enctype.val[i] == key->keytype)
216                 break;
217         }
218
219         if (i == ct.ct_enctype.len)
220             ret = RXGKSEALEDINCON;
221     }
222
223     rt.rt_version = RXGK_CR_TOKEN_VERSION;
224     rt.rt_nonce = ct.ct_nonce + 1;
225
226     rt.rt_key.len = 0;
227     rt.rt_key.val = NULL;
228     rt.rt_error = ret;
229
230     if (ret == 0) {
231         ret = krb5_generate_random_keyblock(context, 
232                                             key->keytype,
233                                             &keyblock);
234         if (ret == 0) {
235             rt.rt_enctype = keyblock.keytype;
236             rt.rt_key.len = keyblock.keyvalue.length;
237             rt.rt_key.val = keyblock.keyvalue.data;
238
239             *session_enctype = keyblock.keytype;
240             *session_key_size = keyblock.keyvalue.length;
241             *session_key = malloc(keyblock.keyvalue.length);
242             if (*session_key == NULL)
243                 abort();
244             memcpy(*session_key, keyblock.keyvalue.data, 
245                    keyblock.keyvalue.length);
246         } else {
247             rt.rt_error = ret;
248         }
249     }
250
251     sz = RXGK_REPLY_TOKEN_MAX_SIZE;
252     if (ydr_encode_RXGK_REPLY_TOKEN(&rt, buf, &sz) == 0) {
253         ret = ENOMEM;
254         goto out;
255     }
256     sz = RXGK_REPLY_TOKEN_MAX_SIZE - sz;
257
258     memset(rt.rt_key.val, 0, rt.rt_key.len);
259
260     data.data = NULL;
261     ret = krb5_encrypt(context, crypto, 0, buf, sz, &data);
262     if (ret)
263         goto out;
264     
265     reply_token->val = malloc(data.length);
266     if (reply_token->val == NULL) {
267         ret = ENOMEM;
268         goto out;
269     }
270
271     reply_token->len = data.length;
272     memcpy(reply_token->val, data.data, data.length);
273
274  out:
275     ydr_free_RXGK_CHALLENGE_TOKEN(&ct);
276     /* ydr_free_RXGK_REPLY_TOKEN(&rt); */
277
278     if (data.data)
279         krb5_data_free(&data);
280     if (keyblock.keyvalue.data)
281         krb5_free_keyblock_contents(context, &keyblock);
282     krb5_crypto_destroy(context, crypto);
283     return ret;
284 }
285
286 /*
287  *
288  */
289
290 void
291 rxgk_getheader(struct rx_packet *pkt, struct rxgk_header_data *h)
292 {
293   uint32_t t;
294
295   /* Collect selected packet fields */
296   h->call_number = htonl(pkt->header.callNumber);
297   t = ((pkt->header.cid & RX_CHANNELMASK) << (32 - RX_CIDSHIFT))
298     | ((pkt->header.seq & 0x3fffffff));
299   h->channel_and_seq = htonl(t);
300 }
301
302 /*
303  *
304  */
305
306 #if 0
307 int
308 rxgk_derive_transport_key(krb5_context context,
309                           krb5_keyblock *rx_conn_key,
310                           RXGK_rxtransport_key *keycontrib,
311                           krb5_keyblock *rkey)
312 {
313     krb5_error_code ret;
314
315     /* XXX heimdal broken doesn't implement derive key for des encrypes */
316
317     switch (rx_conn_key->keytype) {
318     case RXGK_CRYPTO_DES_CBC_CRC:
319     case RXGK_CRYPTO_DES_CBC_MD4:
320     case RXGK_CRYPTO_DES_CBC_MD5:
321         ret = krb5_copy_keyblock_contents(context, rx_conn_key, rkey);
322         if (ret)
323             abort();
324
325         break;
326     default: {
327         char rxk_enc[RXGK_RXTRANSPORT_KEY_MAX_SIZE];
328         size_t sz;
329         krb5_keyblock *key;
330         
331         sz = RXGK_RXTRANSPORT_KEY_MAX_SIZE;
332         if (ydr_encode_RXGK_rxtransport_key(keycontrib, rxk_enc, &sz) == NULL)
333             return EINVAL;
334         
335         sz = RXGK_RXTRANSPORT_KEY_MAX_SIZE - sz;
336
337         ret = krb5_derive_key (context,
338                                rx_conn_key,
339                                rx_conn_key->keytype,
340                                rxk_enc,
341                                sz,
342                                &key);
343         if (ret)
344             abort();
345         
346         ret = krb5_copy_keyblock_contents(context, key, rkey);
347         if (ret)
348             abort();
349         
350         krb5_free_keyblock(context, key);
351         break;
352     }
353     }
354
355     return ret;
356 }
357 #endif
358
359 /*
360  *
361  */
362
363
364 /* XXX replace me */
365
366 int
367 rxgk_random_to_key(int enctype, 
368                    void *random_data, int random_sz,
369                    krb5_keyblock *key)
370 {
371     memset(key, 0, sizeof(*key));
372
373     switch (enctype) {
374     case RXGK_CRYPTO_DES_CBC_CRC:
375     case RXGK_CRYPTO_DES_CBC_MD4:
376     case RXGK_CRYPTO_DES_CBC_MD5:
377         if (random_sz != 8)
378             return RXGKINCONSISTENCY;
379         break;
380     default:
381             return RXGKINCONSISTENCY;
382     }
383
384     key->keyvalue.data = malloc(random_sz);
385     if (key->keyvalue.data == NULL)
386         return ENOMEM;
387     memcpy(key->keyvalue.data, random_data, random_sz);
388     key->keyvalue.length = random_sz;
389     key->keytype = enctype;
390
391     return 0;
392 }