Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/security/util/ManifestDigester/ReproduceRaw.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.ByteArrayInputStream;
25
import java.io.ByteArrayOutputStream;
26
import java.io.IOException;
27
import java.security.MessageDigest;
28
import java.util.ArrayList;
29
import java.util.List;
30
import java.util.stream.Collectors;
31
import java.util.jar.Manifest;
32
33
import sun.security.util.ManifestDigester;
34
35
import org.testng.annotations.DataProvider;
36
import org.testng.annotations.Factory;
37
import org.testng.annotations.BeforeMethod;
38
import org.testng.annotations.Test;
39
40
import static java.nio.charset.StandardCharsets.UTF_8;
41
import static org.testng.Assert.*;
42
43
/**
44
* @test
45
* @bug 8217375
46
* @modules java.base/sun.security.util
47
* @compile ../../tools/jarsigner/Utils.java
48
* @run testng ReproduceRaw
49
* @summary Verifies that {@link ManifestDigester} can reproduce parts of
50
* manifests in their binary form so that {@link JarSigner} can rely on
51
* {@link ManifestDigester.Entry#reproduceRaw} to write in a map view
52
* unmodified entries back also unmodified in their binary form.
53
* <p>
54
* See also<ul>
55
* <li>{@link PreserveRawManifestEntryAndDigest} with end to end tests
56
* with {@code jarsigner} tool and</li>
57
* <li>{@link FindHeaderEndVsManifestDigesterFindFirstSection} about
58
* identifying the binary portion of only main attributes and more extensive
59
* main attributes digesting tests while this one test here is more about
60
* reproducing individual sections and that they result in the same
61
* digests.</li>
62
* </ul>
63
*/
64
public class ReproduceRaw {
65
66
static final boolean VERBOSE = false;
67
68
@DataProvider(name = "parameters")
69
public static Object[][] parameters() {
70
List<Object[]> tests = new ArrayList<>();
71
for (String lineBreak : new String[] { "\n", "\r", "\r\n" }) {
72
for (boolean oldStyle : new Boolean[] { false, true }) {
73
for (boolean workaround : new Boolean[] { false, true }) {
74
tests.add(new Object[] { lineBreak, oldStyle, workaround });
75
}
76
}
77
}
78
return tests.toArray(new Object[tests.size()][]);
79
}
80
81
@Factory(dataProvider = "parameters")
82
public static Object[] createTests(String lineBreak,
83
boolean oldStyle, boolean digestWorkaround) {
84
return new Object[]{
85
new ReproduceRaw(lineBreak, oldStyle, digestWorkaround)
86
};
87
}
88
89
final String lineBreak;
90
final boolean oldStyle;
91
final boolean digestWorkaround;
92
93
public ReproduceRaw(String lineBreak,
94
boolean oldStyle, boolean digestWorkaround) {
95
this.lineBreak = lineBreak;
96
this.oldStyle = oldStyle;
97
this.digestWorkaround = digestWorkaround;
98
}
99
100
@BeforeMethod
101
public void verbose() {
102
System.out.println("lineBreak = " +
103
Utils.escapeStringWithNumbers(lineBreak));
104
System.out.println("oldStyle = " + oldStyle);
105
System.out.println("digestWorkaround = " + digestWorkaround);
106
}
107
108
class EchoMessageDigest extends MessageDigest {
109
110
ByteArrayOutputStream buf;
111
112
EchoMessageDigest() {
113
super("echo");
114
}
115
116
@Override
117
protected void engineReset() {
118
buf = new ByteArrayOutputStream();
119
}
120
121
@Override
122
protected void engineUpdate(byte input) {
123
buf.write(input);
124
}
125
126
@Override
127
protected void engineUpdate(byte[] i, int o, int l) {
128
buf.write(i, o, l);
129
}
130
131
@Override protected byte[] engineDigest() {
132
return buf.toByteArray();
133
}
134
135
}
136
137
/**
138
* similar to corresponding part of {@link JarSigner#sign0}
139
* (stripped down to the code for reproducing the old manifest entry by
140
* entry which was too difficult to achieve using the real JarSigner code
141
* in the test here)
142
*/
143
byte[] reproduceRawManifest(byte[] mfRawBytes,
144
boolean mainAttsProperlyDelimited,
145
boolean sectionProperlyDelimited) throws IOException {
146
Manifest manifest = new Manifest(new ByteArrayInputStream(mfRawBytes));
147
ManifestDigester oldMd = new ManifestDigester(mfRawBytes);
148
ByteArrayOutputStream baos = new ByteArrayOutputStream();
149
150
// main attributes
151
assertEquals(oldMd.getMainAttsEntry().isProperlyDelimited(),
152
mainAttsProperlyDelimited);
153
oldMd.getMainAttsEntry().reproduceRaw(baos);
154
155
// individual sections
156
for (String key : manifest.getEntries().keySet()) {
157
assertEquals(oldMd.get(key).isProperlyDelimited(),
158
sectionProperlyDelimited);
159
oldMd.get(key).reproduceRaw(baos);
160
}
161
162
return baos.toByteArray();
163
}
164
165
static String regExscape(String expr) {
166
for (int i = 0; i < expr.length(); i++) {
167
if (expr.charAt(i) == '\r' || expr.charAt(i) == '\n') {
168
expr = expr.substring(0, i) + "\\" + expr.substring(i++);
169
}
170
}
171
return expr;
172
}
173
174
byte[] digest(byte[] manifest, String section) {
175
MessageDigest digester = new EchoMessageDigest();
176
ManifestDigester md = new ManifestDigester(manifest);
177
ManifestDigester.Entry entry = section == null ?
178
md.getMainAttsEntry(oldStyle) : md.get(section, oldStyle);
179
return digestWorkaround ?
180
entry.digestWorkaround(digester) :
181
entry.digest(digester);
182
}
183
184
void test(byte[] originalManifest, boolean mainAttsProperlyDelimited,
185
boolean sectionProperlyDelimited) throws Exception {
186
Utils.echoManifest(originalManifest, "original manifest");
187
byte[] reproducedManifest = reproduceRawManifest(originalManifest,
188
mainAttsProperlyDelimited, sectionProperlyDelimited);
189
Utils.echoManifest(reproducedManifest, "reproduced manifest");
190
191
// The reproduced manifest is not necessarily completely identical to
192
// the original if it contained superfluous blank lines.
193
// It's sufficient that the digests are equal and as an additional
194
// check, the reproduced manifest is here compared to the original
195
// without more than double line breaks.
196
if (!lineBreak.repeat(2).equals(new String(originalManifest, UTF_8))) {
197
assertEquals(
198
new String(reproducedManifest, UTF_8),
199
new String(originalManifest, UTF_8).replaceAll(
200
regExscape(lineBreak) + "(" + regExscape(lineBreak) + ")+",
201
lineBreak.repeat(2)));
202
}
203
204
// compare digests of reproduced manifest entries with digests of
205
// original manifest entries
206
assertEquals(digest(originalManifest, null),
207
digest(reproducedManifest, null));
208
for (String key : new Manifest(new ByteArrayInputStream(
209
originalManifest)).getEntries().keySet()) {
210
assertEquals(digest(originalManifest, key),
211
digest(reproducedManifest, key));
212
}
213
214
// parse and compare original and reproduced manifests as manifests
215
assertEquals(new Manifest(new ByteArrayInputStream(originalManifest)),
216
new Manifest(new ByteArrayInputStream(reproducedManifest)));
217
}
218
219
void test(byte[] originalManifest, boolean mainAttsProperlyDelimited)
220
throws Exception {
221
// assert all individual sections properly delimited particularly useful
222
// when no individual sections present
223
test(originalManifest, mainAttsProperlyDelimited, true);
224
}
225
226
@Test
227
public void testManifestStartsWithBlankLine() throws Exception {
228
test(lineBreak.getBytes(UTF_8), true);
229
test(lineBreak.repeat(2).getBytes(UTF_8), true);
230
}
231
232
@Test
233
public void testEOFAndNoLineBreakAfterMainAttributes() throws Exception {
234
assertThrows(RuntimeException.class, () ->
235
test("Manifest-Version: 1.0".getBytes(UTF_8), false)
236
);
237
}
238
239
@Test
240
public void testEOFAndNoBlankLineAfterMainAttributes() throws Exception {
241
test(("Manifest-Version: 1.0" + lineBreak).getBytes(UTF_8), false);
242
}
243
244
@Test
245
public void testNormalMainAttributes() throws Exception {
246
test(("Manifest-Version: 1.0" +
247
lineBreak.repeat(2)).getBytes(UTF_8), true);
248
}
249
250
@Test
251
public void testExtraLineBreakAfterMainAttributes() throws Exception {
252
test(("Manifest-Version: 1.0" +
253
lineBreak.repeat(3)).getBytes(UTF_8), true);
254
}
255
256
@Test
257
public void testIndividualSectionNoLineBreak() throws Exception {
258
assertNull(new ManifestDigester((
259
"Manifest-Version: 1.0" + lineBreak +
260
lineBreak +
261
"Name: Section-Name" + lineBreak +
262
"Key: Value"
263
).getBytes(UTF_8)).get("Section-Name"));
264
}
265
266
@Test
267
public void testIndividualSectionOneLineBreak() throws Exception {
268
test((
269
"Manifest-Version: 1.0" + lineBreak +
270
lineBreak +
271
"Name: Section-Name" + lineBreak +
272
"Key: Value" + lineBreak
273
).getBytes(UTF_8), true, false);
274
}
275
276
@Test
277
public void testNormalIndividualSectionTwoLineBreak() throws Exception {
278
test((
279
"Manifest-Version: 1.0" + lineBreak +
280
lineBreak +
281
"Name: Section-Name" + lineBreak +
282
"Key: Value" + lineBreak.repeat(2)
283
).getBytes(UTF_8), true, true);
284
}
285
286
@Test
287
public void testExtraLineBreakAfterIndividualSection() throws Exception {
288
test((
289
"Manifest-Version: 1.0" + lineBreak +
290
lineBreak +
291
"Name: Section-Name" + lineBreak +
292
"Key: Value" + lineBreak.repeat(3)
293
).getBytes(UTF_8), true, true);
294
}
295
296
@Test
297
public void testIndividualSections() throws Exception {
298
test((
299
"Manifest-Version: 1.0" + lineBreak +
300
lineBreak +
301
"Name: Section-Name" + lineBreak +
302
"Key: Value" + lineBreak +
303
lineBreak +
304
"Name: Section-Name" + lineBreak +
305
"Key: Value" + lineBreak +
306
lineBreak
307
).getBytes(UTF_8), true, true);
308
}
309
310
@Test
311
public void testExtraLineBreakBetweenIndividualSections() throws Exception {
312
test((
313
"Manifest-Version: 1.0" + lineBreak +
314
lineBreak +
315
"Name: Section-Name" + lineBreak +
316
"Key: Value" + lineBreak +
317
lineBreak.repeat(2) +
318
"Name: Section-Name" + lineBreak +
319
"Key: Value" + lineBreak +
320
lineBreak
321
).getBytes(UTF_8), true, true);
322
}
323
324
}
325
326