xref: /freebsd/crypto/krb5/src/lib/krb5/krb/ser_actx.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/ser_actx.c - Serialize krb5_auth_context structure */
3 /*
4  * Copyright 1995, 2008 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 
27 #include "k5-int.h"
28 #include "int-proto.h"
29 #include "auth_con.h"
30 
31 #define TOKEN_RADDR     950916
32 #define TOKEN_RPORT     950917
33 #define TOKEN_LADDR     950918
34 #define TOKEN_LPORT     950919
35 #define TOKEN_KEYBLOCK  950920
36 #define TOKEN_LSKBLOCK  950921
37 #define TOKEN_RSKBLOCK  950922
38 
39 krb5_error_code
k5_size_auth_context(krb5_auth_context auth_context,size_t * sizep)40 k5_size_auth_context(krb5_auth_context auth_context, size_t *sizep)
41 {
42     krb5_error_code     kret;
43     size_t              required;
44 
45     /*
46      * krb5_auth_context requires at minimum:
47      *  krb5_int32              for KV5M_AUTH_CONTEXT
48      *  krb5_int32              for auth_context_flags
49      *  krb5_int32              for remote_seq_number
50      *  krb5_int32              for local_seq_number
51      *  krb5_int32              for req_cksumtype
52      *  krb5_int32              for safe_cksumtype
53      *  krb5_int32              for size of i_vector
54      *  krb5_int32              for KV5M_AUTH_CONTEXT
55      */
56     kret = EINVAL;
57     if (auth_context != NULL) {
58         kret = 0;
59 
60         required = auth_context->cstate.length;
61         required += sizeof(krb5_int32)*8;
62 
63         /* Calculate size required by remote_addr, if appropriate */
64         if (!kret && auth_context->remote_addr) {
65             kret = k5_size_address(auth_context->remote_addr, &required);
66             if (!kret)
67                 required += sizeof(krb5_int32);
68         }
69 
70         /* Calculate size required by remote_port, if appropriate */
71         if (!kret && auth_context->remote_port) {
72             kret = k5_size_address(auth_context->remote_port, &required);
73             if (!kret)
74                 required += sizeof(krb5_int32);
75         }
76 
77         /* Calculate size required by local_addr, if appropriate */
78         if (!kret && auth_context->local_addr) {
79             kret = k5_size_address(auth_context->local_addr, &required);
80             if (!kret)
81                 required += sizeof(krb5_int32);
82         }
83 
84         /* Calculate size required by local_port, if appropriate */
85         if (!kret && auth_context->local_port) {
86             kret = k5_size_address(auth_context->local_port, &required);
87             if (!kret)
88                 required += sizeof(krb5_int32);
89         }
90 
91         /* Calculate size required by key, if appropriate */
92         if (!kret && auth_context->key) {
93             kret = k5_size_keyblock(&auth_context->key->keyblock, &required);
94             if (!kret)
95                 required += sizeof(krb5_int32);
96         }
97 
98         /* Calculate size required by send_subkey, if appropriate */
99         if (!kret && auth_context->send_subkey) {
100             kret = k5_size_keyblock(&auth_context->send_subkey->keyblock,
101                                     &required);
102             if (!kret)
103                 required += sizeof(krb5_int32);
104         }
105 
106         /* Calculate size required by recv_subkey, if appropriate */
107         if (!kret && auth_context->recv_subkey) {
108             kret = k5_size_keyblock(&auth_context->recv_subkey->keyblock,
109                                     &required);
110             if (!kret)
111                 required += sizeof(krb5_int32);
112         }
113 
114         /* Calculate size required by authentp, if appropriate */
115         if (!kret && auth_context->authentp)
116             kret = k5_size_authenticator(auth_context->authentp, &required);
117 
118     }
119     if (!kret)
120         *sizep += required;
121     return(kret);
122 }
123 
124 krb5_error_code
k5_externalize_auth_context(krb5_auth_context auth_context,krb5_octet ** buffer,size_t * lenremain)125 k5_externalize_auth_context(krb5_auth_context auth_context,
126                             krb5_octet **buffer, size_t *lenremain)
127 {
128     krb5_error_code     kret;
129     size_t              required;
130     krb5_octet          *bp;
131     size_t              remain;
132 
133     required = 0;
134     bp = *buffer;
135     remain = *lenremain;
136     kret = EINVAL;
137     if (auth_context != NULL) {
138         kret = ENOMEM;
139         if (!k5_size_auth_context(auth_context, &required) &&
140             required <= remain) {
141 
142             /* Write fixed portion */
143             (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
144             (void) krb5_ser_pack_int32(auth_context->auth_context_flags,
145                                        &bp, &remain);
146             (void) krb5_ser_pack_int32(auth_context->remote_seq_number,
147                                        &bp, &remain);
148             (void) krb5_ser_pack_int32(auth_context->local_seq_number,
149                                        &bp, &remain);
150             (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype,
151                                        &bp, &remain);
152             (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype,
153                                        &bp, &remain);
154 
155             /* Write the cipher state */
156             (void) krb5_ser_pack_int32(auth_context->cstate.length, &bp,
157                                        &remain);
158             (void) krb5_ser_pack_bytes((krb5_octet *)auth_context->cstate.data,
159                                        auth_context->cstate.length,
160                                        &bp, &remain);
161 
162             kret = 0;
163 
164             /* Now handle remote_addr, if appropriate */
165             if (!kret && auth_context->remote_addr) {
166                 (void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain);
167                 kret = k5_externalize_address(auth_context->remote_addr,
168                                               &bp, &remain);
169             }
170 
171             /* Now handle remote_port, if appropriate */
172             if (!kret && auth_context->remote_port) {
173                 (void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain);
174                 kret = k5_externalize_address(auth_context->remote_addr,
175                                               &bp, &remain);
176             }
177 
178             /* Now handle local_addr, if appropriate */
179             if (!kret && auth_context->local_addr) {
180                 (void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain);
181                 kret = k5_externalize_address(auth_context->local_addr,
182                                               &bp, &remain);
183             }
184 
185             /* Now handle local_port, if appropriate */
186             if (!kret && auth_context->local_port) {
187                 (void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain);
188                 kret = k5_externalize_address(auth_context->local_addr,
189                                               &bp, &remain);
190             }
191 
192             /* Now handle keyblock, if appropriate */
193             if (!kret && auth_context->key) {
194                 (void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain);
195                 kret = k5_externalize_keyblock(&auth_context->key->keyblock,
196                                                &bp, &remain);
197             }
198 
199             /* Now handle subkey, if appropriate */
200             if (!kret && auth_context->send_subkey) {
201                 (void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain);
202                 kret = k5_externalize_keyblock(&auth_context->
203                                                send_subkey->keyblock,
204                                                &bp, &remain);
205             }
206 
207             /* Now handle subkey, if appropriate */
208             if (!kret && auth_context->recv_subkey) {
209                 (void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain);
210                 kret = k5_externalize_keyblock(&auth_context->
211                                                recv_subkey->keyblock,
212                                                &bp, &remain);
213             }
214 
215             /* Now handle authentp, if appropriate */
216             if (!kret && auth_context->authentp)
217                 kret = k5_externalize_authenticator(auth_context->authentp,
218                                                     &bp, &remain);
219 
220             /*
221              * If we were successful, write trailer then update the pointer and
222              * remaining length;
223              */
224             if (!kret) {
225                 /* Write our trailer */
226                 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
227                 *buffer = bp;
228                 *lenremain = remain;
229             }
230         }
231     }
232     return(kret);
233 }
234 
235 /* Internalize a keyblock and convert it to a key. */
236 static krb5_error_code
intern_key(krb5_key * key,krb5_octet ** bp,size_t * sp)237 intern_key(krb5_key *key, krb5_octet **bp, size_t *sp)
238 {
239     krb5_keyblock *keyblock;
240     krb5_error_code ret;
241 
242     ret = k5_internalize_keyblock(&keyblock, bp, sp);
243     if (ret != 0)
244         return ret;
245     ret = krb5_k_create_key(NULL, keyblock, key);
246     krb5_free_keyblock(NULL, keyblock);
247     return ret;
248 }
249 
250 krb5_error_code
k5_internalize_auth_context(krb5_auth_context * argp,krb5_octet ** buffer,size_t * lenremain)251 k5_internalize_auth_context(krb5_auth_context *argp,
252                             krb5_octet **buffer, size_t *lenremain)
253 {
254     krb5_error_code     kret;
255     krb5_auth_context   auth_context;
256     krb5_int32          ibuf;
257     krb5_octet          *bp;
258     size_t              remain;
259     krb5_int32          cstate_len;
260     krb5_int32          tag;
261 
262     bp = *buffer;
263     remain = *lenremain;
264     kret = EINVAL;
265     /* Read our magic number */
266     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
267         ibuf = 0;
268     if (ibuf == KV5M_AUTH_CONTEXT) {
269         kret = ENOMEM;
270 
271         /* Get memory for the auth_context */
272         if ((remain >= (5*sizeof(krb5_int32))) &&
273             (auth_context = (krb5_auth_context)
274              calloc(1, sizeof(struct _krb5_auth_context)))) {
275 
276             /* Get auth_context_flags */
277             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
278             auth_context->auth_context_flags = ibuf;
279 
280             /* Get remote_seq_number */
281             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
282             auth_context->remote_seq_number = ibuf;
283 
284             /* Get local_seq_number */
285             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
286             auth_context->local_seq_number = ibuf;
287 
288             /* Get req_cksumtype */
289             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
290             auth_context->req_cksumtype = (krb5_cksumtype) ibuf;
291 
292             /* Get safe_cksumtype */
293             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
294             auth_context->safe_cksumtype = (krb5_cksumtype) ibuf;
295 
296             /* Get length of cstate */
297             (void) krb5_ser_unpack_int32(&cstate_len, &bp, &remain);
298 
299             if (cstate_len) {
300                 kret = alloc_data(&auth_context->cstate, cstate_len);
301                 if (!kret) {
302                     kret = krb5_ser_unpack_bytes((krb5_octet *)
303                                                  auth_context->cstate.data,
304                                                  cstate_len, &bp, &remain);
305                 }
306             }
307             else
308                 kret = 0;
309 
310             /* Peek at next token */
311             tag = 0;
312             if (!kret)
313                 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
314 
315             /* This is the remote_addr */
316             if (!kret && (tag == TOKEN_RADDR)) {
317                 if (!(kret = k5_internalize_address(&auth_context->remote_addr,
318                                                     &bp, &remain)))
319                     kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
320             }
321 
322             /* This is the remote_port */
323             if (!kret && (tag == TOKEN_RPORT)) {
324                 if (!(kret = k5_internalize_address(&auth_context->remote_port,
325                                                     &bp, &remain)))
326                     kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
327             }
328 
329             /* This is the local_addr */
330             if (!kret && (tag == TOKEN_LADDR)) {
331                 if (!(kret = k5_internalize_address(&auth_context->local_addr,
332                                                     &bp, &remain)))
333                     kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
334             }
335 
336             /* This is the local_port */
337             if (!kret && (tag == TOKEN_LPORT)) {
338                 if (!(kret = k5_internalize_address(&auth_context->local_port,
339                                                     &bp, &remain)))
340                     kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
341             }
342 
343             /* This is the keyblock */
344             if (!kret && (tag == TOKEN_KEYBLOCK)) {
345                 if (!(kret = intern_key(&auth_context->key, &bp, &remain)))
346                     kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
347             }
348 
349             /* This is the send_subkey */
350             if (!kret && (tag == TOKEN_LSKBLOCK)) {
351                 if (!(kret = intern_key(&auth_context->send_subkey,
352                                         &bp, &remain)))
353                     kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
354             }
355 
356             /* This is the recv_subkey */
357             if (!kret) {
358                 if (tag == TOKEN_RSKBLOCK) {
359                     kret = intern_key(&auth_context->recv_subkey,
360                                       &bp, &remain);
361                 }
362                 else {
363                     /*
364                      * We read the next tag, but it's not of any use here, so
365                      * we effectively 'unget' it here.
366                      */
367                     bp -= sizeof(krb5_int32);
368                     remain += sizeof(krb5_int32);
369                 }
370             }
371 
372             /* Now find the authentp */
373             if (!kret) {
374                 kret = k5_internalize_authenticator(&auth_context->authentp,
375                                                     &bp, &remain);
376                 if (kret == EINVAL)
377                     kret = 0;
378             }
379 
380             /* Finally, find the trailer */
381             if (!kret) {
382                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
383                 if (!kret && (ibuf != KV5M_AUTH_CONTEXT))
384                     kret = EINVAL;
385             }
386             if (!kret) {
387                 *buffer = bp;
388                 *lenremain = remain;
389                 auth_context->magic = KV5M_AUTH_CONTEXT;
390                 *argp = auth_context;
391             }
392             else
393                 krb5_auth_con_free(NULL, auth_context);
394         }
395     }
396     return(kret);
397 }
398