1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson * All rights reserved.
5c19800e8SDoug Rabson *
6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson * are met:
9c19800e8SDoug Rabson *
10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson *
13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson *
17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson * without specific prior written permission.
20c19800e8SDoug Rabson *
21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson * SUCH DAMAGE.
32c19800e8SDoug Rabson */
33c19800e8SDoug Rabson
34c19800e8SDoug Rabson #include "krb5_locl.h"
35ae771770SStanislav Sedov #include <wind.h>
36c19800e8SDoug Rabson
37c19800e8SDoug Rabson struct PAC_INFO_BUFFER {
38c19800e8SDoug Rabson uint32_t type;
39c19800e8SDoug Rabson uint32_t buffersize;
40c19800e8SDoug Rabson uint32_t offset_hi;
41c19800e8SDoug Rabson uint32_t offset_lo;
42c19800e8SDoug Rabson };
43c19800e8SDoug Rabson
44c19800e8SDoug Rabson struct PACTYPE {
45c19800e8SDoug Rabson uint32_t numbuffers;
46c19800e8SDoug Rabson uint32_t version;
47c19800e8SDoug Rabson struct PAC_INFO_BUFFER buffers[1];
48c19800e8SDoug Rabson };
49c19800e8SDoug Rabson
50c19800e8SDoug Rabson struct krb5_pac_data {
51c19800e8SDoug Rabson struct PACTYPE *pac;
52c19800e8SDoug Rabson krb5_data data;
53c19800e8SDoug Rabson struct PAC_INFO_BUFFER *server_checksum;
54c19800e8SDoug Rabson struct PAC_INFO_BUFFER *privsvr_checksum;
55c19800e8SDoug Rabson struct PAC_INFO_BUFFER *logon_name;
56c19800e8SDoug Rabson };
57c19800e8SDoug Rabson
58c19800e8SDoug Rabson #define PAC_ALIGNMENT 8
59c19800e8SDoug Rabson
60c19800e8SDoug Rabson #define PACTYPE_SIZE 8
61c19800e8SDoug Rabson #define PAC_INFO_BUFFER_SIZE 16
62c19800e8SDoug Rabson
63c19800e8SDoug Rabson #define PAC_SERVER_CHECKSUM 6
64c19800e8SDoug Rabson #define PAC_PRIVSVR_CHECKSUM 7
65c19800e8SDoug Rabson #define PAC_LOGON_NAME 10
66c19800e8SDoug Rabson #define PAC_CONSTRAINED_DELEGATION 11
67c19800e8SDoug Rabson
68c19800e8SDoug Rabson #define CHECK(r,f,l) \
69c19800e8SDoug Rabson do { \
70c19800e8SDoug Rabson if (((r) = f ) != 0) { \
71ae771770SStanislav Sedov krb5_clear_error_message(context); \
72c19800e8SDoug Rabson goto l; \
73c19800e8SDoug Rabson } \
74c19800e8SDoug Rabson } while(0)
75c19800e8SDoug Rabson
76c19800e8SDoug Rabson static const char zeros[PAC_ALIGNMENT] = { 0 };
77c19800e8SDoug Rabson
78c19800e8SDoug Rabson /*
79ae771770SStanislav Sedov * HMAC-MD5 checksum over any key (needed for the PAC routines)
80ae771770SStanislav Sedov */
81ae771770SStanislav Sedov
82ae771770SStanislav Sedov static krb5_error_code
HMAC_MD5_any_checksum(krb5_context context,const krb5_keyblock * key,const void * data,size_t len,unsigned usage,Checksum * result)83ae771770SStanislav Sedov HMAC_MD5_any_checksum(krb5_context context,
84ae771770SStanislav Sedov const krb5_keyblock *key,
85ae771770SStanislav Sedov const void *data,
86ae771770SStanislav Sedov size_t len,
87ae771770SStanislav Sedov unsigned usage,
88ae771770SStanislav Sedov Checksum *result)
89ae771770SStanislav Sedov {
90ae771770SStanislav Sedov struct _krb5_key_data local_key;
91ae771770SStanislav Sedov krb5_error_code ret;
92ae771770SStanislav Sedov
93ae771770SStanislav Sedov memset(&local_key, 0, sizeof(local_key));
94ae771770SStanislav Sedov
95ae771770SStanislav Sedov ret = krb5_copy_keyblock(context, key, &local_key.key);
96ae771770SStanislav Sedov if (ret)
97ae771770SStanislav Sedov return ret;
98ae771770SStanislav Sedov
99ae771770SStanislav Sedov ret = krb5_data_alloc (&result->checksum, 16);
100ae771770SStanislav Sedov if (ret) {
101ae771770SStanislav Sedov krb5_free_keyblock(context, local_key.key);
102ae771770SStanislav Sedov return ret;
103ae771770SStanislav Sedov }
104ae771770SStanislav Sedov
105ae771770SStanislav Sedov result->cksumtype = CKSUMTYPE_HMAC_MD5;
106ae771770SStanislav Sedov ret = _krb5_HMAC_MD5_checksum(context, &local_key, data, len, usage, result);
107ae771770SStanislav Sedov if (ret)
108ae771770SStanislav Sedov krb5_data_free(&result->checksum);
109ae771770SStanislav Sedov
110ae771770SStanislav Sedov krb5_free_keyblock(context, local_key.key);
111ae771770SStanislav Sedov return ret;
112ae771770SStanislav Sedov }
113ae771770SStanislav Sedov
114ae771770SStanislav Sedov
pac_header_size(krb5_context context,uint32_t num_buffers,uint32_t * result)115*ed549cb0SCy Schubert static krb5_error_code pac_header_size(krb5_context context,
116*ed549cb0SCy Schubert uint32_t num_buffers,
117*ed549cb0SCy Schubert uint32_t *result)
118*ed549cb0SCy Schubert {
119*ed549cb0SCy Schubert krb5_error_code ret;
120*ed549cb0SCy Schubert uint32_t header_size;
121*ed549cb0SCy Schubert
122*ed549cb0SCy Schubert /* Guard against integer overflow on 32-bit systems. */
123*ed549cb0SCy Schubert if (num_buffers > 1000) {
124*ed549cb0SCy Schubert ret = EINVAL;
125*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "PAC has too many buffers");
126*ed549cb0SCy Schubert return ret;
127*ed549cb0SCy Schubert }
128*ed549cb0SCy Schubert header_size = PAC_INFO_BUFFER_SIZE * num_buffers;
129*ed549cb0SCy Schubert
130*ed549cb0SCy Schubert /* Guard against integer overflow on 32-bit systems. */
131*ed549cb0SCy Schubert if (header_size > UINT32_MAX - PACTYPE_SIZE) {
132*ed549cb0SCy Schubert ret = EINVAL;
133*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "PAC has too many buffers");
134*ed549cb0SCy Schubert return ret;
135*ed549cb0SCy Schubert }
136*ed549cb0SCy Schubert header_size += PACTYPE_SIZE;
137*ed549cb0SCy Schubert
138*ed549cb0SCy Schubert *result = header_size;
139*ed549cb0SCy Schubert
140*ed549cb0SCy Schubert return 0;
141*ed549cb0SCy Schubert }
142*ed549cb0SCy Schubert
pac_aligned_size(krb5_context context,uint32_t size,uint32_t * aligned_size)143*ed549cb0SCy Schubert static krb5_error_code pac_aligned_size(krb5_context context,
144*ed549cb0SCy Schubert uint32_t size,
145*ed549cb0SCy Schubert uint32_t *aligned_size)
146*ed549cb0SCy Schubert {
147*ed549cb0SCy Schubert krb5_error_code ret;
148*ed549cb0SCy Schubert
149*ed549cb0SCy Schubert /* Guard against integer overflow on 32-bit systems. */
150*ed549cb0SCy Schubert if (size > UINT32_MAX - (PAC_ALIGNMENT - 1)) {
151*ed549cb0SCy Schubert ret = EINVAL;
152*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
153*ed549cb0SCy Schubert return ret;
154*ed549cb0SCy Schubert }
155*ed549cb0SCy Schubert size += PAC_ALIGNMENT - 1;
156*ed549cb0SCy Schubert
157*ed549cb0SCy Schubert /* align to PAC_ALIGNMENT */
158*ed549cb0SCy Schubert size = (size / PAC_ALIGNMENT) * PAC_ALIGNMENT;
159*ed549cb0SCy Schubert
160*ed549cb0SCy Schubert *aligned_size = size;
161*ed549cb0SCy Schubert
162*ed549cb0SCy Schubert return 0;
163*ed549cb0SCy Schubert }
164*ed549cb0SCy Schubert
165ae771770SStanislav Sedov /*
166c19800e8SDoug Rabson *
167c19800e8SDoug Rabson */
168c19800e8SDoug Rabson
169ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_parse(krb5_context context,const void * ptr,size_t len,krb5_pac * pac)170c19800e8SDoug Rabson krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
171c19800e8SDoug Rabson krb5_pac *pac)
172c19800e8SDoug Rabson {
173c19800e8SDoug Rabson krb5_error_code ret;
174c19800e8SDoug Rabson krb5_pac p;
175c19800e8SDoug Rabson krb5_storage *sp = NULL;
176c19800e8SDoug Rabson uint32_t i, tmp, tmp2, header_end;
177c19800e8SDoug Rabson
178c19800e8SDoug Rabson p = calloc(1, sizeof(*p));
179c19800e8SDoug Rabson if (p == NULL) {
180ae771770SStanislav Sedov ret = krb5_enomem(context);
181c19800e8SDoug Rabson goto out;
182c19800e8SDoug Rabson }
183c19800e8SDoug Rabson
184c19800e8SDoug Rabson sp = krb5_storage_from_readonly_mem(ptr, len);
185c19800e8SDoug Rabson if (sp == NULL) {
186ae771770SStanislav Sedov ret = krb5_enomem(context);
187c19800e8SDoug Rabson goto out;
188c19800e8SDoug Rabson }
189c19800e8SDoug Rabson krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
190c19800e8SDoug Rabson
191c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &tmp), out);
192c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &tmp2), out);
193c19800e8SDoug Rabson if (tmp < 1) {
194c19800e8SDoug Rabson ret = EINVAL; /* Too few buffers */
195ae771770SStanislav Sedov krb5_set_error_message(context, ret, N_("PAC have too few buffer", ""));
196c19800e8SDoug Rabson goto out;
197c19800e8SDoug Rabson }
198c19800e8SDoug Rabson if (tmp2 != 0) {
199c19800e8SDoug Rabson ret = EINVAL; /* Wrong version */
200ae771770SStanislav Sedov krb5_set_error_message(context, ret,
201ae771770SStanislav Sedov N_("PAC have wrong version %d", ""),
202ae771770SStanislav Sedov (int)tmp2);
203c19800e8SDoug Rabson goto out;
204c19800e8SDoug Rabson }
205c19800e8SDoug Rabson
206*ed549cb0SCy Schubert ret = pac_header_size(context, tmp, &header_end);
207*ed549cb0SCy Schubert if (ret) {
208*ed549cb0SCy Schubert return ret;
209*ed549cb0SCy Schubert }
210*ed549cb0SCy Schubert
211*ed549cb0SCy Schubert p->pac = calloc(1, header_end);
212c19800e8SDoug Rabson if (p->pac == NULL) {
213ae771770SStanislav Sedov ret = krb5_enomem(context);
214c19800e8SDoug Rabson goto out;
215c19800e8SDoug Rabson }
216c19800e8SDoug Rabson
217c19800e8SDoug Rabson p->pac->numbuffers = tmp;
218c19800e8SDoug Rabson p->pac->version = tmp2;
219c19800e8SDoug Rabson
220c19800e8SDoug Rabson if (header_end > len) {
221c19800e8SDoug Rabson ret = EINVAL;
222c19800e8SDoug Rabson goto out;
223c19800e8SDoug Rabson }
224c19800e8SDoug Rabson
225c19800e8SDoug Rabson for (i = 0; i < p->pac->numbuffers; i++) {
226c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].type), out);
227c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize), out);
228c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_lo), out);
229c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_hi), out);
230c19800e8SDoug Rabson
231c19800e8SDoug Rabson /* consistency checks */
232c19800e8SDoug Rabson if (p->pac->buffers[i].offset_lo & (PAC_ALIGNMENT - 1)) {
233c19800e8SDoug Rabson ret = EINVAL;
234ae771770SStanislav Sedov krb5_set_error_message(context, ret,
235ae771770SStanislav Sedov N_("PAC out of allignment", ""));
236c19800e8SDoug Rabson goto out;
237c19800e8SDoug Rabson }
238c19800e8SDoug Rabson if (p->pac->buffers[i].offset_hi) {
239c19800e8SDoug Rabson ret = EINVAL;
240ae771770SStanislav Sedov krb5_set_error_message(context, ret,
241ae771770SStanislav Sedov N_("PAC high offset set", ""));
242c19800e8SDoug Rabson goto out;
243c19800e8SDoug Rabson }
244c19800e8SDoug Rabson if (p->pac->buffers[i].offset_lo > len) {
245c19800e8SDoug Rabson ret = EINVAL;
246ae771770SStanislav Sedov krb5_set_error_message(context, ret,
247ae771770SStanislav Sedov N_("PAC offset off end", ""));
248c19800e8SDoug Rabson goto out;
249c19800e8SDoug Rabson }
250c19800e8SDoug Rabson if (p->pac->buffers[i].offset_lo < header_end) {
251c19800e8SDoug Rabson ret = EINVAL;
252ae771770SStanislav Sedov krb5_set_error_message(context, ret,
253ae771770SStanislav Sedov N_("PAC offset inside header: %lu %lu", ""),
254ae771770SStanislav Sedov (unsigned long)p->pac->buffers[i].offset_lo,
255ae771770SStanislav Sedov (unsigned long)header_end);
256c19800e8SDoug Rabson goto out;
257c19800e8SDoug Rabson }
258c19800e8SDoug Rabson if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){
259c19800e8SDoug Rabson ret = EINVAL;
260ae771770SStanislav Sedov krb5_set_error_message(context, ret, N_("PAC length off end", ""));
261c19800e8SDoug Rabson goto out;
262c19800e8SDoug Rabson }
263c19800e8SDoug Rabson
264c19800e8SDoug Rabson /* let save pointer to data we need later */
265c19800e8SDoug Rabson if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
266c19800e8SDoug Rabson if (p->server_checksum) {
267c19800e8SDoug Rabson ret = EINVAL;
268ae771770SStanislav Sedov krb5_set_error_message(context, ret,
269ae771770SStanislav Sedov N_("PAC have two server checksums", ""));
270c19800e8SDoug Rabson goto out;
271c19800e8SDoug Rabson }
272c19800e8SDoug Rabson p->server_checksum = &p->pac->buffers[i];
273c19800e8SDoug Rabson } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
274c19800e8SDoug Rabson if (p->privsvr_checksum) {
275c19800e8SDoug Rabson ret = EINVAL;
276ae771770SStanislav Sedov krb5_set_error_message(context, ret,
277ae771770SStanislav Sedov N_("PAC have two KDC checksums", ""));
278c19800e8SDoug Rabson goto out;
279c19800e8SDoug Rabson }
280c19800e8SDoug Rabson p->privsvr_checksum = &p->pac->buffers[i];
281c19800e8SDoug Rabson } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
282c19800e8SDoug Rabson if (p->logon_name) {
283c19800e8SDoug Rabson ret = EINVAL;
284ae771770SStanislav Sedov krb5_set_error_message(context, ret,
285ae771770SStanislav Sedov N_("PAC have two logon names", ""));
286c19800e8SDoug Rabson goto out;
287c19800e8SDoug Rabson }
288c19800e8SDoug Rabson p->logon_name = &p->pac->buffers[i];
289c19800e8SDoug Rabson }
290c19800e8SDoug Rabson }
291c19800e8SDoug Rabson
292c19800e8SDoug Rabson ret = krb5_data_copy(&p->data, ptr, len);
293c19800e8SDoug Rabson if (ret)
294c19800e8SDoug Rabson goto out;
295c19800e8SDoug Rabson
296c19800e8SDoug Rabson krb5_storage_free(sp);
297c19800e8SDoug Rabson
298c19800e8SDoug Rabson *pac = p;
299c19800e8SDoug Rabson return 0;
300c19800e8SDoug Rabson
301c19800e8SDoug Rabson out:
302c19800e8SDoug Rabson if (sp)
303c19800e8SDoug Rabson krb5_storage_free(sp);
304c19800e8SDoug Rabson if (p) {
305c19800e8SDoug Rabson if (p->pac)
306c19800e8SDoug Rabson free(p->pac);
307c19800e8SDoug Rabson free(p);
308c19800e8SDoug Rabson }
309c19800e8SDoug Rabson *pac = NULL;
310c19800e8SDoug Rabson
311c19800e8SDoug Rabson return ret;
312c19800e8SDoug Rabson }
313c19800e8SDoug Rabson
314ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_init(krb5_context context,krb5_pac * pac)315c19800e8SDoug Rabson krb5_pac_init(krb5_context context, krb5_pac *pac)
316c19800e8SDoug Rabson {
317c19800e8SDoug Rabson krb5_error_code ret;
318c19800e8SDoug Rabson krb5_pac p;
319c19800e8SDoug Rabson
320c19800e8SDoug Rabson p = calloc(1, sizeof(*p));
321c19800e8SDoug Rabson if (p == NULL) {
322ae771770SStanislav Sedov return krb5_enomem(context);
323c19800e8SDoug Rabson }
324c19800e8SDoug Rabson
325c19800e8SDoug Rabson p->pac = calloc(1, sizeof(*p->pac));
326c19800e8SDoug Rabson if (p->pac == NULL) {
327c19800e8SDoug Rabson free(p);
328ae771770SStanislav Sedov return krb5_enomem(context);
329c19800e8SDoug Rabson }
330c19800e8SDoug Rabson
331c19800e8SDoug Rabson ret = krb5_data_alloc(&p->data, PACTYPE_SIZE);
332c19800e8SDoug Rabson if (ret) {
333c19800e8SDoug Rabson free (p->pac);
334c19800e8SDoug Rabson free(p);
335ae771770SStanislav Sedov return krb5_enomem(context);
336c19800e8SDoug Rabson }
337c19800e8SDoug Rabson
338c19800e8SDoug Rabson *pac = p;
339c19800e8SDoug Rabson return 0;
340c19800e8SDoug Rabson }
341c19800e8SDoug Rabson
342ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_add_buffer(krb5_context context,krb5_pac p,uint32_t type,const krb5_data * data)343c19800e8SDoug Rabson krb5_pac_add_buffer(krb5_context context, krb5_pac p,
344c19800e8SDoug Rabson uint32_t type, const krb5_data *data)
345c19800e8SDoug Rabson {
346c19800e8SDoug Rabson krb5_error_code ret;
347c19800e8SDoug Rabson void *ptr;
348*ed549cb0SCy Schubert uint32_t unaligned_len, num_buffers, len, offset, header_end, old_end;
349c19800e8SDoug Rabson uint32_t i;
350c19800e8SDoug Rabson
351*ed549cb0SCy Schubert if (data->length > UINT32_MAX) {
352*ed549cb0SCy Schubert ret = EINVAL;
353*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
354*ed549cb0SCy Schubert return ret;
355*ed549cb0SCy Schubert }
356c19800e8SDoug Rabson
357*ed549cb0SCy Schubert num_buffers = p->pac->numbuffers;
358*ed549cb0SCy Schubert
359*ed549cb0SCy Schubert if (num_buffers >= UINT32_MAX) {
360*ed549cb0SCy Schubert ret = EINVAL;
361*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
362*ed549cb0SCy Schubert return ret;
363*ed549cb0SCy Schubert }
364*ed549cb0SCy Schubert ret = pac_header_size(context, num_buffers + 1, &header_end);
365*ed549cb0SCy Schubert if (ret) {
366*ed549cb0SCy Schubert return ret;
367*ed549cb0SCy Schubert }
368*ed549cb0SCy Schubert
369*ed549cb0SCy Schubert ptr = realloc(p->pac, header_end);
370ae771770SStanislav Sedov if (ptr == NULL)
371ae771770SStanislav Sedov return krb5_enomem(context);
372ae771770SStanislav Sedov
373c19800e8SDoug Rabson p->pac = ptr;
374c19800e8SDoug Rabson
375*ed549cb0SCy Schubert for (i = 0; i < num_buffers; i++) {
376*ed549cb0SCy Schubert if (p->pac->buffers[i].offset_lo > UINT32_MAX - PAC_INFO_BUFFER_SIZE) {
377*ed549cb0SCy Schubert ret = EINVAL;
378*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
379*ed549cb0SCy Schubert return ret;
380*ed549cb0SCy Schubert }
381c19800e8SDoug Rabson
382*ed549cb0SCy Schubert p->pac->buffers[i].offset_lo += PAC_INFO_BUFFER_SIZE;
383*ed549cb0SCy Schubert }
384*ed549cb0SCy Schubert
385*ed549cb0SCy Schubert if (p->data.length > UINT32_MAX - PAC_INFO_BUFFER_SIZE) {
386*ed549cb0SCy Schubert ret = EINVAL;
387*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
388*ed549cb0SCy Schubert return ret;
389*ed549cb0SCy Schubert }
390c19800e8SDoug Rabson offset = p->data.length + PAC_INFO_BUFFER_SIZE;
391c19800e8SDoug Rabson
392*ed549cb0SCy Schubert p->pac->buffers[num_buffers].type = type;
393*ed549cb0SCy Schubert p->pac->buffers[num_buffers].buffersize = data->length;
394*ed549cb0SCy Schubert p->pac->buffers[num_buffers].offset_lo = offset;
395*ed549cb0SCy Schubert p->pac->buffers[num_buffers].offset_hi = 0;
396c19800e8SDoug Rabson
397c19800e8SDoug Rabson old_end = p->data.length;
398*ed549cb0SCy Schubert if (offset > UINT32_MAX - data->length) {
399ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "integer overrun");
400c19800e8SDoug Rabson return EINVAL;
401c19800e8SDoug Rabson }
402*ed549cb0SCy Schubert unaligned_len = offset + data->length;
403c19800e8SDoug Rabson
404*ed549cb0SCy Schubert ret = pac_aligned_size(context, unaligned_len, &len);
405*ed549cb0SCy Schubert if (ret)
406*ed549cb0SCy Schubert return ret;
407c19800e8SDoug Rabson
408c19800e8SDoug Rabson ret = krb5_data_realloc(&p->data, len);
409c19800e8SDoug Rabson if (ret) {
410ae771770SStanislav Sedov krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
411c19800e8SDoug Rabson return ret;
412c19800e8SDoug Rabson }
413c19800e8SDoug Rabson
414c19800e8SDoug Rabson /*
415c19800e8SDoug Rabson * make place for new PAC INFO BUFFER header
416c19800e8SDoug Rabson */
417*ed549cb0SCy Schubert header_end -= PAC_INFO_BUFFER_SIZE;
418c19800e8SDoug Rabson memmove((unsigned char *)p->data.data + header_end + PAC_INFO_BUFFER_SIZE,
419c19800e8SDoug Rabson (unsigned char *)p->data.data + header_end ,
420c19800e8SDoug Rabson old_end - header_end);
421c19800e8SDoug Rabson memset((unsigned char *)p->data.data + header_end, 0, PAC_INFO_BUFFER_SIZE);
422c19800e8SDoug Rabson
423c19800e8SDoug Rabson /*
424c19800e8SDoug Rabson * copy in new data part
425c19800e8SDoug Rabson */
426c19800e8SDoug Rabson
427c19800e8SDoug Rabson memcpy((unsigned char *)p->data.data + offset,
428c19800e8SDoug Rabson data->data, data->length);
429c19800e8SDoug Rabson memset((unsigned char *)p->data.data + offset + data->length,
430*ed549cb0SCy Schubert 0, p->data.length - unaligned_len);
431c19800e8SDoug Rabson
432c19800e8SDoug Rabson p->pac->numbuffers += 1;
433c19800e8SDoug Rabson
434c19800e8SDoug Rabson return 0;
435c19800e8SDoug Rabson }
436c19800e8SDoug Rabson
437ae771770SStanislav Sedov /**
438ae771770SStanislav Sedov * Get the PAC buffer of specific type from the pac.
439ae771770SStanislav Sedov *
440ae771770SStanislav Sedov * @param context Kerberos 5 context.
441ae771770SStanislav Sedov * @param p the pac structure returned by krb5_pac_parse().
442ae771770SStanislav Sedov * @param type type of buffer to get
443ae771770SStanislav Sedov * @param data return data, free with krb5_data_free().
444ae771770SStanislav Sedov *
445ae771770SStanislav Sedov * @return Returns 0 to indicate success. Otherwise an kerberos et
446ae771770SStanislav Sedov * error code is returned, see krb5_get_error_message().
447ae771770SStanislav Sedov *
448ae771770SStanislav Sedov * @ingroup krb5_pac
449ae771770SStanislav Sedov */
450ae771770SStanislav Sedov
451ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_get_buffer(krb5_context context,krb5_pac p,uint32_t type,krb5_data * data)452c19800e8SDoug Rabson krb5_pac_get_buffer(krb5_context context, krb5_pac p,
453c19800e8SDoug Rabson uint32_t type, krb5_data *data)
454c19800e8SDoug Rabson {
455c19800e8SDoug Rabson krb5_error_code ret;
456c19800e8SDoug Rabson uint32_t i;
457c19800e8SDoug Rabson
458c19800e8SDoug Rabson for (i = 0; i < p->pac->numbuffers; i++) {
459*ed549cb0SCy Schubert const uint32_t len = p->pac->buffers[i].buffersize;
460*ed549cb0SCy Schubert const uint32_t offset = p->pac->buffers[i].offset_lo;
461c19800e8SDoug Rabson
462c19800e8SDoug Rabson if (p->pac->buffers[i].type != type)
463c19800e8SDoug Rabson continue;
464c19800e8SDoug Rabson
465c19800e8SDoug Rabson ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
466c19800e8SDoug Rabson if (ret) {
467ae771770SStanislav Sedov krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
468c19800e8SDoug Rabson return ret;
469c19800e8SDoug Rabson }
470c19800e8SDoug Rabson return 0;
471c19800e8SDoug Rabson }
472ae771770SStanislav Sedov krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found",
473c19800e8SDoug Rabson (unsigned long)type);
474c19800e8SDoug Rabson return ENOENT;
475c19800e8SDoug Rabson }
476c19800e8SDoug Rabson
477c19800e8SDoug Rabson /*
478c19800e8SDoug Rabson *
479c19800e8SDoug Rabson */
480c19800e8SDoug Rabson
481ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_get_types(krb5_context context,krb5_pac p,size_t * len,uint32_t ** types)482c19800e8SDoug Rabson krb5_pac_get_types(krb5_context context,
483c19800e8SDoug Rabson krb5_pac p,
484c19800e8SDoug Rabson size_t *len,
485c19800e8SDoug Rabson uint32_t **types)
486c19800e8SDoug Rabson {
487c19800e8SDoug Rabson size_t i;
488c19800e8SDoug Rabson
489c19800e8SDoug Rabson *types = calloc(p->pac->numbuffers, sizeof(*types));
490c19800e8SDoug Rabson if (*types == NULL) {
491c19800e8SDoug Rabson *len = 0;
492ae771770SStanislav Sedov return krb5_enomem(context);
493c19800e8SDoug Rabson }
494c19800e8SDoug Rabson for (i = 0; i < p->pac->numbuffers; i++)
495c19800e8SDoug Rabson (*types)[i] = p->pac->buffers[i].type;
496c19800e8SDoug Rabson *len = p->pac->numbuffers;
497c19800e8SDoug Rabson
498c19800e8SDoug Rabson return 0;
499c19800e8SDoug Rabson }
500c19800e8SDoug Rabson
501c19800e8SDoug Rabson /*
502c19800e8SDoug Rabson *
503c19800e8SDoug Rabson */
504c19800e8SDoug Rabson
505ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_pac_free(krb5_context context,krb5_pac pac)506c19800e8SDoug Rabson krb5_pac_free(krb5_context context, krb5_pac pac)
507c19800e8SDoug Rabson {
508c19800e8SDoug Rabson krb5_data_free(&pac->data);
509c19800e8SDoug Rabson free(pac->pac);
510c19800e8SDoug Rabson free(pac);
511c19800e8SDoug Rabson }
512c19800e8SDoug Rabson
513c19800e8SDoug Rabson /*
514c19800e8SDoug Rabson *
515c19800e8SDoug Rabson */
516c19800e8SDoug Rabson
517c19800e8SDoug Rabson static krb5_error_code
verify_checksum(krb5_context context,const struct PAC_INFO_BUFFER * sig,const krb5_data * data,void * ptr,size_t len,const krb5_keyblock * key)518c19800e8SDoug Rabson verify_checksum(krb5_context context,
519c19800e8SDoug Rabson const struct PAC_INFO_BUFFER *sig,
520c19800e8SDoug Rabson const krb5_data *data,
521c19800e8SDoug Rabson void *ptr, size_t len,
522c19800e8SDoug Rabson const krb5_keyblock *key)
523c19800e8SDoug Rabson {
524c19800e8SDoug Rabson krb5_storage *sp = NULL;
525c19800e8SDoug Rabson uint32_t type;
526c19800e8SDoug Rabson krb5_error_code ret;
527c19800e8SDoug Rabson Checksum cksum;
528c19800e8SDoug Rabson
529c19800e8SDoug Rabson memset(&cksum, 0, sizeof(cksum));
530c19800e8SDoug Rabson
531c19800e8SDoug Rabson sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo,
532c19800e8SDoug Rabson sig->buffersize);
533ae771770SStanislav Sedov if (sp == NULL)
534ae771770SStanislav Sedov return krb5_enomem(context);
535ae771770SStanislav Sedov
536c19800e8SDoug Rabson krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
537c19800e8SDoug Rabson
538c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &type), out);
539c19800e8SDoug Rabson cksum.cksumtype = type;
540c19800e8SDoug Rabson cksum.checksum.length =
541c19800e8SDoug Rabson sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
542c19800e8SDoug Rabson cksum.checksum.data = malloc(cksum.checksum.length);
543c19800e8SDoug Rabson if (cksum.checksum.data == NULL) {
544ae771770SStanislav Sedov ret = krb5_enomem(context);
545c19800e8SDoug Rabson goto out;
546c19800e8SDoug Rabson }
547c19800e8SDoug Rabson ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
548ae771770SStanislav Sedov if (ret != (int)cksum.checksum.length) {
549c19800e8SDoug Rabson ret = EINVAL;
550ae771770SStanislav Sedov krb5_set_error_message(context, ret, "PAC checksum missing checksum");
551c19800e8SDoug Rabson goto out;
552c19800e8SDoug Rabson }
553c19800e8SDoug Rabson
554c19800e8SDoug Rabson if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) {
555c19800e8SDoug Rabson ret = EINVAL;
556ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Checksum type %d not keyed",
557ae771770SStanislav Sedov cksum.cksumtype);
558c19800e8SDoug Rabson goto out;
559c19800e8SDoug Rabson }
560c19800e8SDoug Rabson
561ae771770SStanislav Sedov /* If the checksum is HMAC-MD5, the checksum type is not tied to
562ae771770SStanislav Sedov * the key type, instead the HMAC-MD5 checksum is applied blindly
563ae771770SStanislav Sedov * on whatever key is used for this connection, avoiding issues
564ae771770SStanislav Sedov * with unkeyed checksums on des-cbc-md5 and des-cbc-crc. See
565ae771770SStanislav Sedov * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
566ae771770SStanislav Sedov * for the same issue in MIT, and
567ae771770SStanislav Sedov * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
568ae771770SStanislav Sedov * for Microsoft's explaination */
569ae771770SStanislav Sedov
570ae771770SStanislav Sedov if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
571ae771770SStanislav Sedov Checksum local_checksum;
572ae771770SStanislav Sedov
573ae771770SStanislav Sedov memset(&local_checksum, 0, sizeof(local_checksum));
574ae771770SStanislav Sedov
575ae771770SStanislav Sedov ret = HMAC_MD5_any_checksum(context, key, ptr, len,
576ae771770SStanislav Sedov KRB5_KU_OTHER_CKSUM, &local_checksum);
577ae771770SStanislav Sedov
578ae771770SStanislav Sedov if (ret != 0 || krb5_data_ct_cmp(&local_checksum.checksum, &cksum.checksum) != 0) {
579ae771770SStanislav Sedov ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
580ae771770SStanislav Sedov krb5_set_error_message(context, ret,
581ae771770SStanislav Sedov N_("PAC integrity check failed for "
582ae771770SStanislav Sedov "hmac-md5 checksum", ""));
583ae771770SStanislav Sedov }
584ae771770SStanislav Sedov krb5_data_free(&local_checksum.checksum);
585ae771770SStanislav Sedov
586ae771770SStanislav Sedov } else {
587ae771770SStanislav Sedov krb5_crypto crypto = NULL;
588ae771770SStanislav Sedov
589c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto);
590c19800e8SDoug Rabson if (ret)
591c19800e8SDoug Rabson goto out;
592c19800e8SDoug Rabson
593c19800e8SDoug Rabson ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
594c19800e8SDoug Rabson ptr, len, &cksum);
595c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto);
596ae771770SStanislav Sedov }
597ae771770SStanislav Sedov free(cksum.checksum.data);
598c19800e8SDoug Rabson krb5_storage_free(sp);
599c19800e8SDoug Rabson
600c19800e8SDoug Rabson return ret;
601c19800e8SDoug Rabson
602c19800e8SDoug Rabson out:
603c19800e8SDoug Rabson if (cksum.checksum.data)
604c19800e8SDoug Rabson free(cksum.checksum.data);
605c19800e8SDoug Rabson if (sp)
606c19800e8SDoug Rabson krb5_storage_free(sp);
607c19800e8SDoug Rabson return ret;
608c19800e8SDoug Rabson }
609c19800e8SDoug Rabson
610c19800e8SDoug Rabson static krb5_error_code
create_checksum(krb5_context context,const krb5_keyblock * key,uint32_t cksumtype,void * data,size_t datalen,void * sig,size_t siglen)611c19800e8SDoug Rabson create_checksum(krb5_context context,
612c19800e8SDoug Rabson const krb5_keyblock *key,
613ae771770SStanislav Sedov uint32_t cksumtype,
614c19800e8SDoug Rabson void *data, size_t datalen,
615c19800e8SDoug Rabson void *sig, size_t siglen)
616c19800e8SDoug Rabson {
617c19800e8SDoug Rabson krb5_crypto crypto = NULL;
618c19800e8SDoug Rabson krb5_error_code ret;
619c19800e8SDoug Rabson Checksum cksum;
620c19800e8SDoug Rabson
621ae771770SStanislav Sedov /* If the checksum is HMAC-MD5, the checksum type is not tied to
622ae771770SStanislav Sedov * the key type, instead the HMAC-MD5 checksum is applied blindly
623ae771770SStanislav Sedov * on whatever key is used for this connection, avoiding issues
624ae771770SStanislav Sedov * with unkeyed checksums on des-cbc-md5 and des-cbc-crc. See
625ae771770SStanislav Sedov * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
626ae771770SStanislav Sedov * for the same issue in MIT, and
627ae771770SStanislav Sedov * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
628ae771770SStanislav Sedov * for Microsoft's explaination */
629ae771770SStanislav Sedov
630ae771770SStanislav Sedov if (cksumtype == (uint32_t)CKSUMTYPE_HMAC_MD5) {
631ae771770SStanislav Sedov ret = HMAC_MD5_any_checksum(context, key, data, datalen,
632ae771770SStanislav Sedov KRB5_KU_OTHER_CKSUM, &cksum);
633ae771770SStanislav Sedov } else {
634c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto);
635c19800e8SDoug Rabson if (ret)
636c19800e8SDoug Rabson return ret;
637c19800e8SDoug Rabson
638c19800e8SDoug Rabson ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0,
639c19800e8SDoug Rabson data, datalen, &cksum);
640c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto);
641c19800e8SDoug Rabson if (ret)
642c19800e8SDoug Rabson return ret;
643ae771770SStanislav Sedov }
644c19800e8SDoug Rabson if (cksum.checksum.length != siglen) {
645ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "pac checksum wrong length");
646c19800e8SDoug Rabson free_Checksum(&cksum);
647c19800e8SDoug Rabson return EINVAL;
648c19800e8SDoug Rabson }
649c19800e8SDoug Rabson
650c19800e8SDoug Rabson memcpy(sig, cksum.checksum.data, siglen);
651c19800e8SDoug Rabson free_Checksum(&cksum);
652c19800e8SDoug Rabson
653c19800e8SDoug Rabson return 0;
654c19800e8SDoug Rabson }
655c19800e8SDoug Rabson
656c19800e8SDoug Rabson
657c19800e8SDoug Rabson /*
658c19800e8SDoug Rabson *
659c19800e8SDoug Rabson */
660c19800e8SDoug Rabson
661c19800e8SDoug Rabson #define NTTIME_EPOCH 0x019DB1DED53E8000LL
662c19800e8SDoug Rabson
663c19800e8SDoug Rabson static uint64_t
unix2nttime(time_t unix_time)664c19800e8SDoug Rabson unix2nttime(time_t unix_time)
665c19800e8SDoug Rabson {
666c19800e8SDoug Rabson long long wt;
667c19800e8SDoug Rabson wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
668c19800e8SDoug Rabson return wt;
669c19800e8SDoug Rabson }
670c19800e8SDoug Rabson
671c19800e8SDoug Rabson static krb5_error_code
verify_logonname(krb5_context context,const struct PAC_INFO_BUFFER * logon_name,const krb5_data * data,time_t authtime,krb5_const_principal principal)672c19800e8SDoug Rabson verify_logonname(krb5_context context,
673c19800e8SDoug Rabson const struct PAC_INFO_BUFFER *logon_name,
674c19800e8SDoug Rabson const krb5_data *data,
675c19800e8SDoug Rabson time_t authtime,
676c19800e8SDoug Rabson krb5_const_principal principal)
677c19800e8SDoug Rabson {
678c19800e8SDoug Rabson krb5_error_code ret;
679c19800e8SDoug Rabson krb5_principal p2;
680c19800e8SDoug Rabson uint32_t time1, time2;
681c19800e8SDoug Rabson krb5_storage *sp;
682c19800e8SDoug Rabson uint16_t len;
683c19800e8SDoug Rabson char *s;
684c19800e8SDoug Rabson
685c19800e8SDoug Rabson sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
686c19800e8SDoug Rabson logon_name->buffersize);
687ae771770SStanislav Sedov if (sp == NULL)
688ae771770SStanislav Sedov return krb5_enomem(context);
689c19800e8SDoug Rabson
690c19800e8SDoug Rabson krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
691c19800e8SDoug Rabson
692c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &time1), out);
693c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint32(sp, &time2), out);
694c19800e8SDoug Rabson
695c19800e8SDoug Rabson {
696c19800e8SDoug Rabson uint64_t t1, t2;
697c19800e8SDoug Rabson t1 = unix2nttime(authtime);
698c19800e8SDoug Rabson t2 = ((uint64_t)time2 << 32) | time1;
699c19800e8SDoug Rabson if (t1 != t2) {
700c19800e8SDoug Rabson krb5_storage_free(sp);
701ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch");
702c19800e8SDoug Rabson return EINVAL;
703c19800e8SDoug Rabson }
704c19800e8SDoug Rabson }
705c19800e8SDoug Rabson CHECK(ret, krb5_ret_uint16(sp, &len), out);
706c19800e8SDoug Rabson if (len == 0) {
707c19800e8SDoug Rabson krb5_storage_free(sp);
708ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "PAC logon name length missing");
709c19800e8SDoug Rabson return EINVAL;
710c19800e8SDoug Rabson }
711c19800e8SDoug Rabson
712c19800e8SDoug Rabson s = malloc(len);
713c19800e8SDoug Rabson if (s == NULL) {
714c19800e8SDoug Rabson krb5_storage_free(sp);
715ae771770SStanislav Sedov return krb5_enomem(context);
716c19800e8SDoug Rabson }
717c19800e8SDoug Rabson ret = krb5_storage_read(sp, s, len);
718c19800e8SDoug Rabson if (ret != len) {
719c19800e8SDoug Rabson krb5_storage_free(sp);
720ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name");
721c19800e8SDoug Rabson return EINVAL;
722c19800e8SDoug Rabson }
723c19800e8SDoug Rabson krb5_storage_free(sp);
724c19800e8SDoug Rabson {
725ae771770SStanislav Sedov size_t ucs2len = len / 2;
726c19800e8SDoug Rabson uint16_t *ucs2;
727c19800e8SDoug Rabson size_t u8len;
728ae771770SStanislav Sedov unsigned int flags = WIND_RW_LE;
729c19800e8SDoug Rabson
730ae771770SStanislav Sedov ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
731ae771770SStanislav Sedov if (ucs2 == NULL)
732ae771770SStanislav Sedov return krb5_enomem(context);
733ae771770SStanislav Sedov
734ae771770SStanislav Sedov ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
735c19800e8SDoug Rabson free(s);
736ae771770SStanislav Sedov if (ret) {
737c19800e8SDoug Rabson free(ucs2);
738ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
739ae771770SStanislav Sedov return ret;
740c19800e8SDoug Rabson }
741ae771770SStanislav Sedov ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
742ae771770SStanislav Sedov if (ret) {
743ae771770SStanislav Sedov free(ucs2);
744ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string");
745ae771770SStanislav Sedov return ret;
746ae771770SStanislav Sedov }
747ae771770SStanislav Sedov u8len += 1; /* Add space for NUL */
748ae771770SStanislav Sedov s = malloc(u8len);
749ae771770SStanislav Sedov if (s == NULL) {
750ae771770SStanislav Sedov free(ucs2);
751ae771770SStanislav Sedov return krb5_enomem(context);
752ae771770SStanislav Sedov }
753ae771770SStanislav Sedov ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len);
754ae771770SStanislav Sedov free(ucs2);
755ae771770SStanislav Sedov if (ret) {
756ae771770SStanislav Sedov free(s);
757ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
758ae771770SStanislav Sedov return ret;
759ae771770SStanislav Sedov }
760ae771770SStanislav Sedov }
761c19800e8SDoug Rabson ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
762c19800e8SDoug Rabson free(s);
763c19800e8SDoug Rabson if (ret)
764c19800e8SDoug Rabson return ret;
765c19800e8SDoug Rabson
766c19800e8SDoug Rabson if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) {
767c19800e8SDoug Rabson ret = EINVAL;
768ae771770SStanislav Sedov krb5_set_error_message(context, ret, "PAC logon name mismatch");
769c19800e8SDoug Rabson }
770c19800e8SDoug Rabson krb5_free_principal(context, p2);
771c19800e8SDoug Rabson return ret;
772c19800e8SDoug Rabson out:
773c19800e8SDoug Rabson return ret;
774c19800e8SDoug Rabson }
775c19800e8SDoug Rabson
776c19800e8SDoug Rabson /*
777c19800e8SDoug Rabson *
778c19800e8SDoug Rabson */
779c19800e8SDoug Rabson
780c19800e8SDoug Rabson static krb5_error_code
build_logon_name(krb5_context context,time_t authtime,krb5_const_principal principal,krb5_data * logon)781c19800e8SDoug Rabson build_logon_name(krb5_context context,
782c19800e8SDoug Rabson time_t authtime,
783c19800e8SDoug Rabson krb5_const_principal principal,
784c19800e8SDoug Rabson krb5_data *logon)
785c19800e8SDoug Rabson {
786c19800e8SDoug Rabson krb5_error_code ret;
787c19800e8SDoug Rabson krb5_storage *sp;
788c19800e8SDoug Rabson uint64_t t;
789c19800e8SDoug Rabson char *s, *s2;
790cf771f22SStanislav Sedov size_t s2_len;
791c19800e8SDoug Rabson
792c19800e8SDoug Rabson t = unix2nttime(authtime);
793c19800e8SDoug Rabson
794c19800e8SDoug Rabson krb5_data_zero(logon);
795c19800e8SDoug Rabson
796c19800e8SDoug Rabson sp = krb5_storage_emem();
797ae771770SStanislav Sedov if (sp == NULL)
798ae771770SStanislav Sedov return krb5_enomem(context);
799ae771770SStanislav Sedov
800c19800e8SDoug Rabson krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
801c19800e8SDoug Rabson
802c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out);
803c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, t >> 32), out);
804c19800e8SDoug Rabson
805c19800e8SDoug Rabson ret = krb5_unparse_name_flags(context, principal,
806c19800e8SDoug Rabson KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s);
807c19800e8SDoug Rabson if (ret)
808c19800e8SDoug Rabson goto out;
809c19800e8SDoug Rabson
810cf771f22SStanislav Sedov {
811cf771f22SStanislav Sedov size_t ucs2_len;
812cf771f22SStanislav Sedov uint16_t *ucs2;
813cf771f22SStanislav Sedov unsigned int flags;
814c19800e8SDoug Rabson
815cf771f22SStanislav Sedov ret = wind_utf8ucs2_length(s, &ucs2_len);
816cf771f22SStanislav Sedov if (ret) {
817c19800e8SDoug Rabson free(s);
818cf771f22SStanislav Sedov krb5_set_error_message(context, ret, "Failed to count length of UTF-8 string");
819cf771f22SStanislav Sedov return ret;
820c19800e8SDoug Rabson }
821c19800e8SDoug Rabson
822cf771f22SStanislav Sedov ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
823cf771f22SStanislav Sedov if (ucs2 == NULL) {
824cf771f22SStanislav Sedov free(s);
825cf771f22SStanislav Sedov return krb5_enomem(context);
826cf771f22SStanislav Sedov }
827cf771f22SStanislav Sedov
828cf771f22SStanislav Sedov ret = wind_utf8ucs2(s, ucs2, &ucs2_len);
829cf771f22SStanislav Sedov free(s);
830cf771f22SStanislav Sedov if (ret) {
831cf771f22SStanislav Sedov free(ucs2);
832cf771f22SStanislav Sedov krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
833cf771f22SStanislav Sedov return ret;
834cf771f22SStanislav Sedov }
835cf771f22SStanislav Sedov
836cf771f22SStanislav Sedov s2_len = (ucs2_len + 1) * 2;
837cf771f22SStanislav Sedov s2 = malloc(s2_len);
838cf771f22SStanislav Sedov if (ucs2 == NULL) {
839cf771f22SStanislav Sedov free(ucs2);
840cf771f22SStanislav Sedov return krb5_enomem(context);
841cf771f22SStanislav Sedov }
842cf771f22SStanislav Sedov
843cf771f22SStanislav Sedov flags = WIND_RW_LE;
844cf771f22SStanislav Sedov ret = wind_ucs2write(ucs2, ucs2_len,
845cf771f22SStanislav Sedov &flags, s2, &s2_len);
846cf771f22SStanislav Sedov free(ucs2);
847cf771f22SStanislav Sedov if (ret) {
848c19800e8SDoug Rabson free(s2);
849cf771f22SStanislav Sedov krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer");
850cf771f22SStanislav Sedov return ret;
851cf771f22SStanislav Sedov }
852cf771f22SStanislav Sedov
853cf771f22SStanislav Sedov /*
854cf771f22SStanislav Sedov * we do not want zero termination
855cf771f22SStanislav Sedov */
856cf771f22SStanislav Sedov s2_len = ucs2_len * 2;
857cf771f22SStanislav Sedov }
858cf771f22SStanislav Sedov
859cf771f22SStanislav Sedov CHECK(ret, krb5_store_uint16(sp, s2_len), out);
860cf771f22SStanislav Sedov
861cf771f22SStanislav Sedov ret = krb5_storage_write(sp, s2, s2_len);
862cf771f22SStanislav Sedov free(s2);
863cf771f22SStanislav Sedov if (ret != (int)s2_len) {
864ae771770SStanislav Sedov ret = krb5_enomem(context);
865c19800e8SDoug Rabson goto out;
866c19800e8SDoug Rabson }
867c19800e8SDoug Rabson ret = krb5_storage_to_data(sp, logon);
868c19800e8SDoug Rabson if (ret)
869c19800e8SDoug Rabson goto out;
870c19800e8SDoug Rabson krb5_storage_free(sp);
871c19800e8SDoug Rabson
872c19800e8SDoug Rabson return 0;
873c19800e8SDoug Rabson out:
874c19800e8SDoug Rabson krb5_storage_free(sp);
875c19800e8SDoug Rabson return ret;
876c19800e8SDoug Rabson }
877c19800e8SDoug Rabson
878c19800e8SDoug Rabson
879ae771770SStanislav Sedov /**
880ae771770SStanislav Sedov * Verify the PAC.
881c19800e8SDoug Rabson *
882ae771770SStanislav Sedov * @param context Kerberos 5 context.
883ae771770SStanislav Sedov * @param pac the pac structure returned by krb5_pac_parse().
884ae771770SStanislav Sedov * @param authtime The time of the ticket the PAC belongs to.
885ae771770SStanislav Sedov * @param principal the principal to verify.
886ae771770SStanislav Sedov * @param server The service key, most always be given.
887ae771770SStanislav Sedov * @param privsvr The KDC key, may be given.
888ae771770SStanislav Sedov
889ae771770SStanislav Sedov * @return Returns 0 to indicate success. Otherwise an kerberos et
890ae771770SStanislav Sedov * error code is returned, see krb5_get_error_message().
891ae771770SStanislav Sedov *
892ae771770SStanislav Sedov * @ingroup krb5_pac
893c19800e8SDoug Rabson */
894c19800e8SDoug Rabson
895ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_verify(krb5_context context,const krb5_pac pac,time_t authtime,krb5_const_principal principal,const krb5_keyblock * server,const krb5_keyblock * privsvr)896c19800e8SDoug Rabson krb5_pac_verify(krb5_context context,
897c19800e8SDoug Rabson const krb5_pac pac,
898c19800e8SDoug Rabson time_t authtime,
899c19800e8SDoug Rabson krb5_const_principal principal,
900c19800e8SDoug Rabson const krb5_keyblock *server,
901c19800e8SDoug Rabson const krb5_keyblock *privsvr)
902c19800e8SDoug Rabson {
903c19800e8SDoug Rabson krb5_error_code ret;
904c19800e8SDoug Rabson
905c19800e8SDoug Rabson if (pac->server_checksum == NULL) {
906ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "PAC missing server checksum");
907c19800e8SDoug Rabson return EINVAL;
908c19800e8SDoug Rabson }
909c19800e8SDoug Rabson if (pac->privsvr_checksum == NULL) {
910ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "PAC missing kdc checksum");
911c19800e8SDoug Rabson return EINVAL;
912c19800e8SDoug Rabson }
913c19800e8SDoug Rabson if (pac->logon_name == NULL) {
914ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "PAC missing logon name");
915c19800e8SDoug Rabson return EINVAL;
916c19800e8SDoug Rabson }
917c19800e8SDoug Rabson
918c19800e8SDoug Rabson ret = verify_logonname(context,
919c19800e8SDoug Rabson pac->logon_name,
920c19800e8SDoug Rabson &pac->data,
921c19800e8SDoug Rabson authtime,
922c19800e8SDoug Rabson principal);
923c19800e8SDoug Rabson if (ret)
924c19800e8SDoug Rabson return ret;
925c19800e8SDoug Rabson
926c19800e8SDoug Rabson /*
927c19800e8SDoug Rabson * in the service case, clean out data option of the privsvr and
928c19800e8SDoug Rabson * server checksum before checking the checksum.
929c19800e8SDoug Rabson */
930c19800e8SDoug Rabson {
931c19800e8SDoug Rabson krb5_data *copy;
932c19800e8SDoug Rabson
933c19800e8SDoug Rabson ret = krb5_copy_data(context, &pac->data, ©);
934c19800e8SDoug Rabson if (ret)
935c19800e8SDoug Rabson return ret;
936c19800e8SDoug Rabson
937c19800e8SDoug Rabson if (pac->server_checksum->buffersize < 4)
938c19800e8SDoug Rabson return EINVAL;
939c19800e8SDoug Rabson if (pac->privsvr_checksum->buffersize < 4)
940c19800e8SDoug Rabson return EINVAL;
941c19800e8SDoug Rabson
942c19800e8SDoug Rabson memset((char *)copy->data + pac->server_checksum->offset_lo + 4,
943c19800e8SDoug Rabson 0,
944c19800e8SDoug Rabson pac->server_checksum->buffersize - 4);
945c19800e8SDoug Rabson
946c19800e8SDoug Rabson memset((char *)copy->data + pac->privsvr_checksum->offset_lo + 4,
947c19800e8SDoug Rabson 0,
948c19800e8SDoug Rabson pac->privsvr_checksum->buffersize - 4);
949c19800e8SDoug Rabson
950c19800e8SDoug Rabson ret = verify_checksum(context,
951c19800e8SDoug Rabson pac->server_checksum,
952c19800e8SDoug Rabson &pac->data,
953c19800e8SDoug Rabson copy->data,
954c19800e8SDoug Rabson copy->length,
955c19800e8SDoug Rabson server);
956c19800e8SDoug Rabson krb5_free_data(context, copy);
957c19800e8SDoug Rabson if (ret)
958c19800e8SDoug Rabson return ret;
959c19800e8SDoug Rabson }
960c19800e8SDoug Rabson if (privsvr) {
961ae771770SStanislav Sedov /* The priv checksum covers the server checksum */
962c19800e8SDoug Rabson ret = verify_checksum(context,
963c19800e8SDoug Rabson pac->privsvr_checksum,
964c19800e8SDoug Rabson &pac->data,
965c19800e8SDoug Rabson (char *)pac->data.data
966c19800e8SDoug Rabson + pac->server_checksum->offset_lo + 4,
967c19800e8SDoug Rabson pac->server_checksum->buffersize - 4,
968c19800e8SDoug Rabson privsvr);
969c19800e8SDoug Rabson if (ret)
970c19800e8SDoug Rabson return ret;
971c19800e8SDoug Rabson }
972c19800e8SDoug Rabson
973c19800e8SDoug Rabson return 0;
974c19800e8SDoug Rabson }
975c19800e8SDoug Rabson
976c19800e8SDoug Rabson /*
977c19800e8SDoug Rabson *
978c19800e8SDoug Rabson */
979c19800e8SDoug Rabson
980c19800e8SDoug Rabson static krb5_error_code
fill_zeros(krb5_context context,krb5_storage * sp,size_t len)981c19800e8SDoug Rabson fill_zeros(krb5_context context, krb5_storage *sp, size_t len)
982c19800e8SDoug Rabson {
983c19800e8SDoug Rabson ssize_t sret;
984c19800e8SDoug Rabson size_t l;
985c19800e8SDoug Rabson
986c19800e8SDoug Rabson while (len) {
987c19800e8SDoug Rabson l = len;
988c19800e8SDoug Rabson if (l > sizeof(zeros))
989c19800e8SDoug Rabson l = sizeof(zeros);
990c19800e8SDoug Rabson sret = krb5_storage_write(sp, zeros, l);
991ae771770SStanislav Sedov if (sret <= 0)
992ae771770SStanislav Sedov return krb5_enomem(context);
993ae771770SStanislav Sedov
994c19800e8SDoug Rabson len -= sret;
995c19800e8SDoug Rabson }
996c19800e8SDoug Rabson return 0;
997c19800e8SDoug Rabson }
998c19800e8SDoug Rabson
999c19800e8SDoug Rabson static krb5_error_code
pac_checksum(krb5_context context,const krb5_keyblock * key,uint32_t * cksumtype,size_t * cksumsize)1000c19800e8SDoug Rabson pac_checksum(krb5_context context,
1001c19800e8SDoug Rabson const krb5_keyblock *key,
1002c19800e8SDoug Rabson uint32_t *cksumtype,
1003c19800e8SDoug Rabson size_t *cksumsize)
1004c19800e8SDoug Rabson {
1005c19800e8SDoug Rabson krb5_cksumtype cktype;
1006c19800e8SDoug Rabson krb5_error_code ret;
1007c19800e8SDoug Rabson krb5_crypto crypto = NULL;
1008c19800e8SDoug Rabson
1009c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto);
1010c19800e8SDoug Rabson if (ret)
1011c19800e8SDoug Rabson return ret;
1012c19800e8SDoug Rabson
1013c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, crypto, &cktype);
1014ae771770SStanislav Sedov krb5_crypto_destroy(context, crypto);
1015c19800e8SDoug Rabson if (ret)
1016c19800e8SDoug Rabson return ret;
1017c19800e8SDoug Rabson
1018c19800e8SDoug Rabson if (krb5_checksum_is_keyed(context, cktype) == FALSE) {
1019ae771770SStanislav Sedov *cksumtype = CKSUMTYPE_HMAC_MD5;
1020ae771770SStanislav Sedov *cksumsize = 16;
1021c19800e8SDoug Rabson }
1022c19800e8SDoug Rabson
1023c19800e8SDoug Rabson ret = krb5_checksumsize(context, cktype, cksumsize);
1024c19800e8SDoug Rabson if (ret)
1025c19800e8SDoug Rabson return ret;
1026c19800e8SDoug Rabson
1027c19800e8SDoug Rabson *cksumtype = (uint32_t)cktype;
1028c19800e8SDoug Rabson
1029c19800e8SDoug Rabson return 0;
1030c19800e8SDoug Rabson }
1031c19800e8SDoug Rabson
1032c19800e8SDoug Rabson krb5_error_code
_krb5_pac_sign(krb5_context context,krb5_pac p,time_t authtime,krb5_principal principal,const krb5_keyblock * server_key,const krb5_keyblock * priv_key,krb5_data * data)1033c19800e8SDoug Rabson _krb5_pac_sign(krb5_context context,
1034c19800e8SDoug Rabson krb5_pac p,
1035c19800e8SDoug Rabson time_t authtime,
1036c19800e8SDoug Rabson krb5_principal principal,
1037c19800e8SDoug Rabson const krb5_keyblock *server_key,
1038c19800e8SDoug Rabson const krb5_keyblock *priv_key,
1039c19800e8SDoug Rabson krb5_data *data)
1040c19800e8SDoug Rabson {
1041c19800e8SDoug Rabson krb5_error_code ret;
1042c19800e8SDoug Rabson krb5_storage *sp = NULL, *spdata = NULL;
1043c19800e8SDoug Rabson uint32_t end;
1044c19800e8SDoug Rabson size_t server_size, priv_size;
1045c19800e8SDoug Rabson uint32_t server_offset = 0, priv_offset = 0;
1046c19800e8SDoug Rabson uint32_t server_cksumtype = 0, priv_cksumtype = 0;
1047*ed549cb0SCy Schubert uint32_t num = 0;
1048*ed549cb0SCy Schubert uint32_t i;
1049c19800e8SDoug Rabson krb5_data logon, d;
1050c19800e8SDoug Rabson
1051c19800e8SDoug Rabson krb5_data_zero(&logon);
1052c19800e8SDoug Rabson
1053c19800e8SDoug Rabson if (p->logon_name == NULL)
1054c19800e8SDoug Rabson num++;
1055c19800e8SDoug Rabson if (p->server_checksum == NULL)
1056c19800e8SDoug Rabson num++;
1057c19800e8SDoug Rabson if (p->privsvr_checksum == NULL)
1058c19800e8SDoug Rabson num++;
1059c19800e8SDoug Rabson
1060c19800e8SDoug Rabson if (num) {
1061c19800e8SDoug Rabson void *ptr;
1062*ed549cb0SCy Schubert uint32_t len;
1063c19800e8SDoug Rabson
1064*ed549cb0SCy Schubert if (p->pac->numbuffers > UINT32_MAX - num) {
1065*ed549cb0SCy Schubert ret = EINVAL;
1066*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
1067*ed549cb0SCy Schubert goto out;
1068*ed549cb0SCy Schubert }
1069*ed549cb0SCy Schubert ret = pac_header_size(context, p->pac->numbuffers + num, &len);
1070*ed549cb0SCy Schubert if (ret)
1071*ed549cb0SCy Schubert goto out;
1072*ed549cb0SCy Schubert
1073*ed549cb0SCy Schubert ptr = realloc(p->pac, len);
1074ae771770SStanislav Sedov if (ptr == NULL)
1075ae771770SStanislav Sedov return krb5_enomem(context);
1076ae771770SStanislav Sedov
1077c19800e8SDoug Rabson p->pac = ptr;
1078c19800e8SDoug Rabson
1079c19800e8SDoug Rabson if (p->logon_name == NULL) {
1080c19800e8SDoug Rabson p->logon_name = &p->pac->buffers[p->pac->numbuffers++];
1081c19800e8SDoug Rabson memset(p->logon_name, 0, sizeof(*p->logon_name));
1082c19800e8SDoug Rabson p->logon_name->type = PAC_LOGON_NAME;
1083c19800e8SDoug Rabson }
1084c19800e8SDoug Rabson if (p->server_checksum == NULL) {
1085c19800e8SDoug Rabson p->server_checksum = &p->pac->buffers[p->pac->numbuffers++];
1086c19800e8SDoug Rabson memset(p->server_checksum, 0, sizeof(*p->server_checksum));
1087c19800e8SDoug Rabson p->server_checksum->type = PAC_SERVER_CHECKSUM;
1088c19800e8SDoug Rabson }
1089c19800e8SDoug Rabson if (p->privsvr_checksum == NULL) {
1090c19800e8SDoug Rabson p->privsvr_checksum = &p->pac->buffers[p->pac->numbuffers++];
1091c19800e8SDoug Rabson memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum));
1092c19800e8SDoug Rabson p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM;
1093c19800e8SDoug Rabson }
1094c19800e8SDoug Rabson }
1095c19800e8SDoug Rabson
1096c19800e8SDoug Rabson /* Calculate LOGON NAME */
1097c19800e8SDoug Rabson ret = build_logon_name(context, authtime, principal, &logon);
1098c19800e8SDoug Rabson if (ret)
1099c19800e8SDoug Rabson goto out;
1100c19800e8SDoug Rabson
1101c19800e8SDoug Rabson /* Set lengths for checksum */
1102c19800e8SDoug Rabson ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
1103c19800e8SDoug Rabson if (ret)
1104c19800e8SDoug Rabson goto out;
1105c19800e8SDoug Rabson ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
1106c19800e8SDoug Rabson if (ret)
1107c19800e8SDoug Rabson goto out;
1108c19800e8SDoug Rabson
1109c19800e8SDoug Rabson /* Encode PAC */
1110c19800e8SDoug Rabson sp = krb5_storage_emem();
1111ae771770SStanislav Sedov if (sp == NULL)
1112ae771770SStanislav Sedov return krb5_enomem(context);
1113ae771770SStanislav Sedov
1114c19800e8SDoug Rabson krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
1115c19800e8SDoug Rabson
1116c19800e8SDoug Rabson spdata = krb5_storage_emem();
1117c19800e8SDoug Rabson if (spdata == NULL) {
1118c19800e8SDoug Rabson krb5_storage_free(sp);
1119ae771770SStanislav Sedov return krb5_enomem(context);
1120c19800e8SDoug Rabson }
1121c19800e8SDoug Rabson krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE);
1122c19800e8SDoug Rabson
1123c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out);
1124c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, p->pac->version), out);
1125c19800e8SDoug Rabson
1126*ed549cb0SCy Schubert ret = pac_header_size(context, p->pac->numbuffers, &end);
1127*ed549cb0SCy Schubert if (ret)
1128*ed549cb0SCy Schubert goto out;
1129c19800e8SDoug Rabson
1130c19800e8SDoug Rabson for (i = 0; i < p->pac->numbuffers; i++) {
1131c19800e8SDoug Rabson uint32_t len;
1132c19800e8SDoug Rabson size_t sret;
1133c19800e8SDoug Rabson void *ptr = NULL;
1134c19800e8SDoug Rabson
1135c19800e8SDoug Rabson /* store data */
1136c19800e8SDoug Rabson
1137c19800e8SDoug Rabson if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
1138*ed549cb0SCy Schubert if (server_size > UINT32_MAX - 4) {
1139*ed549cb0SCy Schubert ret = EINVAL;
1140*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
1141*ed549cb0SCy Schubert goto out;
1142*ed549cb0SCy Schubert }
1143*ed549cb0SCy Schubert if (end > UINT32_MAX - 4) {
1144*ed549cb0SCy Schubert ret = EINVAL;
1145*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
1146*ed549cb0SCy Schubert goto out;
1147*ed549cb0SCy Schubert }
1148c19800e8SDoug Rabson len = server_size + 4;
1149c19800e8SDoug Rabson server_offset = end + 4;
1150c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(spdata, server_cksumtype), out);
1151c19800e8SDoug Rabson CHECK(ret, fill_zeros(context, spdata, server_size), out);
1152c19800e8SDoug Rabson } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
1153*ed549cb0SCy Schubert if (priv_size > UINT32_MAX - 4) {
1154*ed549cb0SCy Schubert ret = EINVAL;
1155*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
1156*ed549cb0SCy Schubert goto out;
1157*ed549cb0SCy Schubert }
1158*ed549cb0SCy Schubert if (end > UINT32_MAX - 4) {
1159*ed549cb0SCy Schubert ret = EINVAL;
1160*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
1161*ed549cb0SCy Schubert goto out;
1162*ed549cb0SCy Schubert }
1163c19800e8SDoug Rabson len = priv_size + 4;
1164c19800e8SDoug Rabson priv_offset = end + 4;
1165c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
1166c19800e8SDoug Rabson CHECK(ret, fill_zeros(context, spdata, priv_size), out);
1167c19800e8SDoug Rabson } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
1168c19800e8SDoug Rabson len = krb5_storage_write(spdata, logon.data, logon.length);
1169c19800e8SDoug Rabson if (logon.length != len) {
1170c19800e8SDoug Rabson ret = EINVAL;
1171c19800e8SDoug Rabson goto out;
1172c19800e8SDoug Rabson }
1173c19800e8SDoug Rabson } else {
1174c19800e8SDoug Rabson len = p->pac->buffers[i].buffersize;
1175c19800e8SDoug Rabson ptr = (char *)p->data.data + p->pac->buffers[i].offset_lo;
1176c19800e8SDoug Rabson
1177c19800e8SDoug Rabson sret = krb5_storage_write(spdata, ptr, len);
1178c19800e8SDoug Rabson if (sret != len) {
1179ae771770SStanislav Sedov ret = krb5_enomem(context);
1180c19800e8SDoug Rabson goto out;
1181c19800e8SDoug Rabson }
1182c19800e8SDoug Rabson /* XXX if not aligned, fill_zeros */
1183c19800e8SDoug Rabson }
1184c19800e8SDoug Rabson
1185c19800e8SDoug Rabson /* write header */
1186c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, p->pac->buffers[i].type), out);
1187c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, len), out);
1188c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, end), out);
1189c19800e8SDoug Rabson CHECK(ret, krb5_store_uint32(sp, 0), out);
1190c19800e8SDoug Rabson
1191c19800e8SDoug Rabson /* advance data endpointer and align */
1192c19800e8SDoug Rabson {
1193*ed549cb0SCy Schubert uint32_t e;
1194c19800e8SDoug Rabson
1195*ed549cb0SCy Schubert if (end > UINT32_MAX - len) {
1196*ed549cb0SCy Schubert ret = EINVAL;
1197*ed549cb0SCy Schubert krb5_set_error_message(context, ret, "integer overrun");
1198*ed549cb0SCy Schubert goto out;
1199*ed549cb0SCy Schubert }
1200c19800e8SDoug Rabson end += len;
1201*ed549cb0SCy Schubert
1202*ed549cb0SCy Schubert ret = pac_aligned_size(context, end, &e);
1203*ed549cb0SCy Schubert if (ret)
1204*ed549cb0SCy Schubert goto out;
1205*ed549cb0SCy Schubert
1206*ed549cb0SCy Schubert if (end != e) {
1207c19800e8SDoug Rabson CHECK(ret, fill_zeros(context, spdata, e - end), out);
1208c19800e8SDoug Rabson }
1209c19800e8SDoug Rabson end = e;
1210c19800e8SDoug Rabson }
1211c19800e8SDoug Rabson
1212c19800e8SDoug Rabson }
1213c19800e8SDoug Rabson
1214c19800e8SDoug Rabson /* assert (server_offset != 0 && priv_offset != 0); */
1215c19800e8SDoug Rabson
1216c19800e8SDoug Rabson /* export PAC */
1217c19800e8SDoug Rabson ret = krb5_storage_to_data(spdata, &d);
1218c19800e8SDoug Rabson if (ret) {
1219ae771770SStanislav Sedov krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1220c19800e8SDoug Rabson goto out;
1221c19800e8SDoug Rabson }
1222c19800e8SDoug Rabson ret = krb5_storage_write(sp, d.data, d.length);
1223ae771770SStanislav Sedov if (ret != (int)d.length) {
1224c19800e8SDoug Rabson krb5_data_free(&d);
1225ae771770SStanislav Sedov ret = krb5_enomem(context);
1226c19800e8SDoug Rabson goto out;
1227c19800e8SDoug Rabson }
1228c19800e8SDoug Rabson krb5_data_free(&d);
1229c19800e8SDoug Rabson
1230c19800e8SDoug Rabson ret = krb5_storage_to_data(sp, &d);
1231c19800e8SDoug Rabson if (ret) {
1232ae771770SStanislav Sedov ret = krb5_enomem(context);
1233c19800e8SDoug Rabson goto out;
1234c19800e8SDoug Rabson }
1235c19800e8SDoug Rabson
1236c19800e8SDoug Rabson /* sign */
1237ae771770SStanislav Sedov ret = create_checksum(context, server_key, server_cksumtype,
1238c19800e8SDoug Rabson d.data, d.length,
1239c19800e8SDoug Rabson (char *)d.data + server_offset, server_size);
1240c19800e8SDoug Rabson if (ret) {
1241c19800e8SDoug Rabson krb5_data_free(&d);
1242c19800e8SDoug Rabson goto out;
1243c19800e8SDoug Rabson }
1244ae771770SStanislav Sedov ret = create_checksum(context, priv_key, priv_cksumtype,
1245c19800e8SDoug Rabson (char *)d.data + server_offset, server_size,
1246c19800e8SDoug Rabson (char *)d.data + priv_offset, priv_size);
1247c19800e8SDoug Rabson if (ret) {
1248c19800e8SDoug Rabson krb5_data_free(&d);
1249c19800e8SDoug Rabson goto out;
1250c19800e8SDoug Rabson }
1251c19800e8SDoug Rabson
1252c19800e8SDoug Rabson /* done */
1253c19800e8SDoug Rabson *data = d;
1254c19800e8SDoug Rabson
1255c19800e8SDoug Rabson krb5_data_free(&logon);
1256c19800e8SDoug Rabson krb5_storage_free(sp);
1257c19800e8SDoug Rabson krb5_storage_free(spdata);
1258c19800e8SDoug Rabson
1259c19800e8SDoug Rabson return 0;
1260c19800e8SDoug Rabson out:
1261c19800e8SDoug Rabson krb5_data_free(&logon);
1262c19800e8SDoug Rabson if (sp)
1263c19800e8SDoug Rabson krb5_storage_free(sp);
1264c19800e8SDoug Rabson if (spdata)
1265c19800e8SDoug Rabson krb5_storage_free(spdata);
1266c19800e8SDoug Rabson return ret;
1267c19800e8SDoug Rabson }
1268