Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/provider/certpath/X509CertificatePair.java
41161 views
1
/*
2
* Copyright (c) 2000, 2012, 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
package sun.security.provider.certpath;
26
27
import java.io.IOException;
28
import java.security.GeneralSecurityException;
29
import java.security.PublicKey;
30
import java.security.cert.CertificateEncodingException;
31
import java.security.cert.CertificateException;
32
import java.security.cert.X509Certificate;
33
import java.security.interfaces.DSAPublicKey;
34
35
import javax.security.auth.x500.X500Principal;
36
37
import sun.security.util.DerOutputStream;
38
import sun.security.util.DerValue;
39
import sun.security.util.Cache;
40
import sun.security.x509.X509CertImpl;
41
import sun.security.provider.X509Factory;
42
43
/**
44
* This class represents an X.509 Certificate Pair object, which is primarily
45
* used to hold a pair of cross certificates issued between Certification
46
* Authorities. The ASN.1 structure is listed below. The forward certificate
47
* of the CertificatePair contains a certificate issued to this CA by another
48
* CA. The reverse certificate of the CertificatePair contains a certificate
49
* issued by this CA to another CA. When both the forward and the reverse
50
* certificates are present in the CertificatePair, the issuer name in one
51
* certificate shall match the subject name in the other and vice versa, and
52
* the subject public key in one certificate shall be capable of verifying the
53
* digital signature on the other certificate and vice versa. If a subject
54
* public key in one certificate does not contain required key algorithm
55
* parameters, then the signature check involving that key is not done.<p>
56
*
57
* The ASN.1 syntax for this object is:
58
* <pre>
59
* CertificatePair ::= SEQUENCE {
60
* forward [0] Certificate OPTIONAL,
61
* reverse [1] Certificate OPTIONAL
62
* -- at least one of the pair shall be present -- }
63
* </pre><p>
64
*
65
* This structure uses EXPLICIT tagging. References: Annex A of
66
* X.509(2000), X.509(1997).
67
*
68
* @author Sean Mullan
69
* @since 1.4
70
*/
71
72
public class X509CertificatePair {
73
74
/* ASN.1 explicit tags */
75
private static final byte TAG_FORWARD = 0;
76
private static final byte TAG_REVERSE = 1;
77
78
private X509Certificate forward;
79
private X509Certificate reverse;
80
private byte[] encoded;
81
82
private static final Cache<Object, X509CertificatePair> cache
83
= Cache.newSoftMemoryCache(750);
84
85
/**
86
* Creates an empty instance of X509CertificatePair.
87
*/
88
public X509CertificatePair() {}
89
90
/**
91
* Creates an instance of X509CertificatePair. At least one of
92
* the pair must be non-null.
93
*
94
* @param forward The forward component of the certificate pair
95
* which represents a certificate issued to this CA by other CAs.
96
* @param reverse The reverse component of the certificate pair
97
* which represents a certificate issued by this CA to other CAs.
98
* @throws CertificateException If an exception occurs.
99
*/
100
public X509CertificatePair(X509Certificate forward, X509Certificate reverse)
101
throws CertificateException {
102
if (forward == null && reverse == null) {
103
throw new CertificateException("at least one of certificate pair "
104
+ "must be non-null");
105
}
106
107
this.forward = forward;
108
this.reverse = reverse;
109
110
checkPair();
111
}
112
113
/**
114
* Create a new X509CertificatePair from its encoding.
115
*
116
* For internal use only, external code should use generateCertificatePair.
117
*/
118
private X509CertificatePair(byte[] encoded) throws CertificateException {
119
try {
120
parse(new DerValue(encoded));
121
this.encoded = encoded;
122
} catch (IOException ex) {
123
throw new CertificateException(ex.toString());
124
}
125
checkPair();
126
}
127
128
/**
129
* Clear the cache for debugging.
130
*/
131
public static synchronized void clearCache() {
132
cache.clear();
133
}
134
135
/**
136
* Create a X509CertificatePair from its encoding. Uses cache lookup
137
* if possible.
138
*/
139
public static synchronized X509CertificatePair generateCertificatePair
140
(byte[] encoded) throws CertificateException {
141
Object key = new Cache.EqualByteArray(encoded);
142
X509CertificatePair pair = cache.get(key);
143
if (pair != null) {
144
return pair;
145
}
146
pair = new X509CertificatePair(encoded);
147
key = new Cache.EqualByteArray(pair.encoded);
148
cache.put(key, pair);
149
return pair;
150
}
151
152
/**
153
* Sets the forward component of the certificate pair.
154
*/
155
public void setForward(X509Certificate cert) throws CertificateException {
156
checkPair();
157
forward = cert;
158
}
159
160
/**
161
* Sets the reverse component of the certificate pair.
162
*/
163
public void setReverse(X509Certificate cert) throws CertificateException {
164
checkPair();
165
reverse = cert;
166
}
167
168
/**
169
* Returns the forward component of the certificate pair.
170
*
171
* @return The forward certificate, or null if not set.
172
*/
173
public X509Certificate getForward() {
174
return forward;
175
}
176
177
/**
178
* Returns the reverse component of the certificate pair.
179
*
180
* @return The reverse certificate, or null if not set.
181
*/
182
public X509Certificate getReverse() {
183
return reverse;
184
}
185
186
/**
187
* Return the DER encoded form of the certificate pair.
188
*
189
* @return The encoded form of the certificate pair.
190
* @throws CerticateEncodingException If an encoding exception occurs.
191
*/
192
public byte[] getEncoded() throws CertificateEncodingException {
193
try {
194
if (encoded == null) {
195
DerOutputStream tmp = new DerOutputStream();
196
emit(tmp);
197
encoded = tmp.toByteArray();
198
}
199
} catch (IOException ex) {
200
throw new CertificateEncodingException(ex.toString());
201
}
202
return encoded;
203
}
204
205
/**
206
* Return a printable representation of the certificate pair.
207
*
208
* @return A String describing the contents of the pair.
209
*/
210
@Override
211
public String toString() {
212
StringBuilder sb = new StringBuilder();
213
sb.append("X.509 Certificate Pair: [\n");
214
if (forward != null)
215
sb.append(" Forward: ").append(forward).append("\n");
216
if (reverse != null)
217
sb.append(" Reverse: ").append(reverse).append("\n");
218
sb.append("]");
219
return sb.toString();
220
}
221
222
/* Parse the encoded bytes */
223
private void parse(DerValue val)
224
throws IOException, CertificateException
225
{
226
if (val.tag != DerValue.tag_Sequence) {
227
throw new IOException
228
("Sequence tag missing for X509CertificatePair");
229
}
230
231
while (val.data != null && val.data.available() != 0) {
232
DerValue opt = val.data.getDerValue();
233
short tag = (byte) (opt.tag & 0x01f);
234
switch (tag) {
235
case TAG_FORWARD:
236
if (opt.isContextSpecific() && opt.isConstructed()) {
237
if (forward != null) {
238
throw new IOException("Duplicate forward "
239
+ "certificate in X509CertificatePair");
240
}
241
opt = opt.data.getDerValue();
242
forward = X509Factory.intern
243
(new X509CertImpl(opt.toByteArray()));
244
}
245
break;
246
case TAG_REVERSE:
247
if (opt.isContextSpecific() && opt.isConstructed()) {
248
if (reverse != null) {
249
throw new IOException("Duplicate reverse "
250
+ "certificate in X509CertificatePair");
251
}
252
opt = opt.data.getDerValue();
253
reverse = X509Factory.intern
254
(new X509CertImpl(opt.toByteArray()));
255
}
256
break;
257
default:
258
throw new IOException("Invalid encoding of "
259
+ "X509CertificatePair");
260
}
261
}
262
if (forward == null && reverse == null) {
263
throw new CertificateException("at least one of certificate pair "
264
+ "must be non-null");
265
}
266
}
267
268
/* Translate to encoded bytes */
269
private void emit(DerOutputStream out)
270
throws IOException, CertificateEncodingException
271
{
272
DerOutputStream tagged = new DerOutputStream();
273
274
if (forward != null) {
275
DerOutputStream tmp = new DerOutputStream();
276
tmp.putDerValue(new DerValue(forward.getEncoded()));
277
tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
278
true, TAG_FORWARD), tmp);
279
}
280
281
if (reverse != null) {
282
DerOutputStream tmp = new DerOutputStream();
283
tmp.putDerValue(new DerValue(reverse.getEncoded()));
284
tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
285
true, TAG_REVERSE), tmp);
286
}
287
288
out.write(DerValue.tag_Sequence, tagged);
289
}
290
291
/*
292
* Check for a valid certificate pair
293
*/
294
private void checkPair() throws CertificateException {
295
296
/* if either of pair is missing, return w/o error */
297
if (forward == null || reverse == null) {
298
return;
299
}
300
/*
301
* If both elements of the pair are present, check that they
302
* are a valid pair.
303
*/
304
X500Principal fwSubject = forward.getSubjectX500Principal();
305
X500Principal fwIssuer = forward.getIssuerX500Principal();
306
X500Principal rvSubject = reverse.getSubjectX500Principal();
307
X500Principal rvIssuer = reverse.getIssuerX500Principal();
308
if (!fwIssuer.equals(rvSubject) || !rvIssuer.equals(fwSubject)) {
309
throw new CertificateException("subject and issuer names in "
310
+ "forward and reverse certificates do not match");
311
}
312
313
/* check signatures unless key parameters are missing */
314
try {
315
PublicKey pk = reverse.getPublicKey();
316
if (!(pk instanceof DSAPublicKey) ||
317
((DSAPublicKey)pk).getParams() != null) {
318
forward.verify(pk);
319
}
320
pk = forward.getPublicKey();
321
if (!(pk instanceof DSAPublicKey) ||
322
((DSAPublicKey)pk).getParams() != null) {
323
reverse.verify(pk);
324
}
325
} catch (GeneralSecurityException e) {
326
throw new CertificateException("invalid signature: "
327
+ e.getMessage());
328
}
329
}
330
}
331
332