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/java/security/PKCS12Attribute.java
38829 views
1
/*
2
* Copyright (c) 2013, 2020, 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 java.security;
27
28
import java.io.IOException;
29
import java.math.BigInteger;
30
import java.util.Arrays;
31
import java.util.regex.Pattern;
32
import sun.security.util.*;
33
34
/**
35
* An attribute associated with a PKCS12 keystore entry.
36
* The attribute name is an ASN.1 Object Identifier and the attribute
37
* value is a set of ASN.1 types.
38
*
39
* @since 1.8
40
*/
41
public final class PKCS12Attribute implements KeyStore.Entry.Attribute {
42
43
private static final Pattern COLON_SEPARATED_HEX_PAIRS =
44
Pattern.compile("^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+$");
45
private String name;
46
private String value;
47
private byte[] encoded;
48
private int hashValue = -1;
49
50
/**
51
* Constructs a PKCS12 attribute from its name and value.
52
* The name is an ASN.1 Object Identifier represented as a list of
53
* dot-separated integers.
54
* A string value is represented as the string itself.
55
* A binary value is represented as a string of colon-separated
56
* pairs of hexadecimal digits.
57
* Multi-valued attributes are represented as a comma-separated
58
* list of values, enclosed in square brackets. See
59
* {@link Arrays#toString(java.lang.Object[])}.
60
* <p>
61
* A string value will be DER-encoded as an ASN.1 UTF8String and a
62
* binary value will be DER-encoded as an ASN.1 Octet String.
63
*
64
* @param name the attribute's identifier
65
* @param value the attribute's value
66
*
67
* @exception NullPointerException if {@code name} or {@code value}
68
* is {@code null}
69
* @exception IllegalArgumentException if {@code name} or
70
* {@code value} is incorrectly formatted
71
*/
72
public PKCS12Attribute(String name, String value) {
73
if (name == null || value == null) {
74
throw new NullPointerException();
75
}
76
// Validate name
77
ObjectIdentifier type;
78
try {
79
type = new ObjectIdentifier(name);
80
} catch (IOException e) {
81
throw new IllegalArgumentException("Incorrect format: name", e);
82
}
83
this.name = name;
84
85
// Validate value
86
int length = value.length();
87
String[] values;
88
if (value.charAt(0) == '[' && value.charAt(length - 1) == ']') {
89
values = value.substring(1, length - 1).split(", ");
90
} else {
91
values = new String[]{ value };
92
}
93
this.value = value;
94
95
try {
96
this.encoded = encode(type, values);
97
} catch (IOException e) {
98
throw new IllegalArgumentException("Incorrect format: value", e);
99
}
100
}
101
102
/**
103
* Constructs a PKCS12 attribute from its ASN.1 DER encoding.
104
* The DER encoding is specified by the following ASN.1 definition:
105
* <pre>
106
*
107
* Attribute ::= SEQUENCE {
108
* type AttributeType,
109
* values SET OF AttributeValue
110
* }
111
* AttributeType ::= OBJECT IDENTIFIER
112
* AttributeValue ::= ANY defined by type
113
*
114
* </pre>
115
*
116
* @param encoded the attribute's ASN.1 DER encoding. It is cloned
117
* to prevent subsequent modificaion.
118
*
119
* @exception NullPointerException if {@code encoded} is
120
* {@code null}
121
* @exception IllegalArgumentException if {@code encoded} is
122
* incorrectly formatted
123
*/
124
public PKCS12Attribute(byte[] encoded) {
125
if (encoded == null) {
126
throw new NullPointerException();
127
}
128
this.encoded = encoded.clone();
129
130
try {
131
parse(encoded);
132
} catch (IOException e) {
133
throw new IllegalArgumentException("Incorrect format: encoded", e);
134
}
135
}
136
137
/**
138
* Returns the attribute's ASN.1 Object Identifier represented as a
139
* list of dot-separated integers.
140
*
141
* @return the attribute's identifier
142
*/
143
@Override
144
public String getName() {
145
return name;
146
}
147
148
/**
149
* Returns the attribute's ASN.1 DER-encoded value as a string.
150
* An ASN.1 DER-encoded value is returned in one of the following
151
* {@code String} formats:
152
* <ul>
153
* <li> the DER encoding of a basic ASN.1 type that has a natural
154
* string representation is returned as the string itself.
155
* Such types are currently limited to BOOLEAN, INTEGER,
156
* OBJECT IDENTIFIER, UTCTime, GeneralizedTime and the
157
* following six ASN.1 string types: UTF8String,
158
* PrintableString, T61String, IA5String, BMPString and
159
* GeneralString.
160
* <li> the DER encoding of any other ASN.1 type is not decoded but
161
* returned as a binary string of colon-separated pairs of
162
* hexadecimal digits.
163
* </ul>
164
* Multi-valued attributes are represented as a comma-separated
165
* list of values, enclosed in square brackets. See
166
* {@link Arrays#toString(java.lang.Object[])}.
167
*
168
* @return the attribute value's string encoding
169
*/
170
@Override
171
public String getValue() {
172
return value;
173
}
174
175
/**
176
* Returns the attribute's ASN.1 DER encoding.
177
*
178
* @return a clone of the attribute's DER encoding
179
*/
180
public byte[] getEncoded() {
181
return encoded.clone();
182
}
183
184
/**
185
* Compares this {@code PKCS12Attribute} and a specified object for
186
* equality.
187
*
188
* @param obj the comparison object
189
*
190
* @return true if {@code obj} is a {@code PKCS12Attribute} and
191
* their DER encodings are equal.
192
*/
193
@Override
194
public boolean equals(Object obj) {
195
if (this == obj) {
196
return true;
197
}
198
if (!(obj instanceof PKCS12Attribute)) {
199
return false;
200
}
201
return Arrays.equals(encoded, ((PKCS12Attribute) obj).getEncoded());
202
}
203
204
/**
205
* Returns the hashcode for this {@code PKCS12Attribute}.
206
* The hash code is computed from its DER encoding.
207
*
208
* @return the hash code
209
*/
210
@Override
211
public int hashCode() {
212
if (hashValue == -1) {
213
Arrays.hashCode(encoded);
214
}
215
return hashValue;
216
}
217
218
/**
219
* Returns a string representation of this {@code PKCS12Attribute}.
220
*
221
* @return a name/value pair separated by an 'equals' symbol
222
*/
223
@Override
224
public String toString() {
225
return (name + "=" + value);
226
}
227
228
private byte[] encode(ObjectIdentifier type, String[] values)
229
throws IOException {
230
DerOutputStream attribute = new DerOutputStream();
231
attribute.putOID(type);
232
DerOutputStream attrContent = new DerOutputStream();
233
for (String value : values) {
234
if (COLON_SEPARATED_HEX_PAIRS.matcher(value).matches()) {
235
byte[] bytes =
236
new BigInteger(value.replace(":", ""), 16).toByteArray();
237
if (bytes[0] == 0) {
238
bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
239
}
240
attrContent.putOctetString(bytes);
241
} else {
242
attrContent.putUTF8String(value);
243
}
244
}
245
attribute.write(DerValue.tag_Set, attrContent);
246
DerOutputStream attributeValue = new DerOutputStream();
247
attributeValue.write(DerValue.tag_Sequence, attribute);
248
249
return attributeValue.toByteArray();
250
}
251
252
private void parse(byte[] encoded) throws IOException {
253
DerInputStream attributeValue = new DerInputStream(encoded);
254
DerValue[] attrSeq = attributeValue.getSequence(2);
255
if (attrSeq.length != 2) {
256
throw new IOException("Invalid length for PKCS12Attribute");
257
}
258
ObjectIdentifier type = attrSeq[0].getOID();
259
DerInputStream attrContent =
260
new DerInputStream(attrSeq[1].toByteArray());
261
DerValue[] attrValueSet = attrContent.getSet(1);
262
String[] values = new String[attrValueSet.length];
263
String printableString;
264
for (int i = 0; i < attrValueSet.length; i++) {
265
if (attrValueSet[i].tag == DerValue.tag_OctetString) {
266
values[i] = Debug.toString(attrValueSet[i].getOctetString());
267
} else if ((printableString = attrValueSet[i].getAsString())
268
!= null) {
269
values[i] = printableString;
270
} else if (attrValueSet[i].tag == DerValue.tag_ObjectId) {
271
values[i] = attrValueSet[i].getOID().toString();
272
} else if (attrValueSet[i].tag == DerValue.tag_GeneralizedTime) {
273
values[i] = attrValueSet[i].getGeneralizedTime().toString();
274
} else if (attrValueSet[i].tag == DerValue.tag_UtcTime) {
275
values[i] = attrValueSet[i].getUTCTime().toString();
276
} else if (attrValueSet[i].tag == DerValue.tag_Integer) {
277
values[i] = attrValueSet[i].getBigInteger().toString();
278
} else if (attrValueSet[i].tag == DerValue.tag_Boolean) {
279
values[i] = String.valueOf(attrValueSet[i].getBoolean());
280
} else {
281
values[i] = Debug.toString(attrValueSet[i].getDataBytes());
282
}
283
}
284
285
this.name = type.toString();
286
this.value = values.length == 1 ? values[0] : Arrays.toString(values);
287
}
288
}
289
290