xref: /freebsd/contrib/libarchive/libarchive/test/test_read_format_rar_encryption.c (revision bd66c1b43e33540205dbc1187c2f2a15c58b57ba)
1 /*
2  * Copyright (c) 2003-2018
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 #include "test.h"
27 
28 /*
29  * All of the archives for this teset contain four files: a.txt, b.txt, c.txt, and d.txt
30  * For solid archives or archvies or archives where filenames are encrypted, all four files are encrypted with the
31  * password "password". For non-solid archives without filename encryption, a.txt and c.txt are not encrypted, b.txt is
32  * encrypted with the password "password", and d.txt is encrypted with the password "password2".
33  *
34  * For all files the file contents is "This is from <filename>" (i.e. "This is from a.txt" etc.)
35  */
test_encrypted_rar_archive(const char * filename,int filenamesEncrypted,int solid)36 static void test_encrypted_rar_archive(const char *filename, int filenamesEncrypted, int solid)
37 {
38 	struct archive_entry *ae;
39 	struct archive *a;
40 	char buff[128];
41 	int expected_read_header_result, expected_read_data_result;
42 	const int expected_file_size = 18; /* This is from X.txt */
43 
44 	/* We should only ever fail to read the header when filenames are encrypted. Otherwise we're failing for other
45 	 * unsupported reasons, in which case we have no hope of detecting encryption */
46 	expected_read_header_result = filenamesEncrypted ? ARCHIVE_FATAL : ARCHIVE_OK;
47 
48 	/* We should only ever fail to read the data for "a.txt" and "c.txt" if they are encrypted */
49 	/* NOTE: We'll never attempt this when filenames are encrypted, so we only check for solid here */
50 	expected_read_data_result = solid ? ARCHIVE_FATAL : expected_file_size;
51 
52 	extract_reference_file(filename);
53 	assert((a = archive_read_new()) != NULL);
54 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
55 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
56 	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, filename, 10240));
57 
58 	/* No data read yet; encryption unknown */
59 	assertEqualInt(ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW, archive_read_has_encrypted_entries(a));
60 
61 	/* Read the header for "a.txt" */
62 	assertEqualIntA(a, expected_read_header_result, archive_read_next_header(a, &ae));
63 	if (!filenamesEncrypted) {
64 		assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
65 		assertEqualString("a.txt", archive_entry_pathname(ae));
66 		assertEqualInt(expected_file_size, archive_entry_size(ae));
67 		assertEqualInt(solid, archive_entry_is_data_encrypted(ae));
68 		assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
69 		/* NOTE: The reader will set this value to zero on the first header that it reads, even if later entries
70 		 * are encrypted */
71 		assertEqualInt(solid, archive_read_has_encrypted_entries(a));
72 		assertEqualIntA(a, expected_read_data_result, archive_read_data(a, buff, sizeof(buff)));
73 		if (!solid) {
74 			assertEqualMem("This is from a.txt", buff, expected_file_size);
75 		}
76 	}
77 	else {
78 		assertEqualInt(1, archive_entry_is_data_encrypted(ae));
79 		assertEqualInt(1, archive_entry_is_metadata_encrypted(ae));
80 		assertEqualInt(1, archive_read_has_encrypted_entries(a));
81 		assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
82 
83 		/* Additional attempts to read headers are futile */
84 		assertEqualInt(ARCHIVE_OK, archive_read_close(a));
85 		assertEqualInt(ARCHIVE_OK, archive_read_free(a));
86 		return;
87 	}
88 
89 	/* From here on out, we can assume that !filenamesEncrypted */
90 
91 	/* Read the header for "b.txt" */
92 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
93 	assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
94 	assertEqualString("b.txt", archive_entry_pathname(ae));
95 	assertEqualInt(expected_file_size, archive_entry_size(ae));
96 	assertEqualInt(1, archive_entry_is_data_encrypted(ae));
97 	assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
98 	assertEqualInt(1, archive_read_has_encrypted_entries(a));
99 	assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
100 
101 	/* Read the header for "c.txt" */
102 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
103 	assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
104 	assertEqualString("c.txt", archive_entry_pathname(ae));
105 	assertEqualInt(expected_file_size, archive_entry_size(ae));
106 	assertEqualInt(solid, archive_entry_is_data_encrypted(ae));
107 	assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
108 	/* After setting to true above, this should forever be true */
109 	assertEqualInt(1, archive_read_has_encrypted_entries(a));
110 	assertEqualIntA(a, expected_read_data_result, archive_read_data(a, buff, sizeof(buff)));
111 	if (!solid) {
112 		assertEqualMem("This is from c.txt", buff, expected_file_size);
113 	}
114 
115 	/* Read the header for "d.txt" */
116 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
117 	assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
118 	assertEqualString("d.txt", archive_entry_pathname(ae));
119 	assertEqualInt(expected_file_size, archive_entry_size(ae));
120 	assertEqualInt(1, archive_entry_is_data_encrypted(ae));
121 	assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
122 	assertEqualInt(1, archive_read_has_encrypted_entries(a));
123 	assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
124 
125 	/* End of archive. */
126 	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
127 
128 	/* Close the archive. */
129 	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
130 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
131 }
132 
DEFINE_TEST(test_read_format_rar4_encrypted)133 DEFINE_TEST(test_read_format_rar4_encrypted)
134 {
135 	test_encrypted_rar_archive("test_read_format_rar4_encrypted.rar", 0, 0);
136 }
137 
DEFINE_TEST(test_read_format_rar4_encrypted_filenames)138 DEFINE_TEST(test_read_format_rar4_encrypted_filenames)
139 {
140 	test_encrypted_rar_archive("test_read_format_rar4_encrypted_filenames.rar", 1, 0);
141 }
142 
DEFINE_TEST(test_read_format_rar4_solid_encrypted)143 DEFINE_TEST(test_read_format_rar4_solid_encrypted)
144 {
145 	/* TODO: If solid RAR4 support is ever added, the following should pass */
146 #if 0
147 	test_encrypted_rar_archive("test_read_format_rar4_solid_encrypted.rar", 0, 1);
148 #else
149 	skipping("RAR4 solid archive support not currently available");
150 #endif
151 }
152 
DEFINE_TEST(test_read_format_rar4_solid_encrypted_filenames)153 DEFINE_TEST(test_read_format_rar4_solid_encrypted_filenames)
154 {
155 	test_encrypted_rar_archive("test_read_format_rar4_solid_encrypted_filenames.rar", 1, 1);
156 }
157 
DEFINE_TEST(test_read_format_rar5_encrypted)158 DEFINE_TEST(test_read_format_rar5_encrypted)
159 {
160 	test_encrypted_rar_archive("test_read_format_rar5_encrypted.rar", 0, 0);
161 }
162 
DEFINE_TEST(test_read_format_rar5_encrypted_filenames)163 DEFINE_TEST(test_read_format_rar5_encrypted_filenames)
164 {
165 	test_encrypted_rar_archive("test_read_format_rar5_encrypted_filenames.rar", 1, 0);
166 }
167 
DEFINE_TEST(test_read_format_rar5_solid_encrypted)168 DEFINE_TEST(test_read_format_rar5_solid_encrypted)
169 {
170 	test_encrypted_rar_archive("test_read_format_rar5_solid_encrypted.rar", 0, 1);
171 }
172 
DEFINE_TEST(test_read_format_rar5_solid_encrypted_filenames)173 DEFINE_TEST(test_read_format_rar5_solid_encrypted_filenames)
174 {
175 	test_encrypted_rar_archive("test_read_format_rar5_solid_encrypted_filenames.rar", 1, 1);
176 }
177