diff --git a/libfsapfs/libfsapfs_key_encrypted_key.c b/libfsapfs/libfsapfs_key_encrypted_key.c index 00e0155..157f6ae 100644 --- a/libfsapfs/libfsapfs_key_encrypted_key.c +++ b/libfsapfs/libfsapfs_key_encrypted_key.c @@ -154,6 +154,9 @@ int libfsapfs_key_encrypted_key_read_data( const uint8_t *wrapped_kek_object_data = NULL; static char *function = "libfsapfs_key_encrypted_key_read_data"; size_t data_offset = 0; + size_t object_value_data_end = 0; + size_t wrapped_kek_object_header_size = 0; + uint16_t kek_metadata_value_data_size = 0; uint16_t value_data_size = 0; uint16_t wrapped_kek_object_data_size = 0; uint8_t byte_value = 0; @@ -220,16 +223,51 @@ int libfsapfs_key_encrypted_key_read_data( } else if( byte_value == 0x81 ) { + if( ( data_size - data_offset ) < 1 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid object extended value data size value out of bounds.", + function ); + + return( -1 ); + } value_data_size = (uint16_t) data[ data_offset++ ]; } else if( byte_value == 0x82 ) { - byte_stream_copy_to_uint16_little_endian( + if( ( data_size - data_offset ) < 2 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid object extended value data size value out of bounds.", + function ); + + return( -1 ); + } + byte_stream_copy_to_uint16_big_endian( &( data[ data_offset ] ), value_data_size ); data_offset += 2; } + if( value_data_size > ( data_size - data_offset ) ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid object value data size value out of bounds.", + function ); + + return( -1 ); + } + object_value_data_end = data_offset + value_data_size; + #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { @@ -278,19 +316,22 @@ int libfsapfs_key_encrypted_key_read_data( return( -1 ); } - if( value_data_size > ( data_size - 2 ) ) + /* The attributes are bound by the object value data, not by the data, + * so that trailing data is not parsed as an attribute. + */ + while( data_offset < object_value_data_end ) { - libcerror_error_set( - error, - LIBCERROR_ERROR_DOMAIN_RUNTIME, - LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, - "%s: invalid object value data size value out of bounds.", - function ); + if( ( object_value_data_end - data_offset ) < 2 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid attribute value data size value out of bounds.", + function ); - return( -1 ); - } - while( data_offset < data_size ) - { + return( -1 ); + } value_tag = data[ data_offset++ ]; byte_value = data[ data_offset++ ]; @@ -314,11 +355,33 @@ int libfsapfs_key_encrypted_key_read_data( } else if( byte_value == 0x81 ) { + if( ( object_value_data_end - data_offset ) < 1 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid attribute extended value data size value out of bounds.", + function ); + + return( -1 ); + } value_data_size = (uint16_t) data[ data_offset++ ]; } else if( byte_value == 0x82 ) { - byte_stream_copy_to_uint16_little_endian( + if( ( object_value_data_end - data_offset ) < 2 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid attribute extended value data size value out of bounds.", + function ); + + return( -1 ); + } + byte_stream_copy_to_uint16_big_endian( &( data[ data_offset ] ), value_data_size ); @@ -344,8 +407,7 @@ int libfsapfs_key_encrypted_key_read_data( { break; } - if( ( data_offset >= data_size ) - || ( value_data_size > ( data_size - data_offset ) ) ) + if( value_data_size > ( object_value_data_end - data_offset ) ) { libcerror_error_set( error, @@ -428,8 +490,24 @@ int libfsapfs_key_encrypted_key_read_data( return( -1 ); } - wrapped_kek_object_data = &( data[ data_offset - 2 ] ); - wrapped_kek_object_data_size = value_data_size + 2; + /* The wrapped KEK packed object is parsed from its own tag + * byte onwards, hence the size of the tag and length bytes + * needs to be determined. + */ + if( byte_value == 0x81 ) + { + wrapped_kek_object_header_size = 3; + } + else if( byte_value == 0x82 ) + { + wrapped_kek_object_header_size = 4; + } + else + { + wrapped_kek_object_header_size = 2; + } + wrapped_kek_object_data = &( data[ data_offset - wrapped_kek_object_header_size ] ); + wrapped_kek_object_data_size = (uint16_t) ( wrapped_kek_object_header_size + value_data_size ); break; @@ -455,6 +533,7 @@ int libfsapfs_key_encrypted_key_read_data( byte_value = wrapped_kek_object_data[ data_offset++ ]; if( ( ( byte_value & 0x80 ) != 0 ) + && ( byte_value != 0x81 ) && ( byte_value != 0x82 ) ) { libcerror_error_set( @@ -471,9 +550,13 @@ int libfsapfs_key_encrypted_key_read_data( { value_data_size = (uint16_t) byte_value; } + else if( byte_value == 0x81 ) + { + value_data_size = (uint16_t) wrapped_kek_object_data[ data_offset++ ]; + } else if( byte_value == 0x82 ) { - byte_stream_copy_to_uint16_little_endian( + byte_stream_copy_to_uint16_big_endian( &( wrapped_kek_object_data[ data_offset ] ), value_data_size ); @@ -538,12 +621,24 @@ int libfsapfs_key_encrypted_key_read_data( return( -1 ); } - while( data_offset < wrapped_kek_object_data_size ) + while( data_offset < (size_t) wrapped_kek_object_data_size ) { + if( ( (size_t) wrapped_kek_object_data_size - data_offset ) < 2 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid attribute value data size value out of bounds.", + function ); + + return( -1 ); + } value_tag = wrapped_kek_object_data[ data_offset++ ]; byte_value = wrapped_kek_object_data[ data_offset++ ]; if( ( ( byte_value & 0x80 ) != 0 ) + && ( byte_value != 0x81 ) && ( byte_value != 0x82 ) ) { libcerror_error_set( @@ -560,9 +655,35 @@ int libfsapfs_key_encrypted_key_read_data( { value_data_size = (uint16_t) byte_value; } + else if( byte_value == 0x81 ) + { + if( ( (size_t) wrapped_kek_object_data_size - data_offset ) < 1 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid attribute extended value data size value out of bounds.", + function ); + + return( -1 ); + } + value_data_size = (uint16_t) wrapped_kek_object_data[ data_offset++ ]; + } else if( byte_value == 0x82 ) { - byte_stream_copy_to_uint16_little_endian( + if( ( (size_t) wrapped_kek_object_data_size - data_offset ) < 2 ) + { + libcerror_error_set( + error, + LIBCERROR_ERROR_DOMAIN_RUNTIME, + LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, + "%s: invalid attribute extended value data size value out of bounds.", + function ); + + return( -1 ); + } + byte_stream_copy_to_uint16_big_endian( &( wrapped_kek_object_data[ data_offset ] ), value_data_size ); @@ -588,8 +709,7 @@ int libfsapfs_key_encrypted_key_read_data( { break; } - if( ( data_offset >= wrapped_kek_object_data_size ) - || ( value_data_size > ( wrapped_kek_object_data_size - data_offset ) ) ) + if( value_data_size > ( (size_t) wrapped_kek_object_data_size - data_offset ) ) { libcerror_error_set( error, @@ -672,7 +792,11 @@ int libfsapfs_key_encrypted_key_read_data( break; case 0x82: - if( value_data_size != 8 ) + /* macOS 26 grew this attribute from 8 bytes to 22 bytes, + * namely a 6-byte header followed by a 16-byte identifier. + */ + if( ( value_data_size != 8 ) + && ( value_data_size != 22 ) ) { libcerror_error_set( error, @@ -684,12 +808,22 @@ int libfsapfs_key_encrypted_key_read_data( return( -1 ); } - kek_metadata = (fsapfs_key_bag_kek_metadata_t *) &( wrapped_kek_object_data[ data_offset ] ); + kek_metadata_value_data_size = value_data_size; + kek_metadata = (fsapfs_key_bag_kek_metadata_t *) &( wrapped_kek_object_data[ data_offset ] ); byte_stream_copy_to_uint32_little_endian( kek_metadata->encryption_method, key_encrypted_key->encryption_method ); + /* In the 22-byte variant the first 4 bytes are not the + * encryption method. The 40-byte wrapped KEK corresponds with + * AES-256. + */ + if( value_data_size == 22 ) + { + key_encrypted_key->encryption_method = 0; + } + #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { @@ -753,8 +887,16 @@ int libfsapfs_key_encrypted_key_read_data( break; case 0x84: + /* A password-protected KEK entry stores a <= 8-byte PBKDF2 + * iteration count here. A macOS 26 container key bag VEK + * entry, which is unwrapped with a key instead of a password, + * carries a 16-byte value that is not an iteration count. The + * 22-byte KEK metadata attribute distinguishes the two, so + * that a corrupt legacy entry is still rejected. + */ if( ( value_data_size == 0 ) - || ( value_data_size > 8 ) ) + || ( ( value_data_size > 8 ) + && ( kek_metadata_value_data_size != 22 ) ) ) { libcerror_error_set( error, @@ -766,6 +908,10 @@ int libfsapfs_key_encrypted_key_read_data( return( -1 ); } + if( value_data_size > 8 ) + { + break; + } key_encrypted_key->number_of_iterations = 0; while( value_data_size > 0 ) @@ -780,7 +926,7 @@ int libfsapfs_key_encrypted_key_read_data( if( libcnotify_verbose != 0 ) { libcnotify_printf( - "%s: number of iterations\t\t: %" PRIu32 "\n", + "%s: number of iterations\t\t: %" PRIu64 "\n", function, key_encrypted_key->number_of_iterations ); @@ -792,7 +938,14 @@ int libfsapfs_key_encrypted_key_read_data( break; case 0x85: - if( value_data_size != 16 ) + /* A password-protected KEK entry stores a 16-byte PBKDF2 salt + * here. A macOS 26 container key bag VEK entry carries an + * unrelated 3-byte value that is not a salt. The 22-byte KEK + * metadata attribute distinguishes the two, so that a corrupt + * legacy entry is still rejected. + */ + if( ( value_data_size != 16 ) + && ( kek_metadata_value_data_size != 22 ) ) { libcerror_error_set( error, @@ -804,6 +957,10 @@ int libfsapfs_key_encrypted_key_read_data( return( -1 ); } + if( value_data_size != 16 ) + { + break; + } if( memory_copy( key_encrypted_key->salt, &( wrapped_kek_object_data[ data_offset ] ), diff --git a/tests/fsapfs_test_key_encrypted_key.c b/tests/fsapfs_test_key_encrypted_key.c index fe452db..36741dd 100644 --- a/tests/fsapfs_test_key_encrypted_key.c +++ b/tests/fsapfs_test_key_encrypted_key.c @@ -21,6 +21,7 @@ #include #include +#include #include #if defined( HAVE_STDLIB_H ) || defined( WINAPI ) @@ -37,6 +38,361 @@ #if defined( __GNUC__ ) && !defined( LIBFSAPFS_DLL_IMPORT ) +/* macOS 26 per-user KEK record (162 bytes) with a 22-byte keyblob[2] + * metadata attribute, captured from a disposable admin/admin VM. + */ +uint8_t fsapfs_test_key_encrypted_key_data1[ 162 ] = { + 0x30, 0x81, 0x9f, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x6e, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x16, 0x49, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x96, 0xd7, 0x25, 0xec, 0x34, 0xd8, 0x42, 0xac, 0x97, 0x64, 0xe4, 0x3f, 0x81, 0x80, 0x4f, + 0x57, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, 0xb6, 0xe6, + 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, 0x65, 0xe9, + 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x84, 0x03, 0x08, 0x89, 0x50, + 0x85, 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, 0x85, 0x38, + 0x43, 0x0e }; + +/* macOS 26 personal recovery key (PRK) KEK record (162 bytes) of the + * same container. A second, independent record with a 22-byte + * keyblob[2] metadata attribute, carrying the crypto user identifier + * Apple uses for the personal recovery key: + * EBC6C064-0000-11AA-AA11-00306543ECAC. + */ +uint8_t fsapfs_test_key_encrypted_key_data2[ 162 ] = { + 0x30, 0x81, 0x9f, 0x80, 0x01, 0x00, 0x81, 0x20, 0x5a, 0xb0, 0xa1, 0x4d, 0xbe, 0xbc, 0xdf, 0x6b, + 0xea, 0x99, 0xbf, 0x48, 0xe9, 0xcd, 0xd2, 0x5e, 0xfc, 0xf6, 0x3b, 0xed, 0xd0, 0x32, 0xfc, 0xe4, + 0x9a, 0x00, 0xc5, 0x5c, 0x42, 0x7d, 0x85, 0xfd, 0x82, 0x08, 0x8c, 0x69, 0xca, 0xc5, 0xec, 0xf6, + 0x3a, 0x99, 0xa3, 0x6e, 0x80, 0x01, 0x00, 0x81, 0x10, 0xeb, 0xc6, 0xc0, 0x64, 0x00, 0x00, 0x11, + 0xaa, 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac, 0x82, 0x16, 0x49, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x96, 0xd7, 0x25, 0xec, 0x34, 0xd8, 0x42, 0xac, 0x97, 0x64, 0xe4, 0x3f, 0x81, 0x80, 0x4f, + 0x57, 0x83, 0x28, 0xd1, 0x92, 0x75, 0xdf, 0x33, 0x8b, 0x1b, 0x76, 0x83, 0x6c, 0x09, 0xfa, 0x12, + 0x34, 0xb9, 0x35, 0x5d, 0x4f, 0xac, 0xee, 0xe2, 0x51, 0xd7, 0xf4, 0x54, 0x92, 0xac, 0x33, 0xe1, + 0xfd, 0x0d, 0xef, 0xae, 0xfd, 0x61, 0x4d, 0xb1, 0x43, 0xba, 0x65, 0x84, 0x03, 0x0a, 0x6b, 0x25, + 0x85, 0x10, 0xd8, 0x3c, 0x49, 0x3c, 0x5a, 0x10, 0x78, 0xdd, 0xc1, 0xe3, 0x6b, 0x3d, 0x4d, 0x37, + 0xdf, 0xa7 }; + +/* macOS 26 container key bag VEK entry (388 bytes): 2-byte long-form + * DER lengths on the outer SEQUENCE and the keyblob, a 22-byte + * metadata attribute, a 16-byte keyblob[4], a 3-byte keyblob[5] and + * additional keyblob[6], [7] and [8] attributes. + */ +uint8_t fsapfs_test_key_encrypted_key_data3[ 388 ] = { + 0x30, 0x82, 0x01, 0x80, 0x80, 0x01, 0x00, 0x81, 0x20, 0x73, 0x24, 0xfa, 0x3a, 0x90, 0xb7, 0x5a, + 0xe5, 0xc5, 0x55, 0x19, 0x3b, 0xac, 0xc1, 0x77, 0x00, 0x7c, 0x09, 0x69, 0xbd, 0x85, 0x12, 0x47, + 0xcf, 0xa9, 0x48, 0x24, 0xf2, 0x0f, 0xe4, 0xbb, 0x22, 0x82, 0x08, 0xee, 0x54, 0x57, 0x36, 0xc5, + 0x9b, 0x91, 0xb5, 0xa3, 0x82, 0x01, 0x4d, 0x80, 0x01, 0x00, 0x81, 0x10, 0x66, 0xeb, 0x31, 0xc4, + 0x19, 0x7c, 0x43, 0xa2, 0xb8, 0x33, 0xc5, 0x20, 0x52, 0x88, 0x4e, 0x9c, 0x82, 0x16, 0x29, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x96, 0xd7, 0x25, 0xec, 0x34, 0xd8, 0x42, 0xac, 0x97, 0x64, 0xe4, 0x3f, + 0x81, 0x80, 0x4f, 0x57, 0x83, 0x28, 0xd7, 0xec, 0xb1, 0xc0, 0x14, 0x0b, 0x97, 0x65, 0x88, 0x89, + 0xbb, 0xce, 0xe5, 0xf4, 0x1d, 0xee, 0x20, 0xeb, 0xd8, 0x9e, 0x48, 0x96, 0x0d, 0x7d, 0x3c, 0x00, + 0x28, 0xed, 0x1b, 0xe4, 0x9c, 0x44, 0xce, 0x8a, 0x1b, 0xbf, 0x17, 0x32, 0x4e, 0x3d, 0x84, 0x10, + 0x8b, 0x84, 0xc6, 0x38, 0xa6, 0x23, 0x48, 0xaa, 0x8e, 0x5e, 0x8d, 0x6d, 0x87, 0xff, 0x33, 0x89, + 0x85, 0x03, 0x35, 0xad, 0x36, 0x86, 0x10, 0xfa, 0x4f, 0xc6, 0xc0, 0x2a, 0x69, 0xe4, 0x71, 0xc2, + 0x97, 0xa3, 0xd8, 0xca, 0x9f, 0x6d, 0xdc, 0x87, 0x10, 0xd3, 0xc8, 0xb8, 0x78, 0x90, 0x9b, 0xa8, + 0x55, 0x11, 0xe0, 0x14, 0x77, 0x68, 0x52, 0x15, 0x26, 0x88, 0x81, 0xb8, 0x77, 0x91, 0x82, 0x20, + 0x68, 0x55, 0x87, 0x79, 0x79, 0x4b, 0x7c, 0xd2, 0x00, 0xf0, 0x71, 0x41, 0xe2, 0xea, 0x17, 0xa6, + 0x4c, 0x55, 0xbe, 0xa3, 0xbe, 0xb2, 0xee, 0x1b, 0x91, 0x14, 0x58, 0x04, 0xf8, 0x6b, 0xbd, 0x58, + 0x19, 0xcd, 0x33, 0x5f, 0x96, 0xd6, 0xcd, 0xb8, 0xb3, 0xbf, 0x9d, 0x7f, 0x5e, 0x4a, 0xe4, 0x82, + 0xb7, 0xb6, 0x3d, 0xcc, 0x1c, 0x9a, 0x5a, 0xa9, 0x87, 0xc9, 0x72, 0x0d, 0xc6, 0x34, 0x6d, 0x1f, + 0x24, 0x76, 0x83, 0x08, 0x7b, 0x94, 0x04, 0xeb, 0xda, 0x95, 0x81, 0xa5, 0x2e, 0xbb, 0x98, 0xcc, + 0xca, 0xc2, 0x31, 0x13, 0xcc, 0x6e, 0x18, 0x8b, 0x40, 0xb9, 0xa3, 0x7f, 0x4d, 0x38, 0x79, 0xa6, + 0x33, 0x72, 0x91, 0x9e, 0x55, 0x2a, 0xe0, 0xe5, 0x44, 0xaa, 0xd6, 0xc0, 0x37, 0x0a, 0x3c, 0xb7, + 0x18, 0xde, 0x57, 0xd7, 0xa7, 0x0f, 0x1c, 0x67, 0xee, 0x32, 0xb1, 0xdc, 0x63, 0x6d, 0x2a, 0x94, + 0xce, 0xdd, 0xd6, 0x94, 0x4a, 0x65, 0x39, 0xb6, 0x4c, 0x84, 0xc5, 0x77, 0x56, 0x98, 0x19, 0xbf, + 0x4a, 0x80, 0x40, 0xf4, 0xae, 0x9c, 0x41, 0x30, 0xe1, 0xfb, 0x57, 0xa1, 0x77, 0x40, 0xdf, 0x34, + 0x70, 0x4d, 0xfb, 0xa1, 0x5f, 0x7b, 0x3f, 0x09, 0x18, 0x22, 0x29, 0xee, 0x56, 0x2c, 0x60, 0xa8, + 0x2d, 0x29, 0x5b, 0x92 }; + +/* KEK record with the pre-macOS 26 8-byte keyblob[2] metadata + * attribute, to safeguard the original code path. + */ +uint8_t fsapfs_test_key_encrypted_key_data4[ 148 ] = { + 0x30, 0x81, 0x91, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x60, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, + 0xb6, 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, + 0x65, 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x84, 0x03, 0x08, + 0x89, 0x50, 0x85, 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, + 0x85, 0x38, 0x43, 0x0e }; + +/* KEK record with 1-byte long-form (0x81) DER lengths on the object and + * on the keyblob attribute. The unsupported keyblob[6] attribute + * precedes keyblob[4] and keyblob[5], so both remain observable. + */ +uint8_t fsapfs_test_key_encrypted_key_data5[ 181 ] = { + 0x30, 0x81, 0xb2, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x81, 0x80, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, + 0x45, 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x16, 0x49, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x96, 0xd7, 0x25, 0xec, 0x34, 0xd8, 0x42, 0xac, 0x97, 0x64, 0xe4, 0x3f, 0x81, 0x80, + 0x4f, 0x57, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, 0xb6, + 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, 0x65, + 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x86, 0x10, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x84, 0x03, + 0x08, 0x89, 0x50, 0x85, 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, + 0x1a, 0x85, 0x38, 0x43, 0x0e }; + +/* KEK record with 2-byte long-form (0x82) DER lengths on the object and + * on the keyblob attribute, and with 1-byte and 2-byte long-form DER + * lengths on the keyblob[6] and keyblob[7] attributes. Both precede + * keyblob[4] and keyblob[5], so those remain observable. + */ +uint8_t fsapfs_test_key_encrypted_key_data6[ 600 ] = { + 0x30, 0x82, 0x02, 0x54, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, + 0x47, 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, + 0x70, 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, + 0x05, 0xfe, 0x57, 0xa3, 0x82, 0x02, 0x21, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, + 0xc9, 0xf6, 0x45, 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x16, 0x49, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x96, 0xd7, 0x25, 0xec, 0x34, 0xd8, 0x42, 0xac, 0x97, 0x64, 0xe4, 0x3f, + 0x81, 0x80, 0x4f, 0x57, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, + 0x77, 0xb6, 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, + 0xcf, 0x65, 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x86, 0x81, + 0x80, 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, + 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, + 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, + 0x8d, 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, + 0xbd, 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, + 0xed, 0xf0, 0xf3, 0xf6, 0xf9, 0xfc, 0xff, 0x02, 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, 0x1a, + 0x1d, 0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x35, 0x38, 0x3b, 0x3e, 0x41, 0x44, 0x47, 0x4a, + 0x4d, 0x50, 0x53, 0x56, 0x59, 0x5c, 0x5f, 0x62, 0x65, 0x68, 0x6b, 0x6e, 0x71, 0x74, 0x77, 0x7a, + 0x7d, 0x87, 0x82, 0x01, 0x2c, 0x00, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x3f, 0x46, + 0x4d, 0x54, 0x5b, 0x62, 0x69, 0x70, 0x77, 0x7e, 0x85, 0x8c, 0x93, 0x9a, 0xa1, 0xa8, 0xaf, 0xb6, + 0xbd, 0xc4, 0xcb, 0xd2, 0xd9, 0xe0, 0xe7, 0xee, 0xf5, 0xfc, 0x03, 0x0a, 0x11, 0x18, 0x1f, 0x26, + 0x2d, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x57, 0x5e, 0x65, 0x6c, 0x73, 0x7a, 0x81, 0x88, 0x8f, 0x96, + 0x9d, 0xa4, 0xab, 0xb2, 0xb9, 0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1, 0xf8, 0xff, 0x06, + 0x0d, 0x14, 0x1b, 0x22, 0x29, 0x30, 0x37, 0x3e, 0x45, 0x4c, 0x53, 0x5a, 0x61, 0x68, 0x6f, 0x76, + 0x7d, 0x84, 0x8b, 0x92, 0x99, 0xa0, 0xa7, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd1, 0xd8, 0xdf, 0xe6, + 0xed, 0xf4, 0xfb, 0x02, 0x09, 0x10, 0x17, 0x1e, 0x25, 0x2c, 0x33, 0x3a, 0x41, 0x48, 0x4f, 0x56, + 0x5d, 0x64, 0x6b, 0x72, 0x79, 0x80, 0x87, 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1, 0xb8, 0xbf, 0xc6, + 0xcd, 0xd4, 0xdb, 0xe2, 0xe9, 0xf0, 0xf7, 0xfe, 0x05, 0x0c, 0x13, 0x1a, 0x21, 0x28, 0x2f, 0x36, + 0x3d, 0x44, 0x4b, 0x52, 0x59, 0x60, 0x67, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x91, 0x98, 0x9f, 0xa6, + 0xad, 0xb4, 0xbb, 0xc2, 0xc9, 0xd0, 0xd7, 0xde, 0xe5, 0xec, 0xf3, 0xfa, 0x01, 0x08, 0x0f, 0x16, + 0x1d, 0x24, 0x2b, 0x32, 0x39, 0x40, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x7f, 0x86, + 0x8d, 0x94, 0x9b, 0xa2, 0xa9, 0xb0, 0xb7, 0xbe, 0xc5, 0xcc, 0xd3, 0xda, 0xe1, 0xe8, 0xef, 0xf6, + 0xfd, 0x04, 0x0b, 0x12, 0x19, 0x20, 0x27, 0x2e, 0x35, 0x3c, 0x43, 0x4a, 0x51, 0x58, 0x5f, 0x66, + 0x6d, 0x74, 0x7b, 0x82, 0x89, 0x90, 0x97, 0x9e, 0xa5, 0xac, 0xb3, 0xba, 0xc1, 0xc8, 0xcf, 0xd6, + 0xdd, 0xe4, 0xeb, 0xf2, 0xf9, 0x00, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x3f, 0x46, + 0x4d, 0x54, 0x5b, 0x62, 0x69, 0x70, 0x77, 0x7e, 0x85, 0x8c, 0x93, 0x9a, 0xa1, 0xa8, 0xaf, 0xb6, + 0xbd, 0xc4, 0xcb, 0xd2, 0xd9, 0xe0, 0xe7, 0xee, 0xf5, 0xfc, 0x03, 0x0a, 0x11, 0x18, 0x1f, 0x26, + 0x2d, 0x84, 0x03, 0x08, 0x89, 0x50, 0x85, 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, + 0x9f, 0x9f, 0x4f, 0x1a, 0x85, 0x38, 0x43, 0x0e }; + +/* KEK record followed by trailing data that itself looks like a wrapped + * KEK packed object attribute. The attributes are bound by the object + * value data, so the trailing data must not be parsed. + */ +uint8_t fsapfs_test_key_encrypted_key_data7[ 223 ] = { + 0x30, 0x81, 0x91, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x60, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, + 0xb6, 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, + 0x65, 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x84, 0x03, 0x08, + 0x89, 0x50, 0x85, 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, + 0x85, 0x38, 0x43, 0x0e, 0xa3, 0x49, 0x80, 0x01, 0x00, 0x81, 0x10, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x82, 0x08, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x28, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 }; + +/* KEK record with an unsupported 12-byte keyblob[2] metadata + * attribute value data size. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data1[ 152 ] = { + 0x30, 0x81, 0x95, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x64, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, + 0x50, 0x23, 0xe9, 0x77, 0xb6, 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, + 0x75, 0xf8, 0x3c, 0xcf, 0x65, 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, + 0x9f, 0x84, 0x03, 0x08, 0x89, 0x50, 0x85, 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, + 0x9f, 0x9f, 0x4f, 0x1a, 0x85, 0x38, 0x43, 0x0e }; + +/* KEK record with an 8-byte keyblob[2] metadata attribute and a 15-byte + * keyblob[5] salt. The 22-byte metadata attribute gates the macOS 26 + * behaviour, so this legacy record must still be rejected. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data2[ 147 ] = { + 0x30, 0x81, 0x90, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x5f, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, + 0xb6, 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, + 0x65, 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x84, 0x03, 0x08, + 0x89, 0x50, 0x85, 0x0f, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, + 0x85, 0x38, 0x43 }; + +/* KEK record with an 8-byte keyblob[2] metadata attribute and a 16-byte + * keyblob[4] number of iterations. Rejected for the same reason. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data3[ 161 ] = { + 0x30, 0x81, 0x9e, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x6d, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, + 0xb6, 0xe6, 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, + 0x65, 0xe9, 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x84, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, + 0x10, 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, 0x85, 0x38, 0x43, + 0x0e }; + +/* KEK record with an empty keyblob[4] number of iterations. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data4[ 159 ] = { + 0x30, 0x81, 0x9c, 0x80, 0x01, 0x00, 0x81, 0x20, 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, + 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, + 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9, 0x82, 0x08, 0x07, 0xda, 0xe2, 0x4e, 0xc2, 0x05, + 0xfe, 0x57, 0xa3, 0x6b, 0x80, 0x01, 0x00, 0x81, 0x10, 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, + 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32, 0x82, 0x16, 0x49, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x96, 0xd7, 0x25, 0xec, 0x34, 0xd8, 0x42, 0xac, 0x97, 0x64, 0xe4, 0x3f, 0x81, 0x80, 0x4f, + 0x57, 0x83, 0x28, 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, 0xb6, 0xe6, + 0xff, 0xca, 0x85, 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, 0x65, 0xe9, + 0xf4, 0x1b, 0x8c, 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f, 0x84, 0x00, 0x85, 0x10, 0x51, + 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, 0x85, 0x38, 0x43, 0x0e }; + +/* Truncated record in which the object 0x81 long-form length byte is + * missing. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data5[ 2 ] = { + 0x30, 0x81 }; + +/* Truncated record in which only 1 of the 2 object 0x82 long-form length + * bytes is present. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data6[ 3 ] = { + 0x30, 0x82, 0x01 }; + +/* Truncated record in which an attribute tag is present but its length + * byte is missing. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data7[ 3 ] = { + 0x30, 0x01, 0x80 }; + +/* Truncated record in which the attribute 0x81 long-form length byte is + * missing. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data8[ 4 ] = { + 0x30, 0x02, 0x80, 0x81 }; + +/* Truncated record in which only 1 of the 2 attribute 0x82 long-form + * length bytes is present. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data9[ 5 ] = { + 0x30, 0x03, 0x80, 0x82, 0x00 }; + +/* Record with attribute value data running past the object value data. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data10[ 6 ] = { + 0x30, 0x04, 0x80, 0x03, 0x00, 0x00 }; + +/* Truncated record in which a wrapped KEK packed object attribute tag is + * present but its length byte is missing. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data11[ 8 ] = { + 0x30, 0x06, 0xa3, 0x04, 0x80, 0x01, 0x00, 0x84 }; + +/* Truncated record in which the wrapped KEK packed object attribute 0x81 + * long-form length byte is missing. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data12[ 9 ] = { + 0x30, 0x07, 0xa3, 0x05, 0x80, 0x01, 0x00, 0x84, 0x81 }; + +/* Truncated record in which neither of the 2 wrapped KEK packed object + * attribute 0x82 long-form length bytes is present. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data13[ 9 ] = { + 0x30, 0x07, 0xa3, 0x05, 0x80, 0x01, 0x00, 0x84, 0x82 }; + +/* Record with wrapped KEK packed object attribute value data running past + * the wrapped KEK packed object. + */ +uint8_t fsapfs_test_key_encrypted_key_error_data14[ 10 ] = { + 0x30, 0x08, 0xa3, 0x06, 0x80, 0x01, 0x00, 0x81, 0x10, 0x00 }; + +/* Expected HMAC of the per-user KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_hmac1[ 32 ] = { + 0x6b, 0x1c, 0x2e, 0xc7, 0x80, 0x18, 0x60, 0x47, 0x0d, 0x39, 0x0e, 0x0b, 0x4d, 0xb6, 0x59, 0x4c, + 0x86, 0x74, 0xd0, 0x50, 0xa0, 0xf7, 0x88, 0x70, 0x67, 0x38, 0x2d, 0x4d, 0x45, 0xe8, 0x30, 0xb9 }; + +/* Expected keyblob[1] identifier of the per-user KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_identifier1[ 16 ] = { + 0xfa, 0xa4, 0x13, 0xcd, 0xc9, 0xf6, 0x45, 0x43, 0xba, 0x84, 0xb8, 0x94, 0x39, 0xc4, 0x07, 0x32 }; + +/* Expected keyblob[3] wrapped KEK of the per-user KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_wrapped_kek1[ 40 ] = { + 0x7c, 0xb2, 0xae, 0xf5, 0x82, 0xde, 0x67, 0x50, 0x23, 0xe9, 0x77, 0xb6, 0xe6, 0xff, 0xca, 0x85, + 0x45, 0xf8, 0x08, 0x15, 0x5e, 0x2b, 0x73, 0x75, 0xf8, 0x3c, 0xcf, 0x65, 0xe9, 0xf4, 0x1b, 0x8c, + 0xe7, 0x12, 0x09, 0x9b, 0xfb, 0x67, 0x59, 0x9f }; + +/* Expected keyblob[5] salt of the per-user KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_salt1[ 16 ] = { + 0x51, 0x42, 0xaf, 0x0b, 0xf4, 0x34, 0xde, 0x02, 0x9f, 0x9f, 0x4f, 0x1a, 0x85, 0x38, 0x43, 0x0e }; + +/* Expected HMAC of the PRK KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_hmac2[ 32 ] = { + 0x5a, 0xb0, 0xa1, 0x4d, 0xbe, 0xbc, 0xdf, 0x6b, 0xea, 0x99, 0xbf, 0x48, 0xe9, 0xcd, 0xd2, 0x5e, + 0xfc, 0xf6, 0x3b, 0xed, 0xd0, 0x32, 0xfc, 0xe4, 0x9a, 0x00, 0xc5, 0x5c, 0x42, 0x7d, 0x85, 0xfd }; + +/* Expected keyblob[1] identifier of the PRK KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_identifier2[ 16 ] = { + 0xeb, 0xc6, 0xc0, 0x64, 0x00, 0x00, 0x11, 0xaa, 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac }; + +/* Expected keyblob[3] wrapped KEK of the PRK KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_wrapped_kek2[ 40 ] = { + 0xd1, 0x92, 0x75, 0xdf, 0x33, 0x8b, 0x1b, 0x76, 0x83, 0x6c, 0x09, 0xfa, 0x12, 0x34, 0xb9, 0x35, + 0x5d, 0x4f, 0xac, 0xee, 0xe2, 0x51, 0xd7, 0xf4, 0x54, 0x92, 0xac, 0x33, 0xe1, 0xfd, 0x0d, 0xef, + 0xae, 0xfd, 0x61, 0x4d, 0xb1, 0x43, 0xba, 0x65 }; + +/* Expected keyblob[5] salt of the PRK KEK record. + */ +uint8_t fsapfs_test_key_encrypted_key_salt2[ 16 ] = { + 0xd8, 0x3c, 0x49, 0x3c, 0x5a, 0x10, 0x78, 0xdd, 0xc1, 0xe3, 0x6b, 0x3d, 0x4d, 0x37, 0xdf, 0xa7 }; + +/* Expected HMAC of the container key bag VEK entry. + */ +uint8_t fsapfs_test_key_encrypted_key_hmac3[ 32 ] = { + 0x73, 0x24, 0xfa, 0x3a, 0x90, 0xb7, 0x5a, 0xe5, 0xc5, 0x55, 0x19, 0x3b, 0xac, 0xc1, 0x77, 0x00, + 0x7c, 0x09, 0x69, 0xbd, 0x85, 0x12, 0x47, 0xcf, 0xa9, 0x48, 0x24, 0xf2, 0x0f, 0xe4, 0xbb, 0x22 }; + +/* Expected keyblob[1] identifier (volume identifier) of the VEK entry. + */ +uint8_t fsapfs_test_key_encrypted_key_identifier3[ 16 ] = { + 0x66, 0xeb, 0x31, 0xc4, 0x19, 0x7c, 0x43, 0xa2, 0xb8, 0x33, 0xc5, 0x20, 0x52, 0x88, 0x4e, 0x9c }; + +/* Expected keyblob[3] wrapped volume key of the VEK entry. + */ +uint8_t fsapfs_test_key_encrypted_key_wrapped_kek3[ 40 ] = { + 0xd7, 0xec, 0xb1, 0xc0, 0x14, 0x0b, 0x97, 0x65, 0x88, 0x89, 0xbb, 0xce, 0xe5, 0xf4, 0x1d, 0xee, + 0x20, 0xeb, 0xd8, 0x9e, 0x48, 0x96, 0x0d, 0x7d, 0x3c, 0x00, 0x28, 0xed, 0x1b, 0xe4, 0x9c, 0x44, + 0xce, 0x8a, 0x1b, 0xbf, 0x17, 0x32, 0x4e, 0x3d }; + +/* An all-zero salt. The VEK entry carries a 3-byte keyblob[5] that is + * not a PBKDF2 salt, so the salt must be left untouched. + */ +uint8_t fsapfs_test_key_encrypted_key_empty_salt[ 16 ] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* Tests the libfsapfs_key_encrypted_key_initialize function * Returns 1 if successful or 0 if not */ @@ -270,34 +626,1218 @@ int fsapfs_test_key_encrypted_key_free( return( 0 ); } -#endif /* defined( __GNUC__ ) && !defined( LIBFSAPFS_DLL_IMPORT ) */ - -/* The main program +/* Tests the libfsapfs_key_encrypted_key_read_data function + * Returns 1 if successful or 0 if not */ -#if defined( HAVE_WIDE_SYSTEM_CHARACTER ) -int wmain( - int argc FSAPFS_TEST_ATTRIBUTE_UNUSED, - wchar_t * const argv[] FSAPFS_TEST_ATTRIBUTE_UNUSED ) -#else -int main( - int argc FSAPFS_TEST_ATTRIBUTE_UNUSED, - char * const argv[] FSAPFS_TEST_ATTRIBUTE_UNUSED ) -#endif +int fsapfs_test_key_encrypted_key_read_data( + void ) { - FSAPFS_TEST_UNREFERENCED_PARAMETER( argc ) - FSAPFS_TEST_UNREFERENCED_PARAMETER( argv ) + libcerror_error_t *error = NULL; + libfsapfs_key_encrypted_key_t *key_encrypted_key = NULL; + int result = 0; -#if defined( __GNUC__ ) && !defined( LIBFSAPFS_DLL_IMPORT ) + /* Every regular case starts from a freshly initialized key encrypted + * key, since libfsapfs_key_encrypted_key_read_data only sets the + * attributes a record actually carries. + */ - FSAPFS_TEST_RUN( - "libfsapfs_key_encrypted_key_initialize", - fsapfs_test_key_encrypted_key_initialize ); + /* Test regular case of a macOS 26 per-user KEK record, which has a + * 22-byte keyblob[2] metadata attribute instead of an 8-byte one. The + * first 4 bytes of a 22-byte metadata attribute are not the encryption + * method, so it is normalized to 0 (AES-256). + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); - FSAPFS_TEST_RUN( - "libfsapfs_key_encrypted_key_free", - fsapfs_test_key_encrypted_key_free ); + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data1, + 162, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac1, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek1, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_salt1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 559440 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 0 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test regular case of the personal recovery key KEK record of the same + * container. A second, independent 22-byte metadata record. + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data2, + 162, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac2, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier2, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek2, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_salt2, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 682789 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 0 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test regular case of a macOS 26 container key bag VEK entry. It uses + * 2-byte long-form DER lengths on the outer SEQUENCE and the keyblob, a + * 1-byte long-form DER length on keyblob[8], and it carries a 16-byte + * keyblob[4] and a 3-byte keyblob[5] that are neither an iteration count + * nor a PBKDF2 salt, so the number of iterations and the salt must be + * left at their initial value. + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data3, + 388, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); - /* TODO: add tests for libfsapfs_key_encrypted_key_read_data */ + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac3, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier3, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek3, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_empty_salt, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 0 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test regular case of a KEK record with the pre-macOS 26 8-byte + * keyblob[2] metadata attribute, where the first 4 bytes are the + * encryption method. + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data4, + 148, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac1, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek1, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_salt1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 559440 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 2 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test regular case of a KEK record with 1-byte long-form (0x81) DER + * lengths on the object and on the keyblob attribute. + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data5, + 181, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac1, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek1, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_salt1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 559440 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 0 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test regular case of a KEK record with 2-byte long-form (0x82) DER + * lengths on the object and on the keyblob attribute, and 1-byte and + * 2-byte long-form DER lengths on keyblob attributes. The recognized + * keyblob[4] and keyblob[5] follow both long-form attributes, so they + * are only set if parsing continued past them. + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data6, + 600, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac1, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek1, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_salt1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 559440 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 0 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test regular case of a KEK record followed by trailing data that + * itself looks like a wrapped KEK packed object attribute. The + * attributes are bound by the object value data, so the trailing + * wrapped KEK packed object must not replace the one in the record. + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data7, + 223, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = memory_compare( + key_encrypted_key->hmac, + fsapfs_test_key_encrypted_key_hmac1, + 32 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->identifier, + fsapfs_test_key_encrypted_key_identifier1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->wrapped_kek, + fsapfs_test_key_encrypted_key_wrapped_kek1, + 40 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + result = memory_compare( + key_encrypted_key->salt, + fsapfs_test_key_encrypted_key_salt1, + 16 ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 0 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT64( + "key_encrypted_key->number_of_iterations", + key_encrypted_key->number_of_iterations, + (uint64_t) 559440 ); + + FSAPFS_TEST_ASSERT_EQUAL_UINT32( + "key_encrypted_key->encryption_method", + key_encrypted_key->encryption_method, + (uint32_t) 2 ); + + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + /* Test error cases + */ + result = libfsapfs_key_encrypted_key_initialize( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + result = libfsapfs_key_encrypted_key_read_data( + NULL, + fsapfs_test_key_encrypted_key_data1, + 162, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + NULL, + 162, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data1, + 1, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data1, + (size_t) SSIZE_MAX + 1, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated inside the object value data + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_data1, + 32, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of an unsupported keyblob[2] metadata attribute value + * data size, which is neither 8 nor 22. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data1, + 152, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of an 8-byte keyblob[2] metadata attribute combined + * with a 15-byte keyblob[5]. Only the 22-byte metadata attribute + * allows keyblob[5] to be something other than a PBKDF2 salt, so a + * corrupt legacy record must still be reported as unsupported. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data2, + 147, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of an 8-byte keyblob[2] metadata attribute combined + * with a 16-byte keyblob[4]. Rejected for the same reason. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data3, + 161, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of an empty keyblob[4] number of iterations. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data4, + 159, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated before the object 0x81 + * long-form length byte. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data5, + 2, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated inside the object 0x82 + * long-form length bytes. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data6, + 3, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated before an attribute length byte. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data7, + 3, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated before an attribute 0x81 + * long-form length byte. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data8, + 4, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated inside the attribute 0x82 + * long-form length bytes. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data9, + 5, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of attribute value data running past the object value + * data. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data10, + 6, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated before a wrapped KEK packed + * object attribute length byte. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data11, + 8, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated before a wrapped KEK packed + * object attribute 0x81 long-form length byte. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data12, + 9, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of a record truncated before the wrapped KEK packed + * object attribute 0x82 long-form length bytes. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data13, + 9, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Test error case of wrapped KEK packed object attribute value data + * running past the wrapped KEK packed object. + */ + result = libfsapfs_key_encrypted_key_read_data( + key_encrypted_key, + fsapfs_test_key_encrypted_key_error_data14, + 10, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + -1 ); + + FSAPFS_TEST_ASSERT_IS_NOT_NULL( + "error", + error ); + + libcerror_error_free( + &error ); + + /* Clean up + */ + result = libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + &error ); + + FSAPFS_TEST_ASSERT_EQUAL_INT( + "result", + result, + 1 ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "key_encrypted_key", + key_encrypted_key ); + + FSAPFS_TEST_ASSERT_IS_NULL( + "error", + error ); + + return( 1 ); + +on_error: + if( error != NULL ) + { + libcerror_error_free( + &error ); + } + if( key_encrypted_key != NULL ) + { + libfsapfs_key_encrypted_key_free( + &key_encrypted_key, + NULL ); + } + return( 0 ); +} + +#endif /* defined( __GNUC__ ) && !defined( LIBFSAPFS_DLL_IMPORT ) */ + +/* The main program + */ +#if defined( HAVE_WIDE_SYSTEM_CHARACTER ) +int wmain( + int argc FSAPFS_TEST_ATTRIBUTE_UNUSED, + wchar_t * const argv[] FSAPFS_TEST_ATTRIBUTE_UNUSED ) +#else +int main( + int argc FSAPFS_TEST_ATTRIBUTE_UNUSED, + char * const argv[] FSAPFS_TEST_ATTRIBUTE_UNUSED ) +#endif +{ + FSAPFS_TEST_UNREFERENCED_PARAMETER( argc ) + FSAPFS_TEST_UNREFERENCED_PARAMETER( argv ) + +#if defined( __GNUC__ ) && !defined( LIBFSAPFS_DLL_IMPORT ) + + FSAPFS_TEST_RUN( + "libfsapfs_key_encrypted_key_initialize", + fsapfs_test_key_encrypted_key_initialize ); + + FSAPFS_TEST_RUN( + "libfsapfs_key_encrypted_key_free", + fsapfs_test_key_encrypted_key_free ); + + FSAPFS_TEST_RUN( + "libfsapfs_key_encrypted_key_read_data", + fsapfs_test_key_encrypted_key_read_data ); /* TODO: add tests for libfsapfs_key_encrypted_key_unlock_with_password */