2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
7 * Copyright 2008 by the Massachusetts Institute of Technology.
10 * Export of this software from the United States of America may
11 * require a specific license from the United States Government.
12 * It is the responsibility of any person or organization contemplating
13 * export to obtain such a license before exporting.
15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
16 * distribute this software and its documentation for any purpose and
17 * without fee is hereby granted, provided that the above copyright
18 * notice appear in all copies and that both that copyright notice and
19 * this permission notice appear in supporting documentation, and that
20 * the name of M.I.T. not be used in advertising or publicity pertaining
21 * to distribution of the software without specific, written prior
22 * permission. Furthermore if you modify this software you must label
23 * your software as modified software and not distribute it in such a
24 * fashion that it might be confused with the original M.I.T. software.
25 * M.I.T. makes no representations about the suitability of
26 * this software for any purpose. It is provided "as is" without express
27 * or implied warranty.
34 /* draft-brezak-win2k-krb-authz-00 */
37 * A PAC consists of a sequence of PAC_INFO_BUFFERs, preceeded by
38 * a PACTYPE header. Decoding the contents of the buffers is left
39 * to the application (notwithstanding signature verification).
44 * These should eventually go to k5-platform.h or equiv.
46 static inline unsigned short
47 load_16_le (const void *cvp
)
49 const unsigned char *p
= cvp
;
50 #if defined(__GNUC__) && defined(K5_LE)
52 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
53 return GETSWAPPED(16,p
);
55 return (p
[0] | (p
[1] << 8));
59 static inline unsigned int
60 load_32_le (const void *cvp
)
62 const unsigned char *p
= cvp
;
63 #if defined(__GNUC__) && defined(K5_LE)
65 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
66 return GETSWAPPED(32,p
);
68 return (p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24));
71 static inline UINT64_TYPE
72 load_64_le (const void *cvp
)
74 const unsigned char *p
= cvp
;
75 #if defined(__GNUC__) && defined(K5_LE)
77 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
78 return GETSWAPPED(64,p
);
80 return ((UINT64_TYPE
)load_32_le(p
+4) << 32) | load_32_le(p
);
85 store_16_le (unsigned int val
, void *vp
)
87 unsigned char *p
= vp
;
88 #if defined(__GNUC__) && defined(K5_LE)
90 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
93 p
[1] = (val
>> 8) & 0xff;
99 store_32_le (unsigned int val
, void *vp
)
101 unsigned char *p
= vp
;
102 #if defined(__GNUC__) && defined(K5_LE)
104 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
105 PUTSWAPPED(32,p
,val
);
107 p
[3] = (val
>> 24) & 0xff;
108 p
[2] = (val
>> 16) & 0xff;
109 p
[1] = (val
>> 8) & 0xff;
110 p
[0] = (val
) & 0xff;
114 store_64_le (UINT64_TYPE val
, void *vp
)
116 unsigned char *p
= vp
;
117 #if defined(__GNUC__) && defined(K5_LE)
119 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
120 PUTSWAPPED(64,p
,val
);
122 p
[7] = (unsigned char)((val
>> 56) & 0xff);
123 p
[6] = (unsigned char)((val
>> 48) & 0xff);
124 p
[5] = (unsigned char)((val
>> 40) & 0xff);
125 p
[4] = (unsigned char)((val
>> 32) & 0xff);
126 p
[3] = (unsigned char)((val
>> 24) & 0xff);
127 p
[2] = (unsigned char)((val
>> 16) & 0xff);
128 p
[1] = (unsigned char)((val
>> 8) & 0xff);
129 p
[0] = (unsigned char)((val
) & 0xff);
134 typedef struct _PAC_INFO_BUFFER
{
136 krb5_ui_4 cbBufferSize
;
140 #define PAC_INFO_BUFFER_LENGTH 16
143 #define PAC_LOGON_INFO 1
144 #define PAC_SERVER_CHECKSUM 6
145 #define PAC_PRIVSVR_CHECKSUM 7
146 #define PAC_CLIENT_INFO 10
148 typedef struct _PACTYPE
{
151 PAC_INFO_BUFFER Buffers
[1];
154 #define PAC_ALIGNMENT 8
155 #define PACTYPE_LENGTH 8U
156 #define PAC_SIGNATURE_DATA_LENGTH 4U
157 #define PAC_CLIENT_INFO_LENGTH 10U
159 #define NT_TIME_EPOCH 11644473600LL
161 struct krb5_pac_data
{
162 PACTYPE
*pac
; /* PAC header + info buffer array */
163 krb5_data data
; /* PAC data (including uninitialised header) */
166 static krb5_error_code
167 k5_pac_locate_buffer(krb5_context context
,
173 * Add a buffer to the provided PAC and update header.
175 static krb5_error_code
176 k5_pac_add_buffer(krb5_context context
,
179 const krb5_data
*data
,
180 krb5_boolean zerofill
,
184 size_t header_len
, i
, pad
= 0;
187 assert((data
->data
== NULL
) == zerofill
);
189 /* Check there isn't already a buffer of this type */
190 if (k5_pac_locate_buffer(context
, pac
, type
, NULL
) == 0) {
191 /* Solaris Kerberos */
192 krb5_set_error_message(context
, EINVAL
,
193 "Duplicate PAC buffer of type %d",
198 header
= (PACTYPE
*)realloc(pac
->pac
,
200 (pac
->pac
->cBuffers
* sizeof(PAC_INFO_BUFFER
)));
201 if (header
== NULL
) {
206 header_len
= PACTYPE_LENGTH
+ (pac
->pac
->cBuffers
* PAC_INFO_BUFFER_LENGTH
);
208 if (data
->length
% PAC_ALIGNMENT
)
209 pad
= PAC_ALIGNMENT
- (data
->length
% PAC_ALIGNMENT
);
211 pac_data
= realloc(pac
->data
.data
,
212 pac
->data
.length
+ PAC_INFO_BUFFER_LENGTH
+ data
->length
+ pad
);
213 if (pac_data
== NULL
) {
216 pac
->data
.data
= pac_data
;
218 /* Update offsets of existing buffers */
219 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++)
220 pac
->pac
->Buffers
[i
].Offset
+= PAC_INFO_BUFFER_LENGTH
;
222 /* Make room for new PAC_INFO_BUFFER */
223 memmove(pac
->data
.data
+ header_len
+ PAC_INFO_BUFFER_LENGTH
,
224 pac
->data
.data
+ header_len
,
225 pac
->data
.length
- header_len
);
226 memset(pac
->data
.data
+ header_len
, 0, PAC_INFO_BUFFER_LENGTH
);
228 /* Initialise new PAC_INFO_BUFFER */
229 pac
->pac
->Buffers
[i
].ulType
= type
;
230 pac
->pac
->Buffers
[i
].cbBufferSize
= data
->length
;
231 pac
->pac
->Buffers
[i
].Offset
= pac
->data
.length
+ PAC_INFO_BUFFER_LENGTH
;
232 assert((pac
->pac
->Buffers
[i
].Offset
% PAC_ALIGNMENT
) == 0);
234 /* Copy in new PAC data and zero padding bytes */
236 memset(pac
->data
.data
+ pac
->pac
->Buffers
[i
].Offset
, 0, data
->length
);
238 memcpy(pac
->data
.data
+ pac
->pac
->Buffers
[i
].Offset
, data
->data
, data
->length
);
240 memset(pac
->data
.data
+ pac
->pac
->Buffers
[i
].Offset
+ data
->length
, 0, pad
);
242 pac
->pac
->cBuffers
++;
243 pac
->data
.length
+= PAC_INFO_BUFFER_LENGTH
+ data
->length
+ pad
;
245 if (out_data
!= NULL
) {
246 out_data
->data
= pac
->data
.data
+ pac
->pac
->Buffers
[i
].Offset
;
247 out_data
->length
= data
->length
;
253 krb5_error_code KRB5_CALLCONV
254 krb5_pac_add_buffer(krb5_context context
,
257 const krb5_data
*data
)
259 return k5_pac_add_buffer(context
, pac
, type
, data
, FALSE
, NULL
);
266 krb5_pac_free(krb5_context context
,
270 if (pac
->data
.data
!= NULL
) {
271 memset(pac
->data
.data
, 0, pac
->data
.length
);
272 free(pac
->data
.data
);
274 if (pac
->pac
!= NULL
)
276 memset(pac
, 0, sizeof(*pac
));
281 static krb5_error_code
282 k5_pac_locate_buffer(krb5_context context
,
287 PAC_INFO_BUFFER
*buffer
= NULL
;
291 /* Solaris Kerberos */
292 krb5_set_error_message(context
, EINVAL
,
293 "Invalid argument 'pac' is NULL");
297 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
298 if (pac
->pac
->Buffers
[i
].ulType
== type
) {
300 buffer
= &pac
->pac
->Buffers
[i
];
302 /* Solaris Kerberos */
303 krb5_set_error_message(context
, EINVAL
,
304 "Invalid buffer found looping thru PAC buffers (type=%d, i=%d)",
311 if (buffer
== NULL
) {
312 /* Solaris Kerberos */
313 krb5_set_error_message(context
, ENOENT
,
314 "No PAC buffer found (type=%d)",
320 assert(buffer
->Offset
+ buffer
->cbBufferSize
<= pac
->data
.length
);
323 data
->length
= buffer
->cbBufferSize
;
324 data
->data
= pac
->data
.data
+ buffer
->Offset
;
331 * Find a buffer and copy data into output
333 krb5_error_code KRB5_CALLCONV
334 krb5_pac_get_buffer(krb5_context context
,
342 ret
= k5_pac_locate_buffer(context
, pac
, type
, &d
);
346 data
->data
= malloc(d
.length
);
347 if (data
->data
== NULL
)
350 data
->length
= d
.length
;
351 memcpy(data
->data
, d
.data
, d
.length
);
357 * Return an array of the types of data in the PAC
359 krb5_error_code KRB5_CALLCONV
360 krb5_pac_get_types(krb5_context context
,
367 *types
= (krb5_ui_4
*)malloc(pac
->pac
->cBuffers
* sizeof(krb5_ui_4
));
371 *len
= pac
->pac
->cBuffers
;
373 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++)
374 (*types
)[i
] = pac
->pac
->Buffers
[i
].ulType
;
382 krb5_error_code KRB5_CALLCONV
383 krb5_pac_init(krb5_context context
,
388 pac
= (krb5_pac
)malloc(sizeof(*pac
));
392 pac
->pac
= (PACTYPE
*)malloc(sizeof(PACTYPE
));
393 if (pac
->pac
== NULL
) {
398 pac
->pac
->cBuffers
= 0;
399 pac
->pac
->Version
= 0;
401 pac
->data
.length
= PACTYPE_LENGTH
;
402 pac
->data
.data
= calloc(1, pac
->data
.length
);
403 if (pac
->data
.data
== NULL
) {
404 krb5_pac_free(context
, pac
);
414 * Parse the supplied data into the PAC allocated by this function
416 krb5_error_code KRB5_CALLCONV
417 krb5_pac_parse(krb5_context context
,
424 const unsigned char *p
= (const unsigned char *)ptr
;
427 krb5_ui_4 cbuffers
, version
;
431 if (len
< PACTYPE_LENGTH
) {
432 /* Solaris Kerberos */
433 krb5_set_error_message(context
, ERANGE
,
434 "PAC type length is out of range (len=%d)",
439 cbuffers
= load_32_le(p
);
441 version
= load_32_le(p
);
445 /* Solaris Kerberos */
446 krb5_set_error_message(context
, EINVAL
,
447 "Invalid PAC version is %d, should be 0",
452 header_len
= PACTYPE_LENGTH
+ (cbuffers
* PAC_INFO_BUFFER_LENGTH
);
453 if (len
< header_len
) {
454 /* Solaris Kerberos */
455 krb5_set_error_message(context
, ERANGE
,
456 "PAC header len (%d) out of range",
461 ret
= krb5_pac_init(context
, &pac
);
465 pac
->pac
= (PACTYPE
*)realloc(pac
->pac
,
466 sizeof(PACTYPE
) + ((cbuffers
- 1) * sizeof(PAC_INFO_BUFFER
)));
467 if (pac
->pac
== NULL
) {
468 krb5_pac_free(context
, pac
);
472 pac
->pac
->cBuffers
= cbuffers
;
473 pac
->pac
->Version
= version
;
475 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
476 PAC_INFO_BUFFER
*buffer
= &pac
->pac
->Buffers
[i
];
478 buffer
->ulType
= load_32_le(p
);
480 buffer
->cbBufferSize
= load_32_le(p
);
482 buffer
->Offset
= load_64_le(p
);
485 if (buffer
->Offset
% PAC_ALIGNMENT
) {
486 krb5_pac_free(context
, pac
);
487 /* Solaris Kerberos */
488 krb5_set_error_message(context
, EINVAL
,
489 "PAC buffer offset mis-aligned");
492 if (buffer
->Offset
< header_len
||
493 buffer
->Offset
+ buffer
->cbBufferSize
> len
) {
494 krb5_pac_free(context
, pac
);
495 /* Solaris Kerberos */
496 krb5_set_error_message(context
, ERANGE
,
497 "PAC offset is out of range");
502 pac
->data
.data
= realloc(pac
->data
.data
, len
);
503 if (pac
->data
.data
== NULL
) {
504 krb5_pac_free(context
, pac
);
507 memcpy(pac
->data
.data
, ptr
, len
);
509 pac
->data
.length
= len
;
516 static krb5_error_code
517 k5_time_to_seconds_since_1970(krb5_context context
, krb5_int64 ntTime
, krb5_timestamp
*elapsedSeconds
)
523 abstime
= ntTime
> 0 ? ntTime
- NT_TIME_EPOCH
: -ntTime
;
525 if (abstime
> KRB5_INT32_MAX
) {
529 *elapsedSeconds
= abstime
;
534 static krb5_error_code
535 k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds
, krb5_ui_8
*ntTime
)
537 *ntTime
= elapsedSeconds
;
539 if (elapsedSeconds
> 0)
540 *ntTime
+= NT_TIME_EPOCH
;
547 static krb5_error_code
548 k5_pac_validate_client(krb5_context context
,
550 krb5_timestamp authtime
,
551 krb5_const_principal principal
)
554 krb5_data client_info
;
557 krb5_timestamp pac_authtime
;
558 krb5_ui_2 pac_princname_length
;
559 krb5_int64 pac_nt_authtime
;
560 krb5_principal pac_principal
;
562 ret
= k5_pac_locate_buffer(context
, pac
, PAC_CLIENT_INFO
, &client_info
);
566 if (client_info
.length
< PAC_CLIENT_INFO_LENGTH
) {
567 /* Solaris Kerberos */
568 krb5_set_error_message(context
, ERANGE
,
569 "PAC client info length out of range",
574 p
= (unsigned char *)client_info
.data
;
575 pac_nt_authtime
= load_64_le(p
);
577 pac_princname_length
= load_16_le(p
);
580 ret
= k5_time_to_seconds_since_1970(context
, pac_nt_authtime
, &pac_authtime
);
584 if (client_info
.length
< PAC_CLIENT_INFO_LENGTH
+ pac_princname_length
||
585 pac_princname_length
% 2) {
586 /* Solaris Kerberos */
587 krb5_set_error_message(context
, ERANGE
,
588 "PAC client info length is out of range");
592 ret
= krb5int_ucs2lecs_to_utf8s(p
, (size_t)pac_princname_length
/ 2, &pac_princname
, NULL
);
596 ret
= krb5_parse_name_flags(context
, pac_princname
, 0, &pac_principal
);
603 if (pac_authtime
!= authtime
) {
604 /* Solaris Kerberos */
606 char pac_timestring
[17];
609 /* Need better ret code here but don't see one */
610 ret
= KRB5KRB_AP_WRONG_PRINC
;
611 err
= krb5_timestamp_to_sfstring(pac_authtime
,
613 sizeof (timestring
), &fill
);
614 pac_err
= krb5_timestamp_to_sfstring(pac_authtime
,
616 sizeof (pac_timestring
), &fill
);
617 if (pac_princname
&& !err
&& !pac_err
) {
618 krb5_set_error_message(context
, ret
,
619 "PAC verify fail: PAC authtime '%s' does not match authtime '%s'. PAC principal is '%s'",
620 pac_timestring
, timestring
, pac_princname
);
622 } else if (krb5_principal_compare(context
, pac_principal
, principal
) == FALSE
) {
623 /* Solaris Kerberos */
625 krb5_error_code perr
;
626 ret
= KRB5KRB_AP_WRONG_PRINC
;
627 perr
= krb5_unparse_name(context
, principal
, &p_name
);
628 if (pac_princname
&& !perr
) {
629 krb5_set_error_message(context
, ret
,
630 "Wrong principal in request: PAC verify: Principal in PAC is '%s' and does not match '%s'",
631 pac_princname
, p_name
);
634 krb5_free_unparsed_name(context
, p_name
);
638 krb5_free_principal(context
, pac_principal
);
643 static krb5_error_code
644 k5_pac_zero_signature(krb5_context context
,
649 PAC_INFO_BUFFER
*buffer
= NULL
;
652 assert(type
== PAC_SERVER_CHECKSUM
|| type
== PAC_PRIVSVR_CHECKSUM
);
653 assert(data
->length
>= pac
->data
.length
);
655 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
656 if (pac
->pac
->Buffers
[i
].ulType
== type
) {
657 buffer
= &pac
->pac
->Buffers
[i
];
662 if (buffer
== NULL
) {
663 /* Solaris Kerberos */
664 krb5_set_error_message(context
, ENOENT
,
665 "No PAC buffer found (type=%d)",
670 if (buffer
->Offset
+ buffer
->cbBufferSize
> pac
->data
.length
) {
674 if (buffer
->cbBufferSize
< PAC_SIGNATURE_DATA_LENGTH
) {
675 return KRB5_BAD_MSIZE
;
678 /* Zero out the data portion of the checksum only */
679 memset(data
->data
+ buffer
->Offset
+ PAC_SIGNATURE_DATA_LENGTH
,
681 buffer
->cbBufferSize
- PAC_SIGNATURE_DATA_LENGTH
);
686 static krb5_error_code
687 k5_pac_verify_server_checksum(krb5_context context
,
689 const krb5_keyblock
*server
)
692 krb5_data pac_data
; /* PAC with zeroed checksums */
693 krb5_checksum checksum
;
694 krb5_data checksum_data
;
698 ret
= k5_pac_locate_buffer(context
, pac
, PAC_SERVER_CHECKSUM
, &checksum_data
);
702 if (checksum_data
.length
< PAC_SIGNATURE_DATA_LENGTH
) {
703 return KRB5_BAD_MSIZE
;
706 p
= (krb5_octet
*)checksum_data
.data
;
707 checksum
.checksum_type
= load_32_le(p
);
708 checksum
.length
= checksum_data
.length
- PAC_SIGNATURE_DATA_LENGTH
;
709 checksum
.contents
= p
+ PAC_SIGNATURE_DATA_LENGTH
;
711 pac_data
.length
= pac
->data
.length
;
712 pac_data
.data
= malloc(pac
->data
.length
);
713 if (pac_data
.data
== NULL
)
716 memcpy(pac_data
.data
, pac
->data
.data
, pac
->data
.length
);
718 /* Zero out both checksum buffers */
719 ret
= k5_pac_zero_signature(context
, pac
, PAC_SERVER_CHECKSUM
, &pac_data
);
725 ret
= k5_pac_zero_signature(context
, pac
, PAC_PRIVSVR_CHECKSUM
, &pac_data
);
731 ret
= krb5_c_verify_checksum(context
, server
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
732 &pac_data
, &checksum
, &valid
);
738 if (valid
== FALSE
) {
739 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
;
740 /* Solaris Kerberos */
741 krb5_set_error_message(context
, ret
,
742 "Decrypt integrity check failed for PAC");
745 free(pac_data
.data
); /* SUNW17PACresync - mem leak fix */
749 static krb5_error_code
750 k5_pac_verify_kdc_checksum(krb5_context context
,
752 const krb5_keyblock
*privsvr
)
755 krb5_data server_checksum
, privsvr_checksum
;
756 krb5_checksum checksum
;
760 ret
= k5_pac_locate_buffer(context
, pac
, PAC_PRIVSVR_CHECKSUM
, &privsvr_checksum
);
764 if (privsvr_checksum
.length
< PAC_SIGNATURE_DATA_LENGTH
) {
765 return KRB5_BAD_MSIZE
;
768 ret
= k5_pac_locate_buffer(context
, pac
, PAC_SERVER_CHECKSUM
, &server_checksum
);
772 if (server_checksum
.length
< PAC_SIGNATURE_DATA_LENGTH
) {
773 return KRB5_BAD_MSIZE
;
776 p
= (krb5_octet
*)privsvr_checksum
.data
;
777 checksum
.checksum_type
= load_32_le(p
);
778 checksum
.length
= privsvr_checksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
779 checksum
.contents
= p
+ PAC_SIGNATURE_DATA_LENGTH
;
781 server_checksum
.data
+= PAC_SIGNATURE_DATA_LENGTH
;
782 server_checksum
.length
-= PAC_SIGNATURE_DATA_LENGTH
;
784 ret
= krb5_c_verify_checksum(context
, privsvr
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
785 &server_checksum
, &checksum
, &valid
);
789 if (valid
== FALSE
) {
790 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
;
791 /* Solaris Kerberos */
792 krb5_set_error_message(context
, ret
,
793 "Decrypt integrity check failed for PAC");
799 krb5_error_code KRB5_CALLCONV
800 krb5_pac_verify(krb5_context context
,
802 krb5_timestamp authtime
,
803 krb5_const_principal principal
,
804 const krb5_keyblock
*server
,
805 const krb5_keyblock
*privsvr
)
809 if (server
== NULL
) {
813 ret
= k5_pac_verify_server_checksum(context
, pac
, server
);
817 if (privsvr
!= NULL
) {
818 ret
= k5_pac_verify_kdc_checksum(context
, pac
, privsvr
);
823 if (principal
!= NULL
) {
824 ret
= k5_pac_validate_client(context
, pac
, authtime
, principal
);
832 static krb5_error_code
833 k5_insert_client_info(krb5_context context
,
835 krb5_timestamp authtime
,
836 krb5_const_principal principal
)
839 krb5_data client_info
;
840 char *princ_name_utf8
= NULL
;
841 unsigned char *princ_name_ucs2
= NULL
, *p
;
842 size_t princ_name_ucs2_len
= 0;
843 krb5_ui_8 nt_authtime
;
845 /* If we already have a CLIENT_INFO buffer, then just validate it */
846 if (k5_pac_locate_buffer(context
, pac
, PAC_CLIENT_INFO
, &client_info
) == 0) {
847 return k5_pac_validate_client(context
, pac
, authtime
, principal
);
850 ret
= krb5_unparse_name_flags(context
, principal
,
851 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &princ_name_utf8
);
855 ret
= krb5int_utf8s_to_ucs2les(princ_name_utf8
,
857 &princ_name_ucs2_len
);
861 client_info
.length
= PAC_CLIENT_INFO_LENGTH
+ princ_name_ucs2_len
;
862 client_info
.data
= NULL
;
864 ret
= k5_pac_add_buffer(context
, pac
, PAC_CLIENT_INFO
, &client_info
, TRUE
, &client_info
);
868 p
= (unsigned char *)client_info
.data
;
870 /* copy in authtime converted to a 64-bit NT time */
871 k5_seconds_since_1970_to_time(authtime
, &nt_authtime
);
872 store_64_le(nt_authtime
, p
);
875 /* copy in number of UCS-2 characters in principal name */
876 store_16_le(princ_name_ucs2_len
, p
);
879 /* copy in principal name */
880 memcpy(p
, princ_name_ucs2
, princ_name_ucs2_len
);
883 if (princ_name_utf8
!= NULL
)
884 free(princ_name_utf8
);
885 if (princ_name_ucs2
!= NULL
)
886 free(princ_name_ucs2
);
891 static krb5_error_code
892 k5_insert_checksum(krb5_context context
,
895 const krb5_keyblock
*key
,
896 krb5_cksumtype
*cksumtype
)
902 ret
= krb5int_c_mandatory_cksumtype(context
, key
->enctype
, cksumtype
);
906 ret
= krb5_c_checksum_length(context
, *cksumtype
, &len
);
910 ret
= k5_pac_locate_buffer(context
, pac
, type
, &cksumdata
);
912 /* If we're resigning PAC, make sure we can fit checksum into existing buffer */
913 if (cksumdata
.length
!= PAC_SIGNATURE_DATA_LENGTH
+ len
) {
917 memset(cksumdata
.data
, 0, cksumdata
.length
);
919 /* Add a zero filled buffer */
920 cksumdata
.length
= PAC_SIGNATURE_DATA_LENGTH
+ len
;
921 cksumdata
.data
= NULL
;
923 ret
= k5_pac_add_buffer(context
, pac
, type
, &cksumdata
, TRUE
, &cksumdata
);
928 /* Encode checksum type into buffer */
929 store_32_le((krb5_ui_4
)*cksumtype
, cksumdata
.data
);
934 /* in-place encoding of PAC header */
935 static krb5_error_code
936 k5_pac_encode_header(krb5_context context
, krb5_pac pac
)
942 header_len
= PACTYPE_LENGTH
+ (pac
->pac
->cBuffers
* PAC_INFO_BUFFER_LENGTH
);
943 assert(pac
->data
.length
>= header_len
);
945 p
= (unsigned char *)pac
->data
.data
;
947 store_32_le(pac
->pac
->cBuffers
, p
);
949 store_32_le(pac
->pac
->Version
, p
);
952 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
953 PAC_INFO_BUFFER
*buffer
= &pac
->pac
->Buffers
[i
];
955 store_32_le(buffer
->ulType
, p
);
957 store_32_le(buffer
->cbBufferSize
, p
);
959 store_64_le(buffer
->Offset
, p
);
962 assert((buffer
->Offset
% PAC_ALIGNMENT
) == 0);
963 assert(buffer
->Offset
+ buffer
->cbBufferSize
<= pac
->data
.length
);
964 assert(buffer
->Offset
>= header_len
);
966 if (buffer
->Offset
% PAC_ALIGNMENT
||
967 buffer
->Offset
+ buffer
->cbBufferSize
> pac
->data
.length
||
968 buffer
->Offset
< header_len
) {
980 * We don't have the new MIT iov interfaces yet and don't need them yet.
981 * We'll need this for full 1.7 resync.
983 krb5_error_code KRB5_CALLCONV
984 krb5int_pac_sign(krb5_context context
,
986 krb5_timestamp authtime
,
987 krb5_const_principal principal
,
988 const krb5_keyblock
*server_key
,
989 const krb5_keyblock
*privsvr_key
,
993 krb5_data server_cksum
, privsvr_cksum
;
994 krb5_cksumtype server_cksumtype
, privsvr_cksumtype
;
995 krb5_crypto_iov iov
[2];
1000 if (principal
!= NULL
) {
1001 ret
= k5_insert_client_info(context
, pac
, authtime
, principal
);
1006 /* Create zeroed buffers for both checksums */
1007 ret
= k5_insert_checksum(context
, pac
, PAC_SERVER_CHECKSUM
,
1008 server_key
, &server_cksumtype
);
1012 ret
= k5_insert_checksum(context
, pac
, PAC_PRIVSVR_CHECKSUM
,
1013 privsvr_key
, &privsvr_cksumtype
);
1017 /* Now, encode the PAC header so that the checksums will include it */
1018 ret
= k5_pac_encode_header(context
, pac
);
1022 /* Generate the server checksum over the entire PAC */
1023 ret
= k5_pac_locate_buffer(context
, pac
, PAC_SERVER_CHECKSUM
, &server_cksum
);
1027 assert(server_cksum
.length
> PAC_SIGNATURE_DATA_LENGTH
);
1029 iov
[0].flags
= KRB5_CRYPTO_TYPE_DATA
;
1030 iov
[0].data
= pac
->data
;
1032 iov
[1].flags
= KRB5_CRYPTO_TYPE_CHECKSUM
;
1033 iov
[1].data
.data
= server_cksum
.data
+ PAC_SIGNATURE_DATA_LENGTH
;
1034 iov
[1].data
.length
= server_cksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
1036 ret
= krb5_c_make_checksum_iov(context
, server_cksumtype
,
1037 server_key
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
1038 iov
, sizeof(iov
)/sizeof(iov
[0]));
1042 /* Generate the privsvr checksum over the server checksum buffer */
1043 ret
= k5_pac_locate_buffer(context
, pac
, PAC_PRIVSVR_CHECKSUM
, &privsvr_cksum
);
1047 assert(privsvr_cksum
.length
> PAC_SIGNATURE_DATA_LENGTH
);
1049 iov
[0].flags
= KRB5_CRYPTO_TYPE_DATA
;
1050 iov
[0].data
.data
= server_cksum
.data
+ PAC_SIGNATURE_DATA_LENGTH
;
1051 iov
[0].data
.length
= server_cksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
1053 iov
[1].flags
= KRB5_CRYPTO_TYPE_CHECKSUM
;
1054 iov
[1].data
.data
= privsvr_cksum
.data
+ PAC_SIGNATURE_DATA_LENGTH
;
1055 iov
[1].data
.length
= privsvr_cksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
1057 ret
= krb5_c_make_checksum_iov(context
, privsvr_cksumtype
,
1058 privsvr_key
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
1059 iov
, sizeof(iov
)/sizeof(iov
[0]));
1063 data
->data
= malloc(pac
->data
.length
);
1064 if (data
->data
== NULL
)
1067 data
->length
= pac
->data
.length
;
1069 memcpy(data
->data
, pac
->data
.data
, pac
->data
.length
);
1070 memset(pac
->data
.data
, 0, PACTYPE_LENGTH
+ (pac
->pac
->cBuffers
* PAC_INFO_BUFFER_LENGTH
));