Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/security/tools/jarsigner/FindHeaderEndVsManifestDigesterFindFirstSection.java
41152 views
1
/*
2
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
import java.io.ByteArrayOutputStream;
25
import java.security.MessageDigest;
26
import java.util.ArrayList;
27
import java.util.List;
28
import sun.security.util.ManifestDigester;
29
30
import org.testng.annotations.Test;
31
import org.testng.annotations.DataProvider;
32
import org.testng.annotations.Factory;
33
import org.testng.annotations.BeforeClass;
34
import org.testng.annotations.BeforeMethod;
35
36
import static java.nio.charset.StandardCharsets.UTF_8;
37
import static org.testng.Assert.*;
38
39
/**
40
* @test
41
* @bug 8217375
42
* @modules java.base/sun.security.util
43
* @run testng FindHeaderEndVsManifestDigesterFindFirstSection
44
* @summary Checks that {@link JarSigner#findHeaderEnd} (moved to now
45
* {@link #findHeaderEnd} in this test) can be replaced with
46
* {@link ManifestDigester#findSection}
47
* (first invocation will identify main attributes)
48
* without making a difference.
49
*/
50
/*
51
* Note to future maintainer:
52
* While it might look at first glance like this test ensures backwards-
53
* compatibility between JarSigner.findHeaderEnd and
54
* ManifestDigester.findSection's first invocation that find the main
55
* attributes section, at the time of that change, this test continues to
56
* verify main attributes digestion now with ManifestDigester.findSection as
57
* opposed to previous implementation in JarSigner.findHeaderEnd.
58
* Before completely removing this test, make sure that main attributes
59
* digestion is covered appropriately with tests. After JarSigner.findHeaderEnd
60
* has been removed digests should still continue to match.
61
*
62
* See also
63
* - jdk/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java
64
* for some end-to-end tests utilizing the jarsigner tool,
65
* - jdk/test/jdk/sun/security/util/ManifestDigester/FindSection.java and
66
* - jdk/test/jdk/sun/security/util/ManifestDigester/DigestInput.java
67
* for much more detailed tests at api level
68
*
69
* Both test mentioned above, however, originally were created when removing
70
* confusion of "Manifest-Main-Attributes" individual section with actual main
71
* attributes whereas the test here is about changes related to raw manifest
72
* reproduction and in the end test pretty much the same behavior.
73
*/
74
public class FindHeaderEndVsManifestDigesterFindFirstSection {
75
76
static final boolean FIXED_8217375 = true; // FIXME
77
78
/**
79
* from former {@link JarSigner#findHeaderEnd}, subject to verification if
80
* it can be replaced with {@link ManifestDigester#findSection}
81
*/
82
@SuppressWarnings("fallthrough")
83
private int findHeaderEnd(byte[] bs) {
84
// Initial state true to deal with empty header
85
boolean newline = true; // just met a newline
86
int len = bs.length;
87
for (int i = 0; i < len; i++) {
88
switch (bs[i]) {
89
case '\r':
90
if (i < len - 1 && bs[i + 1] == '\n') i++;
91
// fallthrough
92
case '\n':
93
if (newline) return i + 1; //+1 to get length
94
newline = true;
95
break;
96
default:
97
newline = false;
98
}
99
}
100
// If header end is not found, it means the MANIFEST.MF has only
101
// the main attributes section and it does not end with 2 newlines.
102
// Returns the whole length so that it can be completely replaced.
103
return len;
104
}
105
106
@DataProvider(name = "parameters")
107
public static Object[][] parameters() {
108
List<Object[]> tests = new ArrayList<>();
109
for (String lineBreak : new String[] { "\n", "\r", "\r\n" }) {
110
if ("\r".equals(lineBreak) && !FIXED_8217375) continue;
111
for (int numLBs = 0; numLBs <= 3; numLBs++) {
112
for (String addSection : new String[] { null, "Ignore" }) {
113
tests.add(new Object[] { lineBreak, numLBs, addSection });
114
}
115
}
116
}
117
return tests.toArray(new Object[tests.size()][]);
118
}
119
120
@Factory(dataProvider = "parameters")
121
public static Object[] createTests(String lineBreak, int numLineBreaks,
122
String individualSectionName) {
123
return new Object[]{new FindHeaderEndVsManifestDigesterFindFirstSection(
124
lineBreak, numLineBreaks, individualSectionName
125
)};
126
}
127
128
final String lineBreak;
129
final int numLineBreaks; // number of line breaks after main attributes
130
final String individualSectionName; // null means only main attributes
131
final byte[] rawBytes;
132
133
FindHeaderEndVsManifestDigesterFindFirstSection(String lineBreak,
134
int numLineBreaks, String individualSectionName) {
135
this.lineBreak = lineBreak;
136
this.numLineBreaks = numLineBreaks;
137
this.individualSectionName = individualSectionName;
138
139
rawBytes = (
140
"oldStyle: trailing space " + lineBreak +
141
"newStyle: no trailing space" + lineBreak.repeat(numLineBreaks) +
142
// numLineBreaks < 2 will not properly delimit individual section
143
// but it does not hurt to test that anyway
144
(individualSectionName != null ?
145
"Name: " + individualSectionName + lineBreak +
146
"Ignore: nothing here" + lineBreak +
147
lineBreak
148
: "")
149
).getBytes(UTF_8);
150
}
151
152
@BeforeMethod
153
public void verbose() {
154
System.out.println("lineBreak = " + stringToIntList(lineBreak));
155
System.out.println("numLineBreaks = " + numLineBreaks);
156
System.out.println("individualSectionName = " + individualSectionName);
157
}
158
159
@FunctionalInterface
160
interface Callable {
161
void call() throws Exception;
162
}
163
164
void catchNoLineBreakAfterMainAttributes(Callable test) throws Exception {
165
// manifests cannot be parsed and digested if the main attributes do
166
// not end in a blank line (double line break) or one line break
167
// immediately before eof.
168
boolean failureExpected = numLineBreaks == 0
169
&& individualSectionName == null;
170
try {
171
test.call();
172
if (failureExpected) fail("expected an exception");
173
} catch (NullPointerException | IllegalStateException e) {
174
if (!failureExpected) fail("unexpected " + e.getMessage(), e);
175
}
176
}
177
178
/**
179
* Checks that the beginning of the manifest until position<ol>
180
* <li>{@code Jarsigner.findHeaderEnd} in the previous version
181
* and</li>
182
* <li>{@code ManifestDigester.getMainAttsEntry().sections[0].
183
* lengthWithBlankLine} in the new version</li>
184
* </ol>produce the same offset (TODO: or the same error).
185
* The beginning of the manifest until that offset (range
186
* <pre>0 .. (offset - 1)</pre>) will be reproduced if the manifest has
187
* not changed.
188
* <p>
189
* Getting {@code startOfNext} of {@link ManifestDigester#findSection}'s
190
* first invokation returned {@link ManifestDigester.Position} which
191
* identifies the end offset of the main attributes is difficulted by
192
* {@link ManifestDigester#findSection} being private and therefore not
193
* directly accessible.
194
*/
195
@Test
196
public void startOfNextLengthWithBlankLine() throws Exception {
197
catchNoLineBreakAfterMainAttributes(() ->
198
assertEquals(lengthWithBlankLine(), findHeaderEnd(rawBytes))
199
);
200
}
201
202
/**
203
* Due to its private visibility,
204
* {@link ManifestDigester.Section#lengthWithBlankLine} is not directly
205
* accessible. However, calling {@link ManifestDigester.Entry#digest}
206
* reveals {@code lengthWithBlankLine} as third parameter in
207
* <pre>md.update(sec.rawBytes, sec.offset, sec.lengthWithBlankLine);</pre>
208
* on line ManifestDigester.java:212.
209
* <p>
210
* This value is the same as {@code startOfNext} of
211
* {@link ManifestDigester#findSection}'s first invocation returned
212
* {@link ManifestDigester.Position} identifying the end offset of the
213
* main attributes because<ol>
214
* <li>the end offset of the main attributes is assigned to
215
* {@code startOfNext} in
216
* <pre>pos.startOfNext = i+1;</pre> in ManifestDigester.java:98</li>
217
* <li>which is then passed on as the third parameter to the constructor
218
* of a new {@link ManifestDigester.Section#Section} by
219
* <pre>new Section(0, pos.endOfSection + 1, pos.startOfNext, rawBytes)));</pre>
220
* in in ManifestDigester.java:128</li>
221
* <li>where it is assigned to
222
* {@link ManifestDigester.Section#lengthWithBlankLine} by
223
* <pre>this.lengthWithBlankLine = lengthWithBlankLine;</pre>
224
* in ManifestDigester.java:241</li>
225
* <li>from where it is picked up by {@link ManifestDigester.Entry#digest}
226
* in
227
* <pre>md.update(sec.rawBytes, sec.offset, sec.lengthWithBlankLine);</pre>
228
* in ManifestDigester.java:212</li>
229
* </ol>
230
* all of which without any modification.
231
*/
232
int lengthWithBlankLine() {
233
int[] lengthWithBlankLine = new int[] { 0 };
234
new ManifestDigester(rawBytes).get(ManifestDigester.MF_MAIN_ATTRS,
235
false).digest(new MessageDigest("lengthWithBlankLine") {
236
@Override protected void engineReset() {
237
lengthWithBlankLine[0] = 0;
238
}
239
@Override protected void engineUpdate(byte b) {
240
lengthWithBlankLine[0]++;
241
}
242
@Override protected void engineUpdate(byte[] b, int o, int l) {
243
lengthWithBlankLine[0] += l;
244
}
245
@Override protected byte[] engineDigest() {
246
return null;
247
}
248
});
249
return lengthWithBlankLine[0];
250
}
251
252
/**
253
* Checks that the replacement of {@link JarSigner#findHeaderEnd} is
254
* actually used to reproduce manifest main attributes.
255
* <p>
256
* {@link #startOfNextLengthWithBlankLine} demonstrates that
257
* {@link JarSigner#findHeaderEnd} has been replaced successfully with
258
* {@link ManifestDigester#findSection} but does not also show that the
259
* main attributes are reproduced with the same offset as before.
260
* {@link #startOfNextLengthWithBlankLine} uses
261
* {@link ManifestDigester.Entry#digest} to demonstrate an equal offset
262
* calculated but {@link ManifestDigester.Entry#digest} is not necessarily
263
* the same as reproducing, especially when considering
264
* {@link ManifestDigester.Entry#oldStyle}.
265
*/
266
@Test(enabled = FIXED_8217375)
267
public void reproduceMainAttributes() throws Exception {
268
catchNoLineBreakAfterMainAttributes(() -> {
269
ByteArrayOutputStream buf = new ByteArrayOutputStream();
270
ManifestDigester md = new ManifestDigester(rawBytes);
271
// without 8217375 fixed the following line will not even compile
272
// so just remove it and skip the test for regression
273
md.getMainAttsEntry().reproduceRaw(buf); // FIXME
274
275
assertEquals(buf.size(), findHeaderEnd(rawBytes));
276
});
277
}
278
279
static List<Integer> stringToIntList(String string) {
280
byte[] bytes = string.getBytes(UTF_8);
281
List<Integer> list = new ArrayList<>();
282
for (int i = 0; i < bytes.length; i++) {
283
list.add((int) bytes[i]);
284
}
285
return list;
286
}
287
288
}
289
290