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
);
275 memset(pac
, 0, sizeof(*pac
));
280 static krb5_error_code
281 k5_pac_locate_buffer(krb5_context context
,
286 PAC_INFO_BUFFER
*buffer
= NULL
;
290 /* Solaris Kerberos */
291 krb5_set_error_message(context
, EINVAL
,
292 "Invalid argument 'pac' is NULL");
296 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
297 if (pac
->pac
->Buffers
[i
].ulType
== type
) {
299 buffer
= &pac
->pac
->Buffers
[i
];
301 /* Solaris Kerberos */
302 krb5_set_error_message(context
, EINVAL
,
303 "Invalid buffer found looping thru PAC buffers (type=%d, i=%d)",
310 if (buffer
== NULL
) {
311 /* Solaris Kerberos */
312 krb5_set_error_message(context
, ENOENT
,
313 "No PAC buffer found (type=%d)",
319 assert(buffer
->Offset
+ buffer
->cbBufferSize
<= pac
->data
.length
);
322 data
->length
= buffer
->cbBufferSize
;
323 data
->data
= pac
->data
.data
+ buffer
->Offset
;
330 * Find a buffer and copy data into output
332 krb5_error_code KRB5_CALLCONV
333 krb5_pac_get_buffer(krb5_context context
,
341 ret
= k5_pac_locate_buffer(context
, pac
, type
, &d
);
345 data
->data
= malloc(d
.length
);
346 if (data
->data
== NULL
)
349 data
->length
= d
.length
;
350 memcpy(data
->data
, d
.data
, d
.length
);
356 * Return an array of the types of data in the PAC
358 krb5_error_code KRB5_CALLCONV
359 krb5_pac_get_types(krb5_context context
,
366 *types
= (krb5_ui_4
*)malloc(pac
->pac
->cBuffers
* sizeof(krb5_ui_4
));
370 *len
= pac
->pac
->cBuffers
;
372 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++)
373 (*types
)[i
] = pac
->pac
->Buffers
[i
].ulType
;
381 krb5_error_code KRB5_CALLCONV
382 krb5_pac_init(krb5_context context
,
387 pac
= (krb5_pac
)malloc(sizeof(*pac
));
391 pac
->pac
= (PACTYPE
*)malloc(sizeof(PACTYPE
));
392 if (pac
->pac
== NULL
) {
397 pac
->pac
->cBuffers
= 0;
398 pac
->pac
->Version
= 0;
400 pac
->data
.length
= PACTYPE_LENGTH
;
401 pac
->data
.data
= calloc(1, pac
->data
.length
);
402 if (pac
->data
.data
== NULL
) {
403 krb5_pac_free(context
, pac
);
413 * Parse the supplied data into the PAC allocated by this function
415 krb5_error_code KRB5_CALLCONV
416 krb5_pac_parse(krb5_context context
,
423 const unsigned char *p
= (const unsigned char *)ptr
;
426 krb5_ui_4 cbuffers
, version
;
430 if (len
< PACTYPE_LENGTH
) {
431 /* Solaris Kerberos */
432 krb5_set_error_message(context
, ERANGE
,
433 "PAC type length is out of range (len=%d)",
438 cbuffers
= load_32_le(p
);
440 version
= load_32_le(p
);
444 /* Solaris Kerberos */
445 krb5_set_error_message(context
, EINVAL
,
446 "Invalid PAC version is %d, should be 0",
451 header_len
= PACTYPE_LENGTH
+ (cbuffers
* PAC_INFO_BUFFER_LENGTH
);
452 if (len
< header_len
) {
453 /* Solaris Kerberos */
454 krb5_set_error_message(context
, ERANGE
,
455 "PAC header len (%d) out of range",
460 ret
= krb5_pac_init(context
, &pac
);
464 pac
->pac
= (PACTYPE
*)realloc(pac
->pac
,
465 sizeof(PACTYPE
) + ((cbuffers
- 1) * sizeof(PAC_INFO_BUFFER
)));
466 if (pac
->pac
== NULL
) {
467 krb5_pac_free(context
, pac
);
471 pac
->pac
->cBuffers
= cbuffers
;
472 pac
->pac
->Version
= version
;
474 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
475 PAC_INFO_BUFFER
*buffer
= &pac
->pac
->Buffers
[i
];
477 buffer
->ulType
= load_32_le(p
);
479 buffer
->cbBufferSize
= load_32_le(p
);
481 buffer
->Offset
= load_64_le(p
);
484 if (buffer
->Offset
% PAC_ALIGNMENT
) {
485 krb5_pac_free(context
, pac
);
486 /* Solaris Kerberos */
487 krb5_set_error_message(context
, EINVAL
,
488 "PAC buffer offset mis-aligned");
491 if (buffer
->Offset
< header_len
||
492 buffer
->Offset
+ buffer
->cbBufferSize
> len
) {
493 krb5_pac_free(context
, pac
);
494 /* Solaris Kerberos */
495 krb5_set_error_message(context
, ERANGE
,
496 "PAC offset is out of range");
501 pac
->data
.data
= realloc(pac
->data
.data
, len
);
502 if (pac
->data
.data
== NULL
) {
503 krb5_pac_free(context
, pac
);
506 memcpy(pac
->data
.data
, ptr
, len
);
508 pac
->data
.length
= len
;
515 static krb5_error_code
516 k5_time_to_seconds_since_1970(krb5_context context
, krb5_int64 ntTime
, krb5_timestamp
*elapsedSeconds
)
522 abstime
= ntTime
> 0 ? ntTime
- NT_TIME_EPOCH
: -ntTime
;
524 if (abstime
> KRB5_INT32_MAX
) {
528 *elapsedSeconds
= abstime
;
533 static krb5_error_code
534 k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds
, krb5_ui_8
*ntTime
)
536 *ntTime
= elapsedSeconds
;
538 if (elapsedSeconds
> 0)
539 *ntTime
+= NT_TIME_EPOCH
;
546 static krb5_error_code
547 k5_pac_validate_client(krb5_context context
,
549 krb5_timestamp authtime
,
550 krb5_const_principal principal
)
553 krb5_data client_info
;
556 krb5_timestamp pac_authtime
;
557 krb5_ui_2 pac_princname_length
;
558 krb5_int64 pac_nt_authtime
;
559 krb5_principal pac_principal
;
561 ret
= k5_pac_locate_buffer(context
, pac
, PAC_CLIENT_INFO
, &client_info
);
565 if (client_info
.length
< PAC_CLIENT_INFO_LENGTH
) {
566 /* Solaris Kerberos */
567 krb5_set_error_message(context
, ERANGE
,
568 "PAC client info length out of range",
573 p
= (unsigned char *)client_info
.data
;
574 pac_nt_authtime
= load_64_le(p
);
576 pac_princname_length
= load_16_le(p
);
579 ret
= k5_time_to_seconds_since_1970(context
, pac_nt_authtime
, &pac_authtime
);
583 if (client_info
.length
< PAC_CLIENT_INFO_LENGTH
+ pac_princname_length
||
584 pac_princname_length
% 2) {
585 /* Solaris Kerberos */
586 krb5_set_error_message(context
, ERANGE
,
587 "PAC client info length is out of range");
591 ret
= krb5int_ucs2lecs_to_utf8s(p
, (size_t)pac_princname_length
/ 2, &pac_princname
, NULL
);
595 ret
= krb5_parse_name_flags(context
, pac_princname
, 0, &pac_principal
);
602 if (pac_authtime
!= authtime
) {
603 /* Solaris Kerberos */
605 char pac_timestring
[17];
608 /* Need better ret code here but don't see one */
609 ret
= KRB5KRB_AP_WRONG_PRINC
;
610 err
= krb5_timestamp_to_sfstring(pac_authtime
,
612 sizeof (timestring
), &fill
);
613 pac_err
= krb5_timestamp_to_sfstring(pac_authtime
,
615 sizeof (pac_timestring
), &fill
);
616 if (pac_princname
&& !err
&& !pac_err
) {
617 krb5_set_error_message(context
, ret
,
618 "PAC verify fail: PAC authtime '%s' does not match authtime '%s'. PAC principal is '%s'",
619 pac_timestring
, timestring
, pac_princname
);
621 } else if (krb5_principal_compare(context
, pac_principal
, principal
) == FALSE
) {
622 /* Solaris Kerberos */
624 krb5_error_code perr
;
625 ret
= KRB5KRB_AP_WRONG_PRINC
;
626 perr
= krb5_unparse_name(context
, principal
, &p_name
);
627 if (pac_princname
&& !perr
) {
628 krb5_set_error_message(context
, ret
,
629 "Wrong principal in request: PAC verify: Principal in PAC is '%s' and does not match '%s'",
630 pac_princname
, p_name
);
633 krb5_free_unparsed_name(context
, p_name
);
637 krb5_free_principal(context
, pac_principal
);
642 static krb5_error_code
643 k5_pac_zero_signature(krb5_context context
,
648 PAC_INFO_BUFFER
*buffer
= NULL
;
651 assert(type
== PAC_SERVER_CHECKSUM
|| type
== PAC_PRIVSVR_CHECKSUM
);
652 assert(data
->length
>= pac
->data
.length
);
654 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
655 if (pac
->pac
->Buffers
[i
].ulType
== type
) {
656 buffer
= &pac
->pac
->Buffers
[i
];
661 if (buffer
== NULL
) {
662 /* Solaris Kerberos */
663 krb5_set_error_message(context
, ENOENT
,
664 "No PAC buffer found (type=%d)",
669 if (buffer
->Offset
+ buffer
->cbBufferSize
> pac
->data
.length
) {
673 if (buffer
->cbBufferSize
< PAC_SIGNATURE_DATA_LENGTH
) {
674 return KRB5_BAD_MSIZE
;
677 /* Zero out the data portion of the checksum only */
678 memset(data
->data
+ buffer
->Offset
+ PAC_SIGNATURE_DATA_LENGTH
,
680 buffer
->cbBufferSize
- PAC_SIGNATURE_DATA_LENGTH
);
685 static krb5_error_code
686 k5_pac_verify_server_checksum(krb5_context context
,
688 const krb5_keyblock
*server
)
691 krb5_data pac_data
; /* PAC with zeroed checksums */
692 krb5_checksum checksum
;
693 krb5_data checksum_data
;
697 ret
= k5_pac_locate_buffer(context
, pac
, PAC_SERVER_CHECKSUM
, &checksum_data
);
701 if (checksum_data
.length
< PAC_SIGNATURE_DATA_LENGTH
) {
702 return KRB5_BAD_MSIZE
;
705 p
= (krb5_octet
*)checksum_data
.data
;
706 checksum
.checksum_type
= load_32_le(p
);
707 checksum
.length
= checksum_data
.length
- PAC_SIGNATURE_DATA_LENGTH
;
708 checksum
.contents
= p
+ PAC_SIGNATURE_DATA_LENGTH
;
710 pac_data
.length
= pac
->data
.length
;
711 pac_data
.data
= malloc(pac
->data
.length
);
712 if (pac_data
.data
== NULL
)
715 memcpy(pac_data
.data
, pac
->data
.data
, pac
->data
.length
);
717 /* Zero out both checksum buffers */
718 ret
= k5_pac_zero_signature(context
, pac
, PAC_SERVER_CHECKSUM
, &pac_data
);
724 ret
= k5_pac_zero_signature(context
, pac
, PAC_PRIVSVR_CHECKSUM
, &pac_data
);
730 ret
= krb5_c_verify_checksum(context
, server
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
731 &pac_data
, &checksum
, &valid
);
737 if (valid
== FALSE
) {
738 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
;
739 /* Solaris Kerberos */
740 krb5_set_error_message(context
, ret
,
741 "Decrypt integrity check failed for PAC");
744 free(pac_data
.data
); /* SUNW17PACresync - mem leak fix */
748 static krb5_error_code
749 k5_pac_verify_kdc_checksum(krb5_context context
,
751 const krb5_keyblock
*privsvr
)
754 krb5_data server_checksum
, privsvr_checksum
;
755 krb5_checksum checksum
;
759 ret
= k5_pac_locate_buffer(context
, pac
, PAC_PRIVSVR_CHECKSUM
, &privsvr_checksum
);
763 if (privsvr_checksum
.length
< PAC_SIGNATURE_DATA_LENGTH
) {
764 return KRB5_BAD_MSIZE
;
767 ret
= k5_pac_locate_buffer(context
, pac
, PAC_SERVER_CHECKSUM
, &server_checksum
);
771 if (server_checksum
.length
< PAC_SIGNATURE_DATA_LENGTH
) {
772 return KRB5_BAD_MSIZE
;
775 p
= (krb5_octet
*)privsvr_checksum
.data
;
776 checksum
.checksum_type
= load_32_le(p
);
777 checksum
.length
= privsvr_checksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
778 checksum
.contents
= p
+ PAC_SIGNATURE_DATA_LENGTH
;
780 server_checksum
.data
+= PAC_SIGNATURE_DATA_LENGTH
;
781 server_checksum
.length
-= PAC_SIGNATURE_DATA_LENGTH
;
783 ret
= krb5_c_verify_checksum(context
, privsvr
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
784 &server_checksum
, &checksum
, &valid
);
788 if (valid
== FALSE
) {
789 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
;
790 /* Solaris Kerberos */
791 krb5_set_error_message(context
, ret
,
792 "Decrypt integrity check failed for PAC");
798 krb5_error_code KRB5_CALLCONV
799 krb5_pac_verify(krb5_context context
,
801 krb5_timestamp authtime
,
802 krb5_const_principal principal
,
803 const krb5_keyblock
*server
,
804 const krb5_keyblock
*privsvr
)
808 if (server
== NULL
) {
812 ret
= k5_pac_verify_server_checksum(context
, pac
, server
);
816 if (privsvr
!= NULL
) {
817 ret
= k5_pac_verify_kdc_checksum(context
, pac
, privsvr
);
822 if (principal
!= NULL
) {
823 ret
= k5_pac_validate_client(context
, pac
, authtime
, principal
);
831 static krb5_error_code
832 k5_insert_client_info(krb5_context context
,
834 krb5_timestamp authtime
,
835 krb5_const_principal principal
)
838 krb5_data client_info
;
839 char *princ_name_utf8
= NULL
;
840 unsigned char *princ_name_ucs2
= NULL
, *p
;
841 size_t princ_name_ucs2_len
= 0;
842 krb5_ui_8 nt_authtime
;
844 /* If we already have a CLIENT_INFO buffer, then just validate it */
845 if (k5_pac_locate_buffer(context
, pac
, PAC_CLIENT_INFO
, &client_info
) == 0) {
846 return k5_pac_validate_client(context
, pac
, authtime
, principal
);
849 ret
= krb5_unparse_name_flags(context
, principal
,
850 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &princ_name_utf8
);
854 ret
= krb5int_utf8s_to_ucs2les(princ_name_utf8
,
856 &princ_name_ucs2_len
);
860 client_info
.length
= PAC_CLIENT_INFO_LENGTH
+ princ_name_ucs2_len
;
861 client_info
.data
= NULL
;
863 ret
= k5_pac_add_buffer(context
, pac
, PAC_CLIENT_INFO
, &client_info
, TRUE
, &client_info
);
867 p
= (unsigned char *)client_info
.data
;
869 /* copy in authtime converted to a 64-bit NT time */
870 k5_seconds_since_1970_to_time(authtime
, &nt_authtime
);
871 store_64_le(nt_authtime
, p
);
874 /* copy in number of UCS-2 characters in principal name */
875 store_16_le(princ_name_ucs2_len
, p
);
878 /* copy in principal name */
879 memcpy(p
, princ_name_ucs2
, princ_name_ucs2_len
);
882 free(princ_name_utf8
);
883 free(princ_name_ucs2
);
888 static krb5_error_code
889 k5_insert_checksum(krb5_context context
,
892 const krb5_keyblock
*key
,
893 krb5_cksumtype
*cksumtype
)
899 ret
= krb5int_c_mandatory_cksumtype(context
, key
->enctype
, cksumtype
);
903 ret
= krb5_c_checksum_length(context
, *cksumtype
, &len
);
907 ret
= k5_pac_locate_buffer(context
, pac
, type
, &cksumdata
);
909 /* If we're resigning PAC, make sure we can fit checksum into existing buffer */
910 if (cksumdata
.length
!= PAC_SIGNATURE_DATA_LENGTH
+ len
) {
914 memset(cksumdata
.data
, 0, cksumdata
.length
);
916 /* Add a zero filled buffer */
917 cksumdata
.length
= PAC_SIGNATURE_DATA_LENGTH
+ len
;
918 cksumdata
.data
= NULL
;
920 ret
= k5_pac_add_buffer(context
, pac
, type
, &cksumdata
, TRUE
, &cksumdata
);
925 /* Encode checksum type into buffer */
926 store_32_le((krb5_ui_4
)*cksumtype
, cksumdata
.data
);
931 /* in-place encoding of PAC header */
932 static krb5_error_code
933 k5_pac_encode_header(krb5_context context
, krb5_pac pac
)
939 header_len
= PACTYPE_LENGTH
+ (pac
->pac
->cBuffers
* PAC_INFO_BUFFER_LENGTH
);
940 assert(pac
->data
.length
>= header_len
);
942 p
= (unsigned char *)pac
->data
.data
;
944 store_32_le(pac
->pac
->cBuffers
, p
);
946 store_32_le(pac
->pac
->Version
, p
);
949 for (i
= 0; i
< pac
->pac
->cBuffers
; i
++) {
950 PAC_INFO_BUFFER
*buffer
= &pac
->pac
->Buffers
[i
];
952 store_32_le(buffer
->ulType
, p
);
954 store_32_le(buffer
->cbBufferSize
, p
);
956 store_64_le(buffer
->Offset
, p
);
959 assert((buffer
->Offset
% PAC_ALIGNMENT
) == 0);
960 assert(buffer
->Offset
+ buffer
->cbBufferSize
<= pac
->data
.length
);
961 assert(buffer
->Offset
>= header_len
);
963 if (buffer
->Offset
% PAC_ALIGNMENT
||
964 buffer
->Offset
+ buffer
->cbBufferSize
> pac
->data
.length
||
965 buffer
->Offset
< header_len
) {
977 * We don't have the new MIT iov interfaces yet and don't need them yet.
978 * We'll need this for full 1.7 resync.
980 krb5_error_code KRB5_CALLCONV
981 krb5int_pac_sign(krb5_context context
,
983 krb5_timestamp authtime
,
984 krb5_const_principal principal
,
985 const krb5_keyblock
*server_key
,
986 const krb5_keyblock
*privsvr_key
,
990 krb5_data server_cksum
, privsvr_cksum
;
991 krb5_cksumtype server_cksumtype
, privsvr_cksumtype
;
992 krb5_crypto_iov iov
[2];
997 if (principal
!= NULL
) {
998 ret
= k5_insert_client_info(context
, pac
, authtime
, principal
);
1003 /* Create zeroed buffers for both checksums */
1004 ret
= k5_insert_checksum(context
, pac
, PAC_SERVER_CHECKSUM
,
1005 server_key
, &server_cksumtype
);
1009 ret
= k5_insert_checksum(context
, pac
, PAC_PRIVSVR_CHECKSUM
,
1010 privsvr_key
, &privsvr_cksumtype
);
1014 /* Now, encode the PAC header so that the checksums will include it */
1015 ret
= k5_pac_encode_header(context
, pac
);
1019 /* Generate the server checksum over the entire PAC */
1020 ret
= k5_pac_locate_buffer(context
, pac
, PAC_SERVER_CHECKSUM
, &server_cksum
);
1024 assert(server_cksum
.length
> PAC_SIGNATURE_DATA_LENGTH
);
1026 iov
[0].flags
= KRB5_CRYPTO_TYPE_DATA
;
1027 iov
[0].data
= pac
->data
;
1029 iov
[1].flags
= KRB5_CRYPTO_TYPE_CHECKSUM
;
1030 iov
[1].data
.data
= server_cksum
.data
+ PAC_SIGNATURE_DATA_LENGTH
;
1031 iov
[1].data
.length
= server_cksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
1033 ret
= krb5_c_make_checksum_iov(context
, server_cksumtype
,
1034 server_key
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
1035 iov
, sizeof(iov
)/sizeof(iov
[0]));
1039 /* Generate the privsvr checksum over the server checksum buffer */
1040 ret
= k5_pac_locate_buffer(context
, pac
, PAC_PRIVSVR_CHECKSUM
, &privsvr_cksum
);
1044 assert(privsvr_cksum
.length
> PAC_SIGNATURE_DATA_LENGTH
);
1046 iov
[0].flags
= KRB5_CRYPTO_TYPE_DATA
;
1047 iov
[0].data
.data
= server_cksum
.data
+ PAC_SIGNATURE_DATA_LENGTH
;
1048 iov
[0].data
.length
= server_cksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
1050 iov
[1].flags
= KRB5_CRYPTO_TYPE_CHECKSUM
;
1051 iov
[1].data
.data
= privsvr_cksum
.data
+ PAC_SIGNATURE_DATA_LENGTH
;
1052 iov
[1].data
.length
= privsvr_cksum
.length
- PAC_SIGNATURE_DATA_LENGTH
;
1054 ret
= krb5_c_make_checksum_iov(context
, privsvr_cksumtype
,
1055 privsvr_key
, KRB5_KEYUSAGE_APP_DATA_CKSUM
,
1056 iov
, sizeof(iov
)/sizeof(iov
[0]));
1060 data
->data
= malloc(pac
->data
.length
);
1061 if (data
->data
== NULL
)
1064 data
->length
= pac
->data
.length
;
1066 memcpy(data
->data
, pac
->data
.data
, pac
->data
.length
);
1067 memset(pac
->data
.data
, 0, PACTYPE_LENGTH
+ (pac
->pac
->cBuffers
* PAC_INFO_BUFFER_LENGTH
));