Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/util/ManifestDigester.java
38830 views
1
/*
2
* Copyright (c) 1997, 2011, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.util;
27
28
import java.security.*;
29
import java.util.ArrayList;
30
import java.util.HashMap;
31
import java.io.ByteArrayOutputStream;
32
import java.util.List;
33
34
/**
35
* This class is used to compute digests on sections of the Manifest.
36
*/
37
public class ManifestDigester {
38
39
public static final String MF_MAIN_ATTRS = "Manifest-Main-Attributes";
40
41
/** the raw bytes of the manifest */
42
private byte rawBytes[];
43
44
/** the entries grouped by names */
45
private HashMap<String, Entry> entries; // key is a UTF-8 string
46
47
/** state returned by findSection */
48
static class Position {
49
int endOfFirstLine; // not including newline character
50
51
int endOfSection; // end of section, not including the blank line
52
// between sections
53
int startOfNext; // the start of the next section
54
}
55
56
/**
57
* find a section in the manifest.
58
*
59
* @param offset should point to the starting offset with in the
60
* raw bytes of the next section.
61
*
62
* @pos set by
63
*
64
* @returns false if end of bytes has been reached, otherwise returns
65
* true
66
*/
67
@SuppressWarnings("fallthrough")
68
private boolean findSection(int offset, Position pos)
69
{
70
int i = offset, len = rawBytes.length;
71
int last = offset;
72
int next;
73
boolean allBlank = true;
74
75
pos.endOfFirstLine = -1;
76
77
while (i < len) {
78
byte b = rawBytes[i];
79
switch(b) {
80
case '\r':
81
if (pos.endOfFirstLine == -1)
82
pos.endOfFirstLine = i-1;
83
if ((i < len) && (rawBytes[i+1] == '\n'))
84
i++;
85
/* fall through */
86
case '\n':
87
if (pos.endOfFirstLine == -1)
88
pos.endOfFirstLine = i-1;
89
if (allBlank || (i == len-1)) {
90
if (i == len-1)
91
pos.endOfSection = i;
92
else
93
pos.endOfSection = last;
94
pos.startOfNext = i+1;
95
return true;
96
}
97
else {
98
// start of a new line
99
last = i;
100
allBlank = true;
101
}
102
break;
103
default:
104
allBlank = false;
105
break;
106
}
107
i++;
108
}
109
return false;
110
}
111
112
public ManifestDigester(byte bytes[])
113
{
114
rawBytes = bytes;
115
entries = new HashMap<String, Entry>();
116
117
ByteArrayOutputStream baos = new ByteArrayOutputStream();
118
119
Position pos = new Position();
120
121
if (!findSection(0, pos))
122
return; // XXX: exception?
123
124
// create an entry for main attributes
125
entries.put(MF_MAIN_ATTRS, new Entry().addSection(
126
new Section(0, pos.endOfSection + 1, pos.startOfNext, rawBytes)));
127
128
int start = pos.startOfNext;
129
while(findSection(start, pos)) {
130
int len = pos.endOfFirstLine-start+1;
131
int sectionLen = pos.endOfSection-start+1;
132
int sectionLenWithBlank = pos.startOfNext-start;
133
134
if (len > 6) {
135
if (isNameAttr(bytes, start)) {
136
StringBuilder nameBuf = new StringBuilder(sectionLen);
137
138
try {
139
nameBuf.append(
140
new String(bytes, start+6, len-6, "UTF8"));
141
142
int i = start + len;
143
if ((i-start) < sectionLen) {
144
if (bytes[i] == '\r') {
145
i += 2;
146
} else {
147
i += 1;
148
}
149
}
150
151
while ((i-start) < sectionLen) {
152
if (bytes[i++] == ' ') {
153
// name is wrapped
154
int wrapStart = i;
155
while (((i-start) < sectionLen)
156
&& (bytes[i++] != '\n'));
157
if (bytes[i-1] != '\n')
158
return; // XXX: exception?
159
int wrapLen;
160
if (bytes[i-2] == '\r')
161
wrapLen = i-wrapStart-2;
162
else
163
wrapLen = i-wrapStart-1;
164
165
nameBuf.append(new String(bytes, wrapStart,
166
wrapLen, "UTF8"));
167
} else {
168
break;
169
}
170
}
171
172
Entry e = entries.get(nameBuf.toString());
173
if (e == null) {
174
entries.put(nameBuf.toString(), new Entry()
175
.addSection(new Section(start, sectionLen,
176
sectionLenWithBlank, rawBytes)));
177
} else {
178
e.addSection(new Section(start, sectionLen,
179
sectionLenWithBlank, rawBytes));
180
}
181
182
} catch (java.io.UnsupportedEncodingException uee) {
183
throw new IllegalStateException(
184
"UTF8 not available on platform");
185
}
186
}
187
}
188
start = pos.startOfNext;
189
}
190
}
191
192
private boolean isNameAttr(byte bytes[], int start)
193
{
194
return ((bytes[start] == 'N') || (bytes[start] == 'n')) &&
195
((bytes[start+1] == 'a') || (bytes[start+1] == 'A')) &&
196
((bytes[start+2] == 'm') || (bytes[start+2] == 'M')) &&
197
((bytes[start+3] == 'e') || (bytes[start+3] == 'E')) &&
198
(bytes[start+4] == ':') &&
199
(bytes[start+5] == ' ');
200
}
201
202
public static class Entry {
203
204
// One Entry for one name, and one name can have multiple sections.
205
// According to the JAR File Specification: "If there are multiple
206
// individual sections for the same file entry, the attributes in
207
// these sections are merged."
208
private List<Section> sections = new ArrayList<>();
209
boolean oldStyle;
210
211
private Entry addSection(Section sec)
212
{
213
sections.add(sec);
214
return this;
215
}
216
217
public byte[] digest(MessageDigest md)
218
{
219
md.reset();
220
for (Section sec : sections) {
221
if (oldStyle) {
222
Section.doOldStyle(md, sec.rawBytes, sec.offset, sec.lengthWithBlankLine);
223
} else {
224
md.update(sec.rawBytes, sec.offset, sec.lengthWithBlankLine);
225
}
226
}
227
return md.digest();
228
}
229
230
/** Netscape doesn't include the new line. Intel and JavaSoft do */
231
232
public byte[] digestWorkaround(MessageDigest md)
233
{
234
md.reset();
235
for (Section sec : sections) {
236
md.update(sec.rawBytes, sec.offset, sec.length);
237
}
238
return md.digest();
239
}
240
}
241
242
private static class Section {
243
int offset;
244
int length;
245
int lengthWithBlankLine;
246
byte[] rawBytes;
247
248
public Section(int offset, int length,
249
int lengthWithBlankLine, byte[] rawBytes)
250
{
251
this.offset = offset;
252
this.length = length;
253
this.lengthWithBlankLine = lengthWithBlankLine;
254
this.rawBytes = rawBytes;
255
}
256
257
private static void doOldStyle(MessageDigest md,
258
byte[] bytes,
259
int offset,
260
int length)
261
{
262
// this is too gross to even document, but here goes
263
// the 1.1 jar verification code ignored spaces at the
264
// end of lines when calculating digests, so that is
265
// what this code does. It only gets called if we
266
// are parsing a 1.1 signed signature file
267
int i = offset;
268
int start = offset;
269
int max = offset + length;
270
int prev = -1;
271
while(i <max) {
272
if ((bytes[i] == '\r') && (prev == ' ')) {
273
md.update(bytes, start, i-start-1);
274
start = i;
275
}
276
prev = bytes[i];
277
i++;
278
}
279
md.update(bytes, start, i-start);
280
}
281
}
282
283
public Entry get(String name, boolean oldStyle) {
284
Entry e = entries.get(name);
285
if (e != null)
286
e.oldStyle = oldStyle;
287
return e;
288
}
289
290
public byte[] manifestDigest(MessageDigest md)
291
{
292
md.reset();
293
md.update(rawBytes, 0, rawBytes.length);
294
return md.digest();
295
}
296
297
}
298
299